Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #include "gfxPlatformMac.h"
8 #include "gfxImageSurface.h"
9 #include "gfxQuartzSurface.h"
10 #include "gfxQuartzImageSurface.h"
11 #include "mozilla/gfx/2D.h"
13 #include "gfxMacPlatformFontList.h"
14 #include "gfxMacFont.h"
15 #include "gfxCoreTextShaper.h"
16 #include "gfxUserFontSet.h"
18 #include "nsTArray.h"
19 #include "mozilla/Preferences.h"
20 #include "qcms.h"
21 #include "gfx2DGlue.h"
23 #include <dlfcn.h>
25 #include "nsCocoaFeatures.h"
27 using namespace mozilla;
28 using namespace mozilla::gfx;
30 // cribbed from CTFontManager.h
31 enum {
32 kAutoActivationDisabled = 1
33 };
34 typedef uint32_t AutoActivationSetting;
36 // bug 567552 - disable auto-activation of fonts
38 static void
39 DisableFontActivation()
40 {
41 // get the main bundle identifier
42 CFBundleRef mainBundle = ::CFBundleGetMainBundle();
43 CFStringRef mainBundleID = nullptr;
45 if (mainBundle) {
46 mainBundleID = ::CFBundleGetIdentifier(mainBundle);
47 }
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 }
55 // if possible, fetch CTFontManagerSetAutoActivationSetting
56 void (*CTFontManagerSetAutoActivationSettingPtr)
57 (CFStringRef, AutoActivationSetting);
58 CTFontManagerSetAutoActivationSettingPtr =
59 (void (*)(CFStringRef, AutoActivationSetting))
60 dlsym(RTLD_DEFAULT, "CTFontManagerSetAutoActivationSetting");
62 // bug 567552 - disable auto-activation of fonts
63 if (CTFontManagerSetAutoActivationSettingPtr) {
64 CTFontManagerSetAutoActivationSettingPtr(mainBundleID,
65 kAutoActivationDisabled);
66 }
67 }
69 gfxPlatformMac::gfxPlatformMac()
70 {
71 DisableFontActivation();
72 mFontAntiAliasingThreshold = ReadAntiAliasingThreshold();
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 }
82 gfxPlatformMac::~gfxPlatformMac()
83 {
84 gfxCoreTextShaper::Shutdown();
85 }
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 }
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 }
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 }
122 already_AddRefed<gfxASurface>
123 gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
124 gfxImageFormat format)
125 {
126 const gfxIntSize& surfaceSize = aSurface->GetSize();
127 nsRefPtr<gfxImageSurface> isurf = aSurface;
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 }
138 return nullptr;
139 }
141 TemporaryRef<ScaledFont>
142 gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
143 {
144 gfxMacFont *font = static_cast<gfxMacFont*>(aFont);
145 return font->GetScaledFont(aTarget);
146 }
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 }
163 nsresult
164 gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
165 {
166 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
167 return NS_OK;
168 }
170 gfxFontGroup *
171 gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
172 const gfxFontStyle *aStyle,
173 gfxUserFontSet *aUserFontSet)
174 {
175 return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
176 }
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 }
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 }
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");
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 }
214 // reject all other formats, known and unknown
215 if (aFormatFlags != 0) {
216 return false;
217 }
219 // no format hint set, need to look at data
220 return true;
221 }
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 }
233 nsresult
234 gfxPlatformMac::UpdateFontList()
235 {
236 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
237 return NS_OK;
238 }
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";
267 void
268 gfxPlatformMac::GetCommonFallbackFonts(const uint32_t aCh,
269 int32_t aRunScript,
270 nsTArray<const char*>& aFontList)
271 {
272 aFontList.AppendElement(kFontLucidaGrande);
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;
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 }
402 // Arial Unicode MS has lots of glyphs for obscure, use it as a last resort
403 aFontList.AppendElement(kFontArialUnicodeMS);
404 }
406 uint32_t
407 gfxPlatformMac::ReadAntiAliasingThreshold()
408 {
409 uint32_t threshold = 0; // default == no threshold
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);
414 // if the pref setting is disabled, return 0 which effectively disables this feature
415 if (!useAntiAliasingThreshold)
416 return threshold;
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);
421 if (prefValue) {
422 if (!CFNumberGetValue(prefValue, kCFNumberIntType, &threshold)) {
423 threshold = 0;
424 }
425 CFRelease(prefValue);
426 }
428 return threshold;
429 }
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));
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);
451 nsRefPtr<gfxASurface> surf =
452 new gfxQuartzSurface(cg, size);
454 return surf.forget();
455 }
457 return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
458 }
460 bool
461 gfxPlatformMac::UseAcceleratedCanvas()
462 {
463 // Lion or later is required
464 return nsCocoaFeatures::OnLionOrLater() && Preferences::GetBool("gfx.canvas.azure.accelerated", false);
465 }
467 bool
468 gfxPlatformMac::SupportsOffMainThreadCompositing()
469 {
470 return true;
471 }
473 void
474 gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
475 {
476 mem = nullptr;
477 size = 0;
479 CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
480 if (!cspace) {
481 cspace = ::CGColorSpaceCreateDeviceRGB();
482 }
483 if (!cspace) {
484 return;
485 }
487 CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace);
489 ::CFRelease(cspace);
491 if (!iccp) {
492 return;
493 }
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 }
507 ::CFRelease(iccp);
508 }