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