michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxPlatformMac.h" michael@0: michael@0: #include "gfxImageSurface.h" michael@0: #include "gfxQuartzSurface.h" michael@0: #include "gfxQuartzImageSurface.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: #include "gfxMacPlatformFontList.h" michael@0: #include "gfxMacFont.h" michael@0: #include "gfxCoreTextShaper.h" michael@0: #include "gfxUserFontSet.h" michael@0: michael@0: #include "nsTArray.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "qcms.h" michael@0: #include "gfx2DGlue.h" michael@0: michael@0: #include michael@0: michael@0: #include "nsCocoaFeatures.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::gfx; michael@0: michael@0: // cribbed from CTFontManager.h michael@0: enum { michael@0: kAutoActivationDisabled = 1 michael@0: }; michael@0: typedef uint32_t AutoActivationSetting; michael@0: michael@0: // bug 567552 - disable auto-activation of fonts michael@0: michael@0: static void michael@0: DisableFontActivation() michael@0: { michael@0: // get the main bundle identifier michael@0: CFBundleRef mainBundle = ::CFBundleGetMainBundle(); michael@0: CFStringRef mainBundleID = nullptr; michael@0: michael@0: if (mainBundle) { michael@0: mainBundleID = ::CFBundleGetIdentifier(mainBundle); michael@0: } michael@0: michael@0: // bug 969388 and bug 922590 - mainBundlID as null is sometimes problematic michael@0: if (!mainBundleID) { michael@0: NS_WARNING("missing bundle ID, packaging set up incorrectly"); michael@0: return; michael@0: } michael@0: michael@0: // if possible, fetch CTFontManagerSetAutoActivationSetting michael@0: void (*CTFontManagerSetAutoActivationSettingPtr) michael@0: (CFStringRef, AutoActivationSetting); michael@0: CTFontManagerSetAutoActivationSettingPtr = michael@0: (void (*)(CFStringRef, AutoActivationSetting)) michael@0: dlsym(RTLD_DEFAULT, "CTFontManagerSetAutoActivationSetting"); michael@0: michael@0: // bug 567552 - disable auto-activation of fonts michael@0: if (CTFontManagerSetAutoActivationSettingPtr) { michael@0: CTFontManagerSetAutoActivationSettingPtr(mainBundleID, michael@0: kAutoActivationDisabled); michael@0: } michael@0: } michael@0: michael@0: gfxPlatformMac::gfxPlatformMac() michael@0: { michael@0: DisableFontActivation(); michael@0: mFontAntiAliasingThreshold = ReadAntiAliasingThreshold(); michael@0: michael@0: uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | michael@0: BackendTypeBit(BackendType::SKIA) | michael@0: BackendTypeBit(BackendType::COREGRAPHICS); michael@0: uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS); michael@0: InitBackendPrefs(canvasMask, BackendType::COREGRAPHICS, michael@0: contentMask, BackendType::COREGRAPHICS); michael@0: } michael@0: michael@0: gfxPlatformMac::~gfxPlatformMac() michael@0: { michael@0: gfxCoreTextShaper::Shutdown(); michael@0: } michael@0: michael@0: gfxPlatformFontList* michael@0: gfxPlatformMac::CreatePlatformFontList() michael@0: { michael@0: gfxPlatformFontList* list = new gfxMacPlatformFontList(); michael@0: if (NS_SUCCEEDED(list->InitFontList())) { michael@0: return list; michael@0: } michael@0: gfxPlatformFontList::Shutdown(); michael@0: return nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatformMac::CreateOffscreenSurface(const IntSize& size, michael@0: gfxContentType contentType) michael@0: { michael@0: nsRefPtr newSurface = michael@0: new gfxQuartzSurface(ThebesIntSize(size), michael@0: OptimalFormatForContent(contentType)); michael@0: return newSurface.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatformMac::CreateOffscreenImageSurface(const gfxIntSize& aSize, michael@0: gfxContentType aContentType) michael@0: { michael@0: nsRefPtr surface = michael@0: CreateOffscreenSurface(aSize.ToIntSize(), aContentType); michael@0: #ifdef DEBUG michael@0: nsRefPtr imageSurface = surface->GetAsImageSurface(); michael@0: NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface"); michael@0: #endif michael@0: return surface.forget(); michael@0: } michael@0: michael@0: michael@0: already_AddRefed michael@0: gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, michael@0: gfxImageFormat format) michael@0: { michael@0: const gfxIntSize& surfaceSize = aSurface->GetSize(); michael@0: nsRefPtr isurf = aSurface; michael@0: michael@0: if (format != aSurface->Format()) { michael@0: isurf = new gfxImageSurface (surfaceSize, format); michael@0: if (!isurf->CopyFrom (aSurface)) { michael@0: // don't even bother doing anything more michael@0: nsRefPtr ret = aSurface; michael@0: return ret.forget(); michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: TemporaryRef michael@0: gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) michael@0: { michael@0: gfxMacFont *font = static_cast(aFont); michael@0: return font->GetScaledFont(aTarget); michael@0: } michael@0: michael@0: nsresult michael@0: gfxPlatformMac::ResolveFontName(const nsAString& aFontName, michael@0: FontResolverCallback aCallback, michael@0: void *aClosure, bool& aAborted) michael@0: { michael@0: nsAutoString resolvedName; michael@0: if (!gfxPlatformFontList::PlatformFontList()-> michael@0: ResolveFontName(aFontName, resolvedName)) { michael@0: aAborted = false; michael@0: return NS_OK; michael@0: } michael@0: aAborted = !(*aCallback)(resolvedName, aClosure); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); michael@0: return NS_OK; michael@0: } michael@0: michael@0: gfxFontGroup * michael@0: gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies, michael@0: const gfxFontStyle *aStyle, michael@0: gfxUserFontSet *aUserFontSet) michael@0: { michael@0: return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); michael@0: } michael@0: michael@0: // these will move to gfxPlatform once all platforms support the fontlist michael@0: gfxFontEntry* michael@0: gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const nsAString& aFontName) michael@0: { michael@0: return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, michael@0: aFontName); michael@0: } michael@0: michael@0: gfxFontEntry* michael@0: gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const uint8_t *aFontData, uint32_t aLength) michael@0: { michael@0: // Ownership of aFontData is received here, and passed on to michael@0: // gfxPlatformFontList::MakePlatformFont(), which must ensure the data michael@0: // is released with NS_Free when no longer needed michael@0: return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, michael@0: aFontData, michael@0: aLength); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) michael@0: { michael@0: // check for strange format flags michael@0: NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), michael@0: "strange font format hint set"); michael@0: michael@0: // accept supported formats michael@0: if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF | michael@0: gfxUserFontSet::FLAG_FORMAT_OPENTYPE | michael@0: gfxUserFontSet::FLAG_FORMAT_TRUETYPE | michael@0: gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)) { michael@0: return true; michael@0: } michael@0: michael@0: // reject all other formats, known and unknown michael@0: if (aFormatFlags != 0) { michael@0: return false; michael@0: } michael@0: michael@0: // no format hint set, need to look at data michael@0: return true; michael@0: } michael@0: michael@0: // these will also move to gfxPlatform once all platforms support the fontlist michael@0: nsresult michael@0: gfxPlatformMac::GetFontList(nsIAtom *aLangGroup, michael@0: const nsACString& aGenericFamily, michael@0: nsTArray& aListOfFonts) michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: gfxPlatformMac::UpdateFontList() michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->UpdateFontList(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static const char kFontArialUnicodeMS[] = "Arial Unicode MS"; michael@0: static const char kFontAppleBraille[] = "Apple Braille"; michael@0: static const char kFontAppleColorEmoji[] = "Apple Color Emoji"; michael@0: static const char kFontAppleSymbols[] = "Apple Symbols"; michael@0: static const char kFontDevanagariSangamMN[] = "Devanagari Sangam MN"; michael@0: static const char kFontEuphemiaUCAS[] = "Euphemia UCAS"; michael@0: static const char kFontGeneva[] = "Geneva"; michael@0: static const char kFontGeezaPro[] = "Geeza Pro"; michael@0: static const char kFontGujaratiSangamMN[] = "Gujarati Sangam MN"; michael@0: static const char kFontGurmukhiMN[] = "Gurmukhi MN"; michael@0: static const char kFontHiraginoKakuGothic[] = "Hiragino Kaku Gothic ProN"; michael@0: static const char kFontHiraginoSansGB[] = "Hiragino Sans GB"; michael@0: static const char kFontKefa[] = "Kefa"; michael@0: static const char kFontKhmerMN[] = "Khmer MN"; michael@0: static const char kFontLaoMN[] = "Lao MN"; michael@0: static const char kFontLucidaGrande[] = "Lucida Grande"; michael@0: static const char kFontMenlo[] = "Menlo"; michael@0: static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le"; michael@0: static const char kFontMingLiUExtB[] = "MingLiU-ExtB"; michael@0: static const char kFontMyanmarMN[] = "Myanmar MN"; michael@0: static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee"; michael@0: static const char kFontSimSunExtB[] = "SimSun-ExtB"; michael@0: static const char kFontSongtiSC[] = "Songti SC"; michael@0: static const char kFontSTHeiti[] = "STHeiti"; michael@0: static const char kFontSTIXGeneral[] = "STIXGeneral"; michael@0: static const char kFontTamilMN[] = "Tamil MN"; michael@0: michael@0: void michael@0: gfxPlatformMac::GetCommonFallbackFonts(const uint32_t aCh, michael@0: int32_t aRunScript, michael@0: nsTArray& aFontList) michael@0: { michael@0: aFontList.AppendElement(kFontLucidaGrande); michael@0: michael@0: if (!IS_IN_BMP(aCh)) { michael@0: uint32_t p = aCh >> 16; michael@0: uint32_t b = aCh >> 8; michael@0: if (p == 1) { michael@0: if (b >= 0x1f0 && b < 0x1f7) { michael@0: aFontList.AppendElement(kFontAppleColorEmoji); michael@0: } else { michael@0: aFontList.AppendElement(kFontAppleSymbols); michael@0: aFontList.AppendElement(kFontSTIXGeneral); michael@0: aFontList.AppendElement(kFontGeneva); michael@0: } michael@0: } else if (p == 2) { michael@0: // OSX installations with MS Office may have these fonts michael@0: aFontList.AppendElement(kFontMingLiUExtB); michael@0: aFontList.AppendElement(kFontSimSunExtB); michael@0: } michael@0: } else { michael@0: uint32_t b = (aCh >> 8) & 0xff; michael@0: michael@0: switch (b) { michael@0: case 0x03: michael@0: case 0x05: michael@0: aFontList.AppendElement(kFontGeneva); michael@0: break; michael@0: case 0x07: michael@0: aFontList.AppendElement(kFontGeezaPro); michael@0: break; michael@0: case 0x09: michael@0: aFontList.AppendElement(kFontDevanagariSangamMN); michael@0: break; michael@0: case 0x0a: michael@0: aFontList.AppendElement(kFontGurmukhiMN); michael@0: aFontList.AppendElement(kFontGujaratiSangamMN); michael@0: break; michael@0: case 0x0b: michael@0: aFontList.AppendElement(kFontTamilMN); michael@0: break; michael@0: case 0x0e: michael@0: aFontList.AppendElement(kFontLaoMN); michael@0: break; michael@0: case 0x0f: michael@0: aFontList.AppendElement(kFontSongtiSC); michael@0: break; michael@0: case 0x10: michael@0: aFontList.AppendElement(kFontMenlo); michael@0: aFontList.AppendElement(kFontMyanmarMN); michael@0: break; michael@0: case 0x13: // Cherokee michael@0: aFontList.AppendElement(kFontPlantagenetCherokee); michael@0: aFontList.AppendElement(kFontKefa); michael@0: break; michael@0: case 0x14: // Unified Canadian Aboriginal Syllabics michael@0: case 0x15: michael@0: case 0x16: michael@0: aFontList.AppendElement(kFontEuphemiaUCAS); michael@0: aFontList.AppendElement(kFontGeneva); michael@0: break; michael@0: case 0x18: // Mongolian, UCAS michael@0: aFontList.AppendElement(kFontSTHeiti); michael@0: aFontList.AppendElement(kFontEuphemiaUCAS); michael@0: break; michael@0: case 0x19: // Khmer michael@0: aFontList.AppendElement(kFontKhmerMN); michael@0: aFontList.AppendElement(kFontMicrosoftTaiLe); michael@0: break; michael@0: case 0x1d: michael@0: case 0x1e: michael@0: aFontList.AppendElement(kFontGeneva); michael@0: break; michael@0: case 0x20: // Symbol ranges michael@0: case 0x21: michael@0: case 0x22: michael@0: case 0x23: michael@0: case 0x24: michael@0: case 0x25: michael@0: case 0x26: michael@0: case 0x27: michael@0: case 0x29: michael@0: case 0x2a: michael@0: case 0x2b: michael@0: case 0x2e: michael@0: aFontList.AppendElement(kFontAppleSymbols); michael@0: aFontList.AppendElement(kFontMenlo); michael@0: aFontList.AppendElement(kFontSTIXGeneral); michael@0: aFontList.AppendElement(kFontGeneva); michael@0: aFontList.AppendElement(kFontHiraginoKakuGothic); michael@0: aFontList.AppendElement(kFontAppleColorEmoji); michael@0: break; michael@0: case 0x2c: michael@0: aFontList.AppendElement(kFontGeneva); michael@0: break; michael@0: case 0x2d: michael@0: aFontList.AppendElement(kFontKefa); michael@0: aFontList.AppendElement(kFontGeneva); michael@0: break; michael@0: case 0x28: // Braille michael@0: aFontList.AppendElement(kFontAppleBraille); michael@0: break; michael@0: case 0x31: michael@0: aFontList.AppendElement(kFontHiraginoSansGB); michael@0: break; michael@0: case 0x4d: michael@0: aFontList.AppendElement(kFontAppleSymbols); michael@0: break; michael@0: case 0xa0: // Yi michael@0: case 0xa1: michael@0: case 0xa2: michael@0: case 0xa3: michael@0: case 0xa4: michael@0: aFontList.AppendElement(kFontSTHeiti); michael@0: break; michael@0: case 0xa6: michael@0: case 0xa7: michael@0: aFontList.AppendElement(kFontGeneva); michael@0: aFontList.AppendElement(kFontAppleSymbols); michael@0: break; michael@0: case 0xab: michael@0: aFontList.AppendElement(kFontKefa); michael@0: break; michael@0: case 0xfc: michael@0: case 0xff: michael@0: aFontList.AppendElement(kFontAppleSymbols); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // Arial Unicode MS has lots of glyphs for obscure, use it as a last resort michael@0: aFontList.AppendElement(kFontArialUnicodeMS); michael@0: } michael@0: michael@0: uint32_t michael@0: gfxPlatformMac::ReadAntiAliasingThreshold() michael@0: { michael@0: uint32_t threshold = 0; // default == no threshold michael@0: michael@0: // first read prefs flag to determine whether to use the setting or not michael@0: bool useAntiAliasingThreshold = Preferences::GetBool("gfx.use_text_smoothing_setting", false); michael@0: michael@0: // if the pref setting is disabled, return 0 which effectively disables this feature michael@0: if (!useAntiAliasingThreshold) michael@0: return threshold; michael@0: michael@0: // value set via Appearance pref panel, "Turn off text smoothing for font sizes xxx and smaller" michael@0: CFNumberRef prefValue = (CFNumberRef)CFPreferencesCopyAppValue(CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication); michael@0: michael@0: if (prefValue) { michael@0: if (!CFNumberGetValue(prefValue, kCFNumberIntType, &threshold)) { michael@0: threshold = 0; michael@0: } michael@0: CFRelease(prefValue); michael@0: } michael@0: michael@0: return threshold; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) michael@0: { michael@0: if (aTarget->GetType() == BackendType::COREGRAPHICS_ACCELERATED) { michael@0: RefPtr source = aTarget->Snapshot(); michael@0: RefPtr sourceData = source->GetDataSurface(); michael@0: unsigned char* data = sourceData->GetData(); michael@0: nsRefPtr surf = new gfxImageSurface(data, ThebesIntSize(sourceData->GetSize()), sourceData->Stride(), michael@0: gfxImageFormat::ARGB32); michael@0: // We could fix this by telling gfxImageSurface it owns data. michael@0: nsRefPtr cpy = new gfxImageSurface(ThebesIntSize(sourceData->GetSize()), gfxImageFormat::ARGB32); michael@0: cpy->CopyFrom(surf); michael@0: return cpy.forget(); michael@0: } else if (aTarget->GetType() == BackendType::COREGRAPHICS) { michael@0: CGContextRef cg = static_cast(aTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT)); michael@0: michael@0: //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize michael@0: IntSize intSize = aTarget->GetSize(); michael@0: gfxIntSize size(intSize.width, intSize.height); michael@0: michael@0: nsRefPtr surf = michael@0: new gfxQuartzSurface(cg, size); michael@0: michael@0: return surf.forget(); michael@0: } michael@0: michael@0: return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatformMac::UseAcceleratedCanvas() michael@0: { michael@0: // Lion or later is required michael@0: return nsCocoaFeatures::OnLionOrLater() && Preferences::GetBool("gfx.canvas.azure.accelerated", false); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatformMac::SupportsOffMainThreadCompositing() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size) michael@0: { michael@0: mem = nullptr; michael@0: size = 0; michael@0: michael@0: CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); michael@0: if (!cspace) { michael@0: cspace = ::CGColorSpaceCreateDeviceRGB(); michael@0: } michael@0: if (!cspace) { michael@0: return; michael@0: } michael@0: michael@0: CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace); michael@0: michael@0: ::CFRelease(cspace); michael@0: michael@0: if (!iccp) { michael@0: return; michael@0: } michael@0: michael@0: // copy to external buffer michael@0: size = static_cast(::CFDataGetLength(iccp)); michael@0: if (size > 0) { michael@0: void *data = malloc(size); michael@0: if (data) { michael@0: memcpy(data, ::CFDataGetBytePtr(iccp), size); michael@0: mem = data; michael@0: } else { michael@0: size = 0; michael@0: } michael@0: } michael@0: michael@0: ::CFRelease(iccp); michael@0: }