|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "gfxPlatformMac.h" |
|
7 |
|
8 #include "gfxImageSurface.h" |
|
9 #include "gfxQuartzSurface.h" |
|
10 #include "gfxQuartzImageSurface.h" |
|
11 #include "mozilla/gfx/2D.h" |
|
12 |
|
13 #include "gfxMacPlatformFontList.h" |
|
14 #include "gfxMacFont.h" |
|
15 #include "gfxCoreTextShaper.h" |
|
16 #include "gfxUserFontSet.h" |
|
17 |
|
18 #include "nsTArray.h" |
|
19 #include "mozilla/Preferences.h" |
|
20 #include "qcms.h" |
|
21 #include "gfx2DGlue.h" |
|
22 |
|
23 #include <dlfcn.h> |
|
24 |
|
25 #include "nsCocoaFeatures.h" |
|
26 |
|
27 using namespace mozilla; |
|
28 using namespace mozilla::gfx; |
|
29 |
|
30 // cribbed from CTFontManager.h |
|
31 enum { |
|
32 kAutoActivationDisabled = 1 |
|
33 }; |
|
34 typedef uint32_t AutoActivationSetting; |
|
35 |
|
36 // bug 567552 - disable auto-activation of fonts |
|
37 |
|
38 static void |
|
39 DisableFontActivation() |
|
40 { |
|
41 // get the main bundle identifier |
|
42 CFBundleRef mainBundle = ::CFBundleGetMainBundle(); |
|
43 CFStringRef mainBundleID = nullptr; |
|
44 |
|
45 if (mainBundle) { |
|
46 mainBundleID = ::CFBundleGetIdentifier(mainBundle); |
|
47 } |
|
48 |
|
49 // bug 969388 and bug 922590 - mainBundlID as null is sometimes problematic |
|
50 if (!mainBundleID) { |
|
51 NS_WARNING("missing bundle ID, packaging set up incorrectly"); |
|
52 return; |
|
53 } |
|
54 |
|
55 // if possible, fetch CTFontManagerSetAutoActivationSetting |
|
56 void (*CTFontManagerSetAutoActivationSettingPtr) |
|
57 (CFStringRef, AutoActivationSetting); |
|
58 CTFontManagerSetAutoActivationSettingPtr = |
|
59 (void (*)(CFStringRef, AutoActivationSetting)) |
|
60 dlsym(RTLD_DEFAULT, "CTFontManagerSetAutoActivationSetting"); |
|
61 |
|
62 // bug 567552 - disable auto-activation of fonts |
|
63 if (CTFontManagerSetAutoActivationSettingPtr) { |
|
64 CTFontManagerSetAutoActivationSettingPtr(mainBundleID, |
|
65 kAutoActivationDisabled); |
|
66 } |
|
67 } |
|
68 |
|
69 gfxPlatformMac::gfxPlatformMac() |
|
70 { |
|
71 DisableFontActivation(); |
|
72 mFontAntiAliasingThreshold = ReadAntiAliasingThreshold(); |
|
73 |
|
74 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | |
|
75 BackendTypeBit(BackendType::SKIA) | |
|
76 BackendTypeBit(BackendType::COREGRAPHICS); |
|
77 uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS); |
|
78 InitBackendPrefs(canvasMask, BackendType::COREGRAPHICS, |
|
79 contentMask, BackendType::COREGRAPHICS); |
|
80 } |
|
81 |
|
82 gfxPlatformMac::~gfxPlatformMac() |
|
83 { |
|
84 gfxCoreTextShaper::Shutdown(); |
|
85 } |
|
86 |
|
87 gfxPlatformFontList* |
|
88 gfxPlatformMac::CreatePlatformFontList() |
|
89 { |
|
90 gfxPlatformFontList* list = new gfxMacPlatformFontList(); |
|
91 if (NS_SUCCEEDED(list->InitFontList())) { |
|
92 return list; |
|
93 } |
|
94 gfxPlatformFontList::Shutdown(); |
|
95 return nullptr; |
|
96 } |
|
97 |
|
98 already_AddRefed<gfxASurface> |
|
99 gfxPlatformMac::CreateOffscreenSurface(const IntSize& size, |
|
100 gfxContentType contentType) |
|
101 { |
|
102 nsRefPtr<gfxASurface> newSurface = |
|
103 new gfxQuartzSurface(ThebesIntSize(size), |
|
104 OptimalFormatForContent(contentType)); |
|
105 return newSurface.forget(); |
|
106 } |
|
107 |
|
108 already_AddRefed<gfxASurface> |
|
109 gfxPlatformMac::CreateOffscreenImageSurface(const gfxIntSize& aSize, |
|
110 gfxContentType aContentType) |
|
111 { |
|
112 nsRefPtr<gfxASurface> surface = |
|
113 CreateOffscreenSurface(aSize.ToIntSize(), aContentType); |
|
114 #ifdef DEBUG |
|
115 nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface(); |
|
116 NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface"); |
|
117 #endif |
|
118 return surface.forget(); |
|
119 } |
|
120 |
|
121 |
|
122 already_AddRefed<gfxASurface> |
|
123 gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, |
|
124 gfxImageFormat format) |
|
125 { |
|
126 const gfxIntSize& surfaceSize = aSurface->GetSize(); |
|
127 nsRefPtr<gfxImageSurface> isurf = aSurface; |
|
128 |
|
129 if (format != aSurface->Format()) { |
|
130 isurf = new gfxImageSurface (surfaceSize, format); |
|
131 if (!isurf->CopyFrom (aSurface)) { |
|
132 // don't even bother doing anything more |
|
133 nsRefPtr<gfxASurface> ret = aSurface; |
|
134 return ret.forget(); |
|
135 } |
|
136 } |
|
137 |
|
138 return nullptr; |
|
139 } |
|
140 |
|
141 TemporaryRef<ScaledFont> |
|
142 gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) |
|
143 { |
|
144 gfxMacFont *font = static_cast<gfxMacFont*>(aFont); |
|
145 return font->GetScaledFont(aTarget); |
|
146 } |
|
147 |
|
148 nsresult |
|
149 gfxPlatformMac::ResolveFontName(const nsAString& aFontName, |
|
150 FontResolverCallback aCallback, |
|
151 void *aClosure, bool& aAborted) |
|
152 { |
|
153 nsAutoString resolvedName; |
|
154 if (!gfxPlatformFontList::PlatformFontList()-> |
|
155 ResolveFontName(aFontName, resolvedName)) { |
|
156 aAborted = false; |
|
157 return NS_OK; |
|
158 } |
|
159 aAborted = !(*aCallback)(resolvedName, aClosure); |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
163 nsresult |
|
164 gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) |
|
165 { |
|
166 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); |
|
167 return NS_OK; |
|
168 } |
|
169 |
|
170 gfxFontGroup * |
|
171 gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies, |
|
172 const gfxFontStyle *aStyle, |
|
173 gfxUserFontSet *aUserFontSet) |
|
174 { |
|
175 return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); |
|
176 } |
|
177 |
|
178 // these will move to gfxPlatform once all platforms support the fontlist |
|
179 gfxFontEntry* |
|
180 gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, |
|
181 const nsAString& aFontName) |
|
182 { |
|
183 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, |
|
184 aFontName); |
|
185 } |
|
186 |
|
187 gfxFontEntry* |
|
188 gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, |
|
189 const uint8_t *aFontData, uint32_t aLength) |
|
190 { |
|
191 // Ownership of aFontData is received here, and passed on to |
|
192 // gfxPlatformFontList::MakePlatformFont(), which must ensure the data |
|
193 // is released with NS_Free when no longer needed |
|
194 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, |
|
195 aFontData, |
|
196 aLength); |
|
197 } |
|
198 |
|
199 bool |
|
200 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) |
|
201 { |
|
202 // check for strange format flags |
|
203 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), |
|
204 "strange font format hint set"); |
|
205 |
|
206 // accept supported formats |
|
207 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF | |
|
208 gfxUserFontSet::FLAG_FORMAT_OPENTYPE | |
|
209 gfxUserFontSet::FLAG_FORMAT_TRUETYPE | |
|
210 gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)) { |
|
211 return true; |
|
212 } |
|
213 |
|
214 // reject all other formats, known and unknown |
|
215 if (aFormatFlags != 0) { |
|
216 return false; |
|
217 } |
|
218 |
|
219 // no format hint set, need to look at data |
|
220 return true; |
|
221 } |
|
222 |
|
223 // these will also move to gfxPlatform once all platforms support the fontlist |
|
224 nsresult |
|
225 gfxPlatformMac::GetFontList(nsIAtom *aLangGroup, |
|
226 const nsACString& aGenericFamily, |
|
227 nsTArray<nsString>& aListOfFonts) |
|
228 { |
|
229 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts); |
|
230 return NS_OK; |
|
231 } |
|
232 |
|
233 nsresult |
|
234 gfxPlatformMac::UpdateFontList() |
|
235 { |
|
236 gfxPlatformFontList::PlatformFontList()->UpdateFontList(); |
|
237 return NS_OK; |
|
238 } |
|
239 |
|
240 static const char kFontArialUnicodeMS[] = "Arial Unicode MS"; |
|
241 static const char kFontAppleBraille[] = "Apple Braille"; |
|
242 static const char kFontAppleColorEmoji[] = "Apple Color Emoji"; |
|
243 static const char kFontAppleSymbols[] = "Apple Symbols"; |
|
244 static const char kFontDevanagariSangamMN[] = "Devanagari Sangam MN"; |
|
245 static const char kFontEuphemiaUCAS[] = "Euphemia UCAS"; |
|
246 static const char kFontGeneva[] = "Geneva"; |
|
247 static const char kFontGeezaPro[] = "Geeza Pro"; |
|
248 static const char kFontGujaratiSangamMN[] = "Gujarati Sangam MN"; |
|
249 static const char kFontGurmukhiMN[] = "Gurmukhi MN"; |
|
250 static const char kFontHiraginoKakuGothic[] = "Hiragino Kaku Gothic ProN"; |
|
251 static const char kFontHiraginoSansGB[] = "Hiragino Sans GB"; |
|
252 static const char kFontKefa[] = "Kefa"; |
|
253 static const char kFontKhmerMN[] = "Khmer MN"; |
|
254 static const char kFontLaoMN[] = "Lao MN"; |
|
255 static const char kFontLucidaGrande[] = "Lucida Grande"; |
|
256 static const char kFontMenlo[] = "Menlo"; |
|
257 static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le"; |
|
258 static const char kFontMingLiUExtB[] = "MingLiU-ExtB"; |
|
259 static const char kFontMyanmarMN[] = "Myanmar MN"; |
|
260 static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee"; |
|
261 static const char kFontSimSunExtB[] = "SimSun-ExtB"; |
|
262 static const char kFontSongtiSC[] = "Songti SC"; |
|
263 static const char kFontSTHeiti[] = "STHeiti"; |
|
264 static const char kFontSTIXGeneral[] = "STIXGeneral"; |
|
265 static const char kFontTamilMN[] = "Tamil MN"; |
|
266 |
|
267 void |
|
268 gfxPlatformMac::GetCommonFallbackFonts(const uint32_t aCh, |
|
269 int32_t aRunScript, |
|
270 nsTArray<const char*>& aFontList) |
|
271 { |
|
272 aFontList.AppendElement(kFontLucidaGrande); |
|
273 |
|
274 if (!IS_IN_BMP(aCh)) { |
|
275 uint32_t p = aCh >> 16; |
|
276 uint32_t b = aCh >> 8; |
|
277 if (p == 1) { |
|
278 if (b >= 0x1f0 && b < 0x1f7) { |
|
279 aFontList.AppendElement(kFontAppleColorEmoji); |
|
280 } else { |
|
281 aFontList.AppendElement(kFontAppleSymbols); |
|
282 aFontList.AppendElement(kFontSTIXGeneral); |
|
283 aFontList.AppendElement(kFontGeneva); |
|
284 } |
|
285 } else if (p == 2) { |
|
286 // OSX installations with MS Office may have these fonts |
|
287 aFontList.AppendElement(kFontMingLiUExtB); |
|
288 aFontList.AppendElement(kFontSimSunExtB); |
|
289 } |
|
290 } else { |
|
291 uint32_t b = (aCh >> 8) & 0xff; |
|
292 |
|
293 switch (b) { |
|
294 case 0x03: |
|
295 case 0x05: |
|
296 aFontList.AppendElement(kFontGeneva); |
|
297 break; |
|
298 case 0x07: |
|
299 aFontList.AppendElement(kFontGeezaPro); |
|
300 break; |
|
301 case 0x09: |
|
302 aFontList.AppendElement(kFontDevanagariSangamMN); |
|
303 break; |
|
304 case 0x0a: |
|
305 aFontList.AppendElement(kFontGurmukhiMN); |
|
306 aFontList.AppendElement(kFontGujaratiSangamMN); |
|
307 break; |
|
308 case 0x0b: |
|
309 aFontList.AppendElement(kFontTamilMN); |
|
310 break; |
|
311 case 0x0e: |
|
312 aFontList.AppendElement(kFontLaoMN); |
|
313 break; |
|
314 case 0x0f: |
|
315 aFontList.AppendElement(kFontSongtiSC); |
|
316 break; |
|
317 case 0x10: |
|
318 aFontList.AppendElement(kFontMenlo); |
|
319 aFontList.AppendElement(kFontMyanmarMN); |
|
320 break; |
|
321 case 0x13: // Cherokee |
|
322 aFontList.AppendElement(kFontPlantagenetCherokee); |
|
323 aFontList.AppendElement(kFontKefa); |
|
324 break; |
|
325 case 0x14: // Unified Canadian Aboriginal Syllabics |
|
326 case 0x15: |
|
327 case 0x16: |
|
328 aFontList.AppendElement(kFontEuphemiaUCAS); |
|
329 aFontList.AppendElement(kFontGeneva); |
|
330 break; |
|
331 case 0x18: // Mongolian, UCAS |
|
332 aFontList.AppendElement(kFontSTHeiti); |
|
333 aFontList.AppendElement(kFontEuphemiaUCAS); |
|
334 break; |
|
335 case 0x19: // Khmer |
|
336 aFontList.AppendElement(kFontKhmerMN); |
|
337 aFontList.AppendElement(kFontMicrosoftTaiLe); |
|
338 break; |
|
339 case 0x1d: |
|
340 case 0x1e: |
|
341 aFontList.AppendElement(kFontGeneva); |
|
342 break; |
|
343 case 0x20: // Symbol ranges |
|
344 case 0x21: |
|
345 case 0x22: |
|
346 case 0x23: |
|
347 case 0x24: |
|
348 case 0x25: |
|
349 case 0x26: |
|
350 case 0x27: |
|
351 case 0x29: |
|
352 case 0x2a: |
|
353 case 0x2b: |
|
354 case 0x2e: |
|
355 aFontList.AppendElement(kFontAppleSymbols); |
|
356 aFontList.AppendElement(kFontMenlo); |
|
357 aFontList.AppendElement(kFontSTIXGeneral); |
|
358 aFontList.AppendElement(kFontGeneva); |
|
359 aFontList.AppendElement(kFontHiraginoKakuGothic); |
|
360 aFontList.AppendElement(kFontAppleColorEmoji); |
|
361 break; |
|
362 case 0x2c: |
|
363 aFontList.AppendElement(kFontGeneva); |
|
364 break; |
|
365 case 0x2d: |
|
366 aFontList.AppendElement(kFontKefa); |
|
367 aFontList.AppendElement(kFontGeneva); |
|
368 break; |
|
369 case 0x28: // Braille |
|
370 aFontList.AppendElement(kFontAppleBraille); |
|
371 break; |
|
372 case 0x31: |
|
373 aFontList.AppendElement(kFontHiraginoSansGB); |
|
374 break; |
|
375 case 0x4d: |
|
376 aFontList.AppendElement(kFontAppleSymbols); |
|
377 break; |
|
378 case 0xa0: // Yi |
|
379 case 0xa1: |
|
380 case 0xa2: |
|
381 case 0xa3: |
|
382 case 0xa4: |
|
383 aFontList.AppendElement(kFontSTHeiti); |
|
384 break; |
|
385 case 0xa6: |
|
386 case 0xa7: |
|
387 aFontList.AppendElement(kFontGeneva); |
|
388 aFontList.AppendElement(kFontAppleSymbols); |
|
389 break; |
|
390 case 0xab: |
|
391 aFontList.AppendElement(kFontKefa); |
|
392 break; |
|
393 case 0xfc: |
|
394 case 0xff: |
|
395 aFontList.AppendElement(kFontAppleSymbols); |
|
396 break; |
|
397 default: |
|
398 break; |
|
399 } |
|
400 } |
|
401 |
|
402 // Arial Unicode MS has lots of glyphs for obscure, use it as a last resort |
|
403 aFontList.AppendElement(kFontArialUnicodeMS); |
|
404 } |
|
405 |
|
406 uint32_t |
|
407 gfxPlatformMac::ReadAntiAliasingThreshold() |
|
408 { |
|
409 uint32_t threshold = 0; // default == no threshold |
|
410 |
|
411 // first read prefs flag to determine whether to use the setting or not |
|
412 bool useAntiAliasingThreshold = Preferences::GetBool("gfx.use_text_smoothing_setting", false); |
|
413 |
|
414 // if the pref setting is disabled, return 0 which effectively disables this feature |
|
415 if (!useAntiAliasingThreshold) |
|
416 return threshold; |
|
417 |
|
418 // value set via Appearance pref panel, "Turn off text smoothing for font sizes xxx and smaller" |
|
419 CFNumberRef prefValue = (CFNumberRef)CFPreferencesCopyAppValue(CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication); |
|
420 |
|
421 if (prefValue) { |
|
422 if (!CFNumberGetValue(prefValue, kCFNumberIntType, &threshold)) { |
|
423 threshold = 0; |
|
424 } |
|
425 CFRelease(prefValue); |
|
426 } |
|
427 |
|
428 return threshold; |
|
429 } |
|
430 |
|
431 already_AddRefed<gfxASurface> |
|
432 gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) |
|
433 { |
|
434 if (aTarget->GetType() == BackendType::COREGRAPHICS_ACCELERATED) { |
|
435 RefPtr<SourceSurface> source = aTarget->Snapshot(); |
|
436 RefPtr<DataSourceSurface> sourceData = source->GetDataSurface(); |
|
437 unsigned char* data = sourceData->GetData(); |
|
438 nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(data, ThebesIntSize(sourceData->GetSize()), sourceData->Stride(), |
|
439 gfxImageFormat::ARGB32); |
|
440 // We could fix this by telling gfxImageSurface it owns data. |
|
441 nsRefPtr<gfxImageSurface> cpy = new gfxImageSurface(ThebesIntSize(sourceData->GetSize()), gfxImageFormat::ARGB32); |
|
442 cpy->CopyFrom(surf); |
|
443 return cpy.forget(); |
|
444 } else if (aTarget->GetType() == BackendType::COREGRAPHICS) { |
|
445 CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT)); |
|
446 |
|
447 //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize |
|
448 IntSize intSize = aTarget->GetSize(); |
|
449 gfxIntSize size(intSize.width, intSize.height); |
|
450 |
|
451 nsRefPtr<gfxASurface> surf = |
|
452 new gfxQuartzSurface(cg, size); |
|
453 |
|
454 return surf.forget(); |
|
455 } |
|
456 |
|
457 return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); |
|
458 } |
|
459 |
|
460 bool |
|
461 gfxPlatformMac::UseAcceleratedCanvas() |
|
462 { |
|
463 // Lion or later is required |
|
464 return nsCocoaFeatures::OnLionOrLater() && Preferences::GetBool("gfx.canvas.azure.accelerated", false); |
|
465 } |
|
466 |
|
467 bool |
|
468 gfxPlatformMac::SupportsOffMainThreadCompositing() |
|
469 { |
|
470 return true; |
|
471 } |
|
472 |
|
473 void |
|
474 gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size) |
|
475 { |
|
476 mem = nullptr; |
|
477 size = 0; |
|
478 |
|
479 CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); |
|
480 if (!cspace) { |
|
481 cspace = ::CGColorSpaceCreateDeviceRGB(); |
|
482 } |
|
483 if (!cspace) { |
|
484 return; |
|
485 } |
|
486 |
|
487 CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace); |
|
488 |
|
489 ::CFRelease(cspace); |
|
490 |
|
491 if (!iccp) { |
|
492 return; |
|
493 } |
|
494 |
|
495 // copy to external buffer |
|
496 size = static_cast<size_t>(::CFDataGetLength(iccp)); |
|
497 if (size > 0) { |
|
498 void *data = malloc(size); |
|
499 if (data) { |
|
500 memcpy(data, ::CFDataGetBytePtr(iccp), size); |
|
501 mem = data; |
|
502 } else { |
|
503 size = 0; |
|
504 } |
|
505 } |
|
506 |
|
507 ::CFRelease(iccp); |
|
508 } |