michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 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: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: #endif michael@0: michael@0: #include "mozilla/layers/CompositorChild.h" michael@0: #include "mozilla/layers/CompositorParent.h" michael@0: #include "mozilla/layers/ImageBridgeChild.h" michael@0: #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter michael@0: michael@0: #include "prlog.h" michael@0: michael@0: #include "gfxPlatform.h" michael@0: #include "gfxPrefs.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #define getpid _getpid michael@0: #else michael@0: #include michael@0: #endif michael@0: michael@0: #include "nsXULAppAPI.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: michael@0: #if defined(XP_WIN) michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxD2DSurface.h" michael@0: #elif defined(XP_MACOSX) michael@0: #include "gfxPlatformMac.h" michael@0: #include "gfxQuartzSurface.h" michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: #include "gfxPlatformGtk.h" michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: #include "gfxQtPlatform.h" michael@0: #elif defined(ANDROID) michael@0: #include "gfxAndroidPlatform.h" michael@0: #endif michael@0: michael@0: #include "nsGkAtoms.h" michael@0: #include "gfxPlatformFontList.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxImageSurface.h" michael@0: #include "nsUnicodeProperties.h" michael@0: #include "harfbuzz/hb.h" michael@0: #include "gfxGraphiteShaper.h" michael@0: #include "gfx2DGlue.h" michael@0: #include "gfxGradientCache.h" michael@0: michael@0: #include "nsUnicodeRange.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsTArray.h" michael@0: #include "nsILocaleService.h" michael@0: #include "nsIObserverService.h" michael@0: #include "MainThreadUtils.h" michael@0: michael@0: #include "nsWeakReference.h" michael@0: michael@0: #include "cairo.h" michael@0: #include "qcms.h" michael@0: michael@0: #include "plstr.h" michael@0: #include "nsCRT.h" michael@0: #include "GLContext.h" michael@0: #include "GLContextProvider.h" michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "TexturePoolOGL.h" michael@0: #endif michael@0: michael@0: #include "mozilla/Hal.h" michael@0: #ifdef USE_SKIA michael@0: #include "skia/SkGraphics.h" michael@0: michael@0: #include "SkiaGLGlue.h" michael@0: #else michael@0: class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted { michael@0: }; michael@0: #endif michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Mutex.h" michael@0: michael@0: #include "nsIGfxInfo.h" michael@0: #include "nsIXULRuntime.h" michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: namespace mozilla { michael@0: namespace layers { michael@0: void InitGralloc(); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::layers; michael@0: michael@0: gfxPlatform *gPlatform = nullptr; michael@0: static bool gEverInitialized = false; michael@0: michael@0: static Mutex* gGfxPlatformPrefsLock = nullptr; michael@0: michael@0: // These two may point to the same profile michael@0: static qcms_profile *gCMSOutputProfile = nullptr; michael@0: static qcms_profile *gCMSsRGBProfile = nullptr; michael@0: michael@0: static qcms_transform *gCMSRGBTransform = nullptr; michael@0: static qcms_transform *gCMSInverseRGBTransform = nullptr; michael@0: static qcms_transform *gCMSRGBATransform = nullptr; michael@0: michael@0: static bool gCMSInitialized = false; michael@0: static eCMSMode gCMSMode = eCMSMode_Off; michael@0: michael@0: static bool gCMSIntentInitialized = false; michael@0: static int gCMSIntent = QCMS_INTENT_DEFAULT; michael@0: michael@0: michael@0: static void ShutdownCMS(); michael@0: michael@0: #include "mozilla/gfx/2D.h" michael@0: using namespace mozilla::gfx; michael@0: michael@0: /* Class to listen for pref changes so that chrome code can dynamically michael@0: force sRGB as an output profile. See Bug #452125. */ michael@0: class SRGBOverrideObserver MOZ_FINAL : public nsIObserver, michael@0: public nsSupportsWeakReference michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference) michael@0: michael@0: #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled" michael@0: michael@0: #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts" michael@0: #define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT michael@0: #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps" michael@0: michael@0: #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled" michael@0: michael@0: #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit" michael@0: #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries" michael@0: michael@0: #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled" michael@0: michael@0: #define BIDI_NUMERAL_PREF "bidi.numeral" michael@0: michael@0: #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb" michael@0: michael@0: NS_IMETHODIMP michael@0: SRGBOverrideObserver::Observe(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t* someData) michael@0: { michael@0: NS_ASSERTION(NS_strcmp(someData, michael@0: MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0, michael@0: "Restarting CMS on wrong pref!"); michael@0: ShutdownCMS(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static const char* kObservedPrefs[] = { michael@0: "gfx.downloadable_fonts.", michael@0: "gfx.font_rendering.", michael@0: BIDI_NUMERAL_PREF, michael@0: nullptr michael@0: }; michael@0: michael@0: class FontPrefsObserver MOZ_FINAL : public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: FontPrefsObserver::Observe(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t *someData) michael@0: { michael@0: if (!someData) { michael@0: NS_ERROR("font pref observer code broken"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone"); michael@0: gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get()); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: class MemoryPressureObserver MOZ_FINAL : public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: MemoryPressureObserver::Observe(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t *someData) michael@0: { michael@0: NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic"); michael@0: Factory::PurgeAllCaches(); michael@0: michael@0: gfxPlatform::GetPlatform()->PurgeSkiaCache(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // this needs to match the list of pref font.default.xx entries listed in all.js! michael@0: // the order *must* match the order in eFontPrefLang michael@0: static const char *gPrefLangNames[] = { michael@0: "x-western", michael@0: "x-central-euro", michael@0: "ja", michael@0: "zh-TW", michael@0: "zh-CN", michael@0: "zh-HK", michael@0: "ko", michael@0: "x-cyrillic", michael@0: "x-baltic", michael@0: "el", michael@0: "tr", michael@0: "th", michael@0: "he", michael@0: "ar", michael@0: "x-devanagari", michael@0: "x-tamil", michael@0: "x-armn", michael@0: "x-beng", michael@0: "x-cans", michael@0: "x-ethi", michael@0: "x-geor", michael@0: "x-gujr", michael@0: "x-guru", michael@0: "x-khmr", michael@0: "x-mlym", michael@0: "x-orya", michael@0: "x-telu", michael@0: "x-knda", michael@0: "x-sinh", michael@0: "x-tibt", michael@0: "x-unicode", michael@0: }; michael@0: michael@0: gfxPlatform::gfxPlatform() michael@0: : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(), michael@0: &gfxPlatform::GetAzureBackendInfo) michael@0: { michael@0: mUseHarfBuzzScripts = UNINITIALIZED_VALUE; michael@0: mAllowDownloadableFonts = UNINITIALIZED_VALUE; michael@0: mFallbackUsesCmaps = UNINITIALIZED_VALUE; michael@0: michael@0: mWordCacheCharLimit = UNINITIALIZED_VALUE; michael@0: mWordCacheMaxEntries = UNINITIALIZED_VALUE; michael@0: mGraphiteShapingEnabled = UNINITIALIZED_VALUE; michael@0: mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; michael@0: mBidiNumeralOption = UNINITIALIZED_VALUE; michael@0: michael@0: mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default; michael@0: michael@0: mSkiaGlue = nullptr; michael@0: michael@0: uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA); michael@0: uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); michael@0: InitBackendPrefs(canvasMask, BackendType::CAIRO, michael@0: contentMask, BackendType::CAIRO); michael@0: } michael@0: michael@0: gfxPlatform* michael@0: gfxPlatform::GetPlatform() michael@0: { michael@0: if (!gPlatform) { michael@0: Init(); michael@0: } michael@0: return gPlatform; michael@0: } michael@0: michael@0: void RecordingPrefChanged(const char *aPrefName, void *aClosure) michael@0: { michael@0: if (Preferences::GetBool("gfx.2d.recording", false)) { michael@0: nsAutoCString fileName; michael@0: nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile"); michael@0: michael@0: if (prefFileName) { michael@0: fileName.Append(NS_ConvertUTF16toUTF8(prefFileName)); michael@0: } else { michael@0: nsCOMPtr tmpFile; michael@0: if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) { michael@0: return; michael@0: } michael@0: fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid()); michael@0: michael@0: nsresult rv = tmpFile->AppendNative(fileName); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: rv = tmpFile->GetNativePath(fileName); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: } michael@0: michael@0: gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading()); michael@0: printf_stderr("Recording to %s\n", fileName.get()); michael@0: Factory::SetGlobalEventRecorder(gPlatform->mRecorder); michael@0: } else { michael@0: Factory::SetGlobalEventRecorder(nullptr); michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::Init() michael@0: { michael@0: if (gEverInitialized) { michael@0: NS_RUNTIMEABORT("Already started???"); michael@0: } michael@0: gEverInitialized = true; michael@0: michael@0: // Initialize the preferences by creating the singleton. michael@0: gfxPrefs::GetSingleton(); michael@0: michael@0: gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock"); michael@0: michael@0: /* Initialize the GfxInfo service. michael@0: * Note: we can't call functions on GfxInfo that depend michael@0: * on gPlatform until after it has been initialized michael@0: * below. GfxInfo initialization annotates our michael@0: * crash reports so we want to do it before michael@0: * we try to load any drivers and do device detection michael@0: * incase that code crashes. See bug #591561. */ michael@0: nsCOMPtr gfxInfo; michael@0: /* this currently will only succeed on Windows */ michael@0: gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); michael@0: michael@0: #if defined(XP_WIN) michael@0: gPlatform = new gfxWindowsPlatform; michael@0: #elif defined(XP_MACOSX) michael@0: gPlatform = new gfxPlatformMac; michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: gPlatform = new gfxPlatformGtk; michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: gPlatform = new gfxQtPlatform; michael@0: #elif defined(ANDROID) michael@0: gPlatform = new gfxAndroidPlatform; michael@0: #else michael@0: #error "No gfxPlatform implementation available" michael@0: #endif michael@0: michael@0: #ifdef DEBUG michael@0: mozilla::gl::GLContext::StaticInit(); michael@0: #endif michael@0: michael@0: bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() || michael@0: GetPrefLayersOffMainThreadCompositionEnabled(); michael@0: michael@0: if (!OffMainThreadCompositionRequired()) { michael@0: useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing(); michael@0: } michael@0: michael@0: if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) { michael@0: CompositorParent::StartUp(); michael@0: if (gfxPrefs::AsyncVideoEnabled()) { michael@0: ImageBridgeChild::StartUp(); michael@0: } michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others michael@0: rv = gfxPlatformFontList::Init(); michael@0: if (NS_FAILED(rv)) { michael@0: NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList"); michael@0: } michael@0: #endif michael@0: michael@0: gPlatform->mScreenReferenceSurface = michael@0: gPlatform->CreateOffscreenSurface(IntSize(1, 1), michael@0: gfxContentType::COLOR_ALPHA); michael@0: if (!gPlatform->mScreenReferenceSurface) { michael@0: NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface"); michael@0: } michael@0: michael@0: gPlatform->mScreenReferenceDrawTarget = michael@0: gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1), michael@0: SurfaceFormat::B8G8R8A8); michael@0: if (!gPlatform->mScreenReferenceDrawTarget) { michael@0: NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget"); michael@0: } michael@0: michael@0: rv = gfxFontCache::Init(); michael@0: if (NS_FAILED(rv)) { michael@0: NS_RUNTIMEABORT("Could not initialize gfxFontCache"); michael@0: } michael@0: michael@0: /* Create and register our CMS Override observer. */ michael@0: gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver(); michael@0: Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB); michael@0: michael@0: gPlatform->mFontPrefsObserver = new FontPrefsObserver(); michael@0: Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs); michael@0: michael@0: mozilla::gl::GLContext::PlatformStartup(); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // Texture pool init michael@0: mozilla::gl::TexturePoolOGL::Init(); michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: mozilla::layers::InitGralloc(); michael@0: #endif michael@0: michael@0: Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr); michael@0: michael@0: CreateCMSOutputProfile(); michael@0: michael@0: // Listen to memory pressure event so we can purge DrawTarget caches michael@0: nsCOMPtr obs = mozilla::services::GetObserverService(); michael@0: if (obs) { michael@0: gPlatform->mMemoryPressureObserver = new MemoryPressureObserver(); michael@0: obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false); michael@0: } michael@0: michael@0: RegisterStrongMemoryReporter(new GfxMemoryImageReporter()); michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::Shutdown() michael@0: { michael@0: // These may be called before the corresponding subsystems have actually michael@0: // started up. That's OK, they can handle it. michael@0: gfxFontCache::Shutdown(); michael@0: gfxFontGroup::Shutdown(); michael@0: gfxGradientCache::Shutdown(); michael@0: gfxGraphiteShaper::Shutdown(); michael@0: #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others michael@0: gfxPlatformFontList::Shutdown(); michael@0: #endif michael@0: michael@0: // Free the various non-null transforms and loaded profiles michael@0: ShutdownCMS(); michael@0: michael@0: // In some cases, gPlatform may not be created but Shutdown() called, michael@0: // e.g., during xpcshell tests. michael@0: if (gPlatform) { michael@0: /* Unregister our CMS Override callback. */ michael@0: NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone"); michael@0: Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB); michael@0: gPlatform->mSRGBOverrideObserver = nullptr; michael@0: michael@0: NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone"); michael@0: Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs); michael@0: gPlatform->mFontPrefsObserver = nullptr; michael@0: michael@0: NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone"); michael@0: nsCOMPtr obs = mozilla::services::GetObserverService(); michael@0: if (obs) { michael@0: obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure"); michael@0: } michael@0: michael@0: gPlatform->mMemoryPressureObserver = nullptr; michael@0: gPlatform->mSkiaGlue = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // Shut down the texture pool michael@0: mozilla::gl::TexturePoolOGL::Shutdown(); michael@0: #endif michael@0: michael@0: // Shut down the default GL context provider. michael@0: mozilla::gl::GLContextProvider::Shutdown(); michael@0: michael@0: #if defined(XP_WIN) michael@0: // The above shutdown calls operate on the available context providers on michael@0: // most platforms. Windows is a "special snowflake", though, and has three michael@0: // context providers available, so we have to shut all of them down. michael@0: // We should only support the default GL provider on Windows; then, this michael@0: // could go away. Unfortunately, we currently support WGL (the default) for michael@0: // WebGL on Optimus. michael@0: mozilla::gl::GLContextProviderEGL::Shutdown(); michael@0: #endif michael@0: michael@0: delete gGfxPlatformPrefsLock; michael@0: michael@0: gfxPrefs::DestroySingleton(); michael@0: gfxFont::DestroySingletons(); michael@0: michael@0: delete gPlatform; michael@0: gPlatform = nullptr; michael@0: } michael@0: michael@0: gfxPlatform::~gfxPlatform() michael@0: { michael@0: mScreenReferenceSurface = nullptr; michael@0: mScreenReferenceDrawTarget = nullptr; michael@0: michael@0: // The cairo folks think we should only clean up in debug builds, michael@0: // but we're generally in the habit of trying to shut down as michael@0: // cleanly as possible even in production code, so call this michael@0: // cairo_debug_* function unconditionally. michael@0: // michael@0: // because cairo can assert and thus crash on shutdown, don't do this in release builds michael@0: #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND) michael@0: #ifdef USE_SKIA michael@0: // must do Skia cleanup before Cairo cleanup, because Skia may be referencing michael@0: // Cairo objects e.g. through SkCairoFTTypeface michael@0: SkGraphics::Term(); michael@0: #endif michael@0: michael@0: #if MOZ_TREE_CAIRO michael@0: cairo_debug_reset_static_data(); michael@0: #endif michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::PreferMemoryOverShmem() const { michael@0: MOZ_ASSERT(!CompositorParent::IsInCompositorThread()); michael@0: return mLayersPreferMemoryOverShmem; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize, michael@0: gfxContentType aContentType) michael@0: { michael@0: nsRefPtr newSurface; michael@0: newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType)); michael@0: michael@0: return newSurface.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatform::OptimizeImage(gfxImageSurface *aSurface, michael@0: gfxImageFormat format) michael@0: { michael@0: IntSize surfaceSize = aSurface->GetSize().ToIntSize(); michael@0: michael@0: #ifdef XP_WIN michael@0: if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == michael@0: gfxWindowsPlatform::RENDER_DIRECT2D) { michael@0: return nullptr; michael@0: } michael@0: #endif michael@0: nsRefPtr optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format)); michael@0: if (!optSurface || optSurface->CairoStatus() != 0) michael@0: return nullptr; michael@0: michael@0: gfxContext tmpCtx(optSurface); michael@0: tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: tmpCtx.SetSource(aSurface); michael@0: tmpCtx.Paint(); michael@0: michael@0: return optSurface.forget(); michael@0: } michael@0: michael@0: cairo_user_data_key_t kDrawTarget; michael@0: michael@0: RefPtr michael@0: gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize) michael@0: { michael@0: SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType()); michael@0: RefPtr drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format); michael@0: aSurface->SetData(&kDrawTarget, drawTarget, nullptr); michael@0: return drawTarget; michael@0: } michael@0: michael@0: // This is a temporary function used by ContentClient to build a DrawTarget michael@0: // around the gfxASurface. This should eventually be replaced by plumbing michael@0: // the DrawTarget through directly michael@0: RefPtr michael@0: gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: // this is a bit of a hack that assumes that the buffer associated with the CGContext michael@0: // will live around long enough that nothing bad will happen. michael@0: if (aSurface->GetType() == gfxSurfaceType::Quartz) { michael@0: return Factory::CreateDrawTargetForCairoCGContext(static_cast(aSurface)->GetCGContext(), aSize); michael@0: } michael@0: #endif michael@0: MOZ_CRASH(); michael@0: return nullptr; michael@0: } michael@0: michael@0: michael@0: cairo_user_data_key_t kSourceSurface; michael@0: michael@0: /** michael@0: * Record the backend that was used to construct the SourceSurface. michael@0: * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair, michael@0: * we check to make sure the DrawTarget's backend matches the backend michael@0: * for the cached SourceSurface, and only use it if they match. This michael@0: * can avoid expensive and unnecessary readbacks. michael@0: */ michael@0: struct SourceSurfaceUserData michael@0: { michael@0: RefPtr mSrcSurface; michael@0: BackendType mBackendType; michael@0: }; michael@0: michael@0: void SourceBufferDestroy(void *srcSurfUD) michael@0: { michael@0: delete static_cast(srcSurfUD); michael@0: } michael@0: michael@0: UserDataKey kThebesSurface; michael@0: michael@0: struct DependentSourceSurfaceUserData michael@0: { michael@0: nsRefPtr mSurface; michael@0: }; michael@0: michael@0: void SourceSurfaceDestroyed(void *aData) michael@0: { michael@0: delete static_cast(aData); michael@0: } michael@0: michael@0: #if MOZ_TREE_CAIRO michael@0: void SourceSnapshotDetached(cairo_surface_t *nullSurf) michael@0: { michael@0: gfxImageSurface* origSurf = michael@0: static_cast(cairo_surface_get_user_data(nullSurf, &kSourceSurface)); michael@0: michael@0: origSurf->SetData(&kSourceSurface, nullptr, nullptr); michael@0: } michael@0: #else michael@0: void SourceSnapshotDetached(void *nullSurf) michael@0: { michael@0: gfxImageSurface* origSurf = static_cast(nullSurf); michael@0: origSurf->SetData(&kSourceSurface, nullptr, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: void michael@0: gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface) michael@0: { michael@0: aSurface->SetData(&kSourceSurface, nullptr, nullptr); michael@0: } michael@0: michael@0: static TemporaryRef michael@0: CopySurface(gfxASurface* aSurface) michael@0: { michael@0: const nsIntSize size = aSurface->GetSize(); michael@0: gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType()); michael@0: RefPtr data = michael@0: Factory::CreateDataSourceSurface(ToIntSize(size), michael@0: ImageFormatToSurfaceFormat(format)); michael@0: if (!data) { michael@0: return nullptr; michael@0: } michael@0: michael@0: DataSourceSurface::MappedSurface map; michael@0: DebugOnly result = data->Map(DataSourceSurface::WRITE, &map); michael@0: MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!"); michael@0: michael@0: nsRefPtr image = new gfxImageSurface(map.mData, size, map.mStride, format); michael@0: nsRefPtr ctx = new gfxContext(image); michael@0: michael@0: ctx->SetSource(aSurface); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->Paint(); michael@0: michael@0: data->Unmap(); michael@0: michael@0: return data; michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface) michael@0: { michael@0: if (!aSurface->CairoSurface() || aSurface->CairoStatus()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!aTarget) { michael@0: if (ScreenReferenceDrawTarget()) { michael@0: aTarget = ScreenReferenceDrawTarget(); michael@0: } else { michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: void *userData = aSurface->GetData(&kSourceSurface); michael@0: michael@0: if (userData) { michael@0: SourceSurfaceUserData *surf = static_cast(userData); michael@0: michael@0: if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetType()) { michael@0: return surf->mSrcSurface; michael@0: } michael@0: // We can just continue here as when setting new user data the destroy michael@0: // function will be called for the old user data. michael@0: } michael@0: michael@0: SurfaceFormat format; michael@0: if (aSurface->GetContentType() == gfxContentType::ALPHA) { michael@0: format = SurfaceFormat::A8; michael@0: } else if (aSurface->GetContentType() == gfxContentType::COLOR) { michael@0: format = SurfaceFormat::B8G8R8X8; michael@0: } else { michael@0: format = SurfaceFormat::B8G8R8A8; michael@0: } michael@0: michael@0: RefPtr srcBuffer; michael@0: michael@0: #ifdef XP_WIN michael@0: if (aSurface->GetType() == gfxSurfaceType::D2D && michael@0: format != SurfaceFormat::A8) { michael@0: NativeSurface surf; michael@0: surf.mFormat = format; michael@0: surf.mType = NativeSurfaceType::D3D10_TEXTURE; michael@0: surf.mSurface = static_cast(aSurface)->GetTexture(); michael@0: surf.mSize = ToIntSize(aSurface->GetSize()); michael@0: mozilla::gfx::DrawTarget *dt = static_cast(aSurface->GetData(&kDrawTarget)); michael@0: if (dt) { michael@0: dt->Flush(); michael@0: } michael@0: srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf); michael@0: } else michael@0: #endif michael@0: if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) { michael@0: // If this is an xlib cairo surface we don't want to fetch it into memory michael@0: // because this is a major slow down. michael@0: NativeSurface surf; michael@0: surf.mFormat = format; michael@0: surf.mType = NativeSurfaceType::CAIRO_SURFACE; michael@0: surf.mSurface = aSurface->CairoSurface(); michael@0: surf.mSize = ToIntSize(aSurface->GetSize()); michael@0: srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf); michael@0: michael@0: if (srcBuffer) { michael@0: // It's cheap enough to make a new one so we won't keep it around and michael@0: // keeping it creates a cycle. michael@0: return srcBuffer; michael@0: } michael@0: } michael@0: michael@0: if (!srcBuffer) { michael@0: nsRefPtr imgSurface = aSurface->GetAsImageSurface(); michael@0: michael@0: RefPtr dataSurf; michael@0: michael@0: if (imgSurface) { michael@0: dataSurf = GetWrappedDataSourceSurface(aSurface); michael@0: } else { michael@0: dataSurf = CopySurface(aSurface); michael@0: } michael@0: michael@0: if (!dataSurf) { michael@0: return nullptr; michael@0: } michael@0: michael@0: srcBuffer = aTarget->OptimizeSourceSurface(dataSurf); michael@0: michael@0: if (imgSurface && srcBuffer == dataSurf) { michael@0: // Our wrapping surface will hold a reference to its image surface. We cause michael@0: // a reference cycle if we add it to the cache. And caching it is pretty michael@0: // pointless since we'll just wrap it again next use. michael@0: return srcBuffer; michael@0: } michael@0: } michael@0: michael@0: // Add user data to aSurface so we can cache lookups in the future. michael@0: SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData; michael@0: srcSurfUD->mBackendType = aTarget->GetType(); michael@0: srcSurfUD->mSrcSurface = srcBuffer; michael@0: aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy); michael@0: michael@0: return srcBuffer; michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface) michael@0: { michael@0: nsRefPtr image = aSurface->GetAsImageSurface(); michael@0: if (!image) { michael@0: return nullptr; michael@0: } michael@0: RefPtr result = michael@0: Factory::CreateWrappingDataSourceSurface(image->Data(), michael@0: image->Stride(), michael@0: ToIntSize(image->GetSize()), michael@0: ImageFormatToSurfaceFormat(image->Format())); michael@0: michael@0: if (!result) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // If we wrapped the underlying data of aSurface, then we need to add user data michael@0: // to make sure aSurface stays alive until we are done with the data. michael@0: DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData; michael@0: srcSurfUD->mSurface = aSurface; michael@0: result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: TemporaryRef michael@0: gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) michael@0: { michael@0: NativeFont nativeFont; michael@0: nativeFont.mType = NativeFontType::CAIRO_FONT_FACE; michael@0: nativeFont.mFont = aFont->GetCairoScaledFont(); michael@0: RefPtr scaledFont = michael@0: Factory::CreateScaledFontForNativeFont(nativeFont, michael@0: aFont->GetAdjustedSize()); michael@0: return scaledFont; michael@0: } michael@0: michael@0: cairo_user_data_key_t kDrawSourceSurface; michael@0: static void michael@0: DataSourceSurfaceDestroy(void *dataSourceSurface) michael@0: { michael@0: static_cast(dataSourceSurface)->Release(); michael@0: } michael@0: michael@0: cairo_user_data_key_t kDrawTargetForSurface; michael@0: static void michael@0: DataDrawTargetDestroy(void *aTarget) michael@0: { michael@0: static_cast(aTarget)->Release(); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) michael@0: { michael@0: if (!aTarget) { michael@0: return false; michael@0: } michael@0: michael@0: return SupportsAzureContentForType(aTarget->GetType()); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::UseAcceleratedSkiaCanvas() michael@0: { michael@0: return gfxPrefs::CanvasAzureAccelerated() && michael@0: mPreferredCanvasBackend == BackendType::SKIA; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::InitializeSkiaCacheLimits() michael@0: { michael@0: if (UseAcceleratedSkiaCanvas()) { michael@0: bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache(); michael@0: int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems(); michael@0: int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize(); michael@0: michael@0: // Prefs are in megabytes, but we want the sizes in bytes michael@0: cacheSizeLimit *= 1024*1024; michael@0: michael@0: if (usingDynamicCache) { michael@0: uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory(); michael@0: michael@0: if (totalMemory <= 256*1024*1024) { michael@0: // We need a very minimal cache on 256 meg devices michael@0: cacheSizeLimit = 2*1024*1024; michael@0: } else if (totalMemory > 0) { michael@0: cacheSizeLimit = totalMemory / 16; michael@0: } michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit); michael@0: #endif michael@0: michael@0: #ifdef USE_SKIA_GPU michael@0: mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: mozilla::gl::SkiaGLGlue* michael@0: gfxPlatform::GetSkiaGLGlue() michael@0: { michael@0: #ifdef USE_SKIA_GPU michael@0: if (!mSkiaGlue) { michael@0: /* Dummy context. We always draw into a FBO. michael@0: * michael@0: * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it michael@0: * stands, this only works on the main thread. michael@0: */ michael@0: mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA(); michael@0: nsRefPtr glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps); michael@0: if (!glContext) { michael@0: printf_stderr("Failed to create GLContext for SkiaGL!\n"); michael@0: return nullptr; michael@0: } michael@0: mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext); michael@0: MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext"); michael@0: InitializeSkiaCacheLimits(); michael@0: } michael@0: #endif michael@0: michael@0: return mSkiaGlue; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::PurgeSkiaCache() michael@0: { michael@0: #ifdef USE_SKIA_GPU michael@0: if (!mSkiaGlue) michael@0: return; michael@0: michael@0: mSkiaGlue->GetGrContext()->freeGpuResources(); michael@0: #endif michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) michael@0: { michael@0: if (aTarget->GetType() == BackendType::CAIRO) { michael@0: cairo_surface_t* csurf = michael@0: static_cast(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE)); michael@0: if (csurf) { michael@0: return gfxASurface::Wrap(csurf); michael@0: } michael@0: } michael@0: michael@0: // The semantics of this part of the function are sort of weird. If we michael@0: // don't have direct support for the backend, we snapshot the first time michael@0: // and then return the snapshotted surface for the lifetime of the draw michael@0: // target. Sometimes it seems like this works out, but it seems like it michael@0: // might result in no updates ever. michael@0: RefPtr source = aTarget->Snapshot(); michael@0: RefPtr data = source->GetDataSurface(); michael@0: michael@0: if (!data) { michael@0: return nullptr; michael@0: } michael@0: michael@0: IntSize size = data->GetSize(); michael@0: gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat()); michael@0: michael@0: michael@0: nsRefPtr surf = michael@0: new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height), michael@0: data->Stride(), format); michael@0: michael@0: if (surf->CairoStatus()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy); michael@0: // keep the draw target alive as long as we need its data michael@0: aTarget->AddRef(); michael@0: surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy); michael@0: michael@0: return surf.forget(); michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) michael@0: { michael@0: // There is a bunch of knowledge in the gfxPlatform heirarchy about how to michael@0: // create the best offscreen surface for the current system and situation. We michael@0: // can easily take advantage of this for the Cairo backend, so that's what we michael@0: // do. michael@0: // mozilla::gfx::Factory can get away without having all this knowledge for michael@0: // now, but this might need to change in the future (using michael@0: // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all michael@0: // backends). michael@0: if (aBackend == BackendType::CAIRO) { michael@0: nsRefPtr surf = CreateOffscreenSurface(aSize, michael@0: ContentForFormat(aFormat)); michael@0: if (!surf || surf->CairoStatus()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return CreateDrawTargetForSurface(surf, aSize); michael@0: } else { michael@0: return Factory::CreateDrawTarget(aBackend, aSize, aFormat); michael@0: } michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) michael@0: { michael@0: NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend."); michael@0: RefPtr target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat); michael@0: if (target || michael@0: mFallbackCanvasBackend == BackendType::NONE) { michael@0: return target; michael@0: } michael@0: michael@0: return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat); michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) michael@0: { michael@0: NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend."); michael@0: return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat); michael@0: } michael@0: michael@0: RefPtr michael@0: gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) michael@0: { michael@0: NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend."); michael@0: if (mContentBackend == BackendType::CAIRO) { michael@0: nsRefPtr image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat)); michael@0: return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize); michael@0: } michael@0: return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat); michael@0: } michael@0: michael@0: /* static */ BackendType michael@0: gfxPlatform::BackendTypeForName(const nsCString& aName) michael@0: { michael@0: if (aName.EqualsLiteral("cairo")) michael@0: return BackendType::CAIRO; michael@0: if (aName.EqualsLiteral("skia")) michael@0: return BackendType::SKIA; michael@0: if (aName.EqualsLiteral("direct2d")) michael@0: return BackendType::DIRECT2D; michael@0: if (aName.EqualsLiteral("cg")) michael@0: return BackendType::COREGRAPHICS; michael@0: return BackendType::NONE; michael@0: } michael@0: michael@0: nsresult michael@0: gfxPlatform::GetFontList(nsIAtom *aLangGroup, michael@0: const nsACString& aGenericFamily, michael@0: nsTArray& aListOfFonts) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: nsresult michael@0: gfxPlatform::UpdateFontList() michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::DownloadableFontsEnabled() michael@0: { michael@0: if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) { michael@0: mAllowDownloadableFonts = michael@0: Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false); michael@0: } michael@0: michael@0: return mAllowDownloadableFonts; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::UseCmapsDuringSystemFallback() michael@0: { michael@0: if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) { michael@0: mFallbackUsesCmaps = michael@0: Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false); michael@0: } michael@0: michael@0: return mFallbackUsesCmaps; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::OpenTypeSVGEnabled() michael@0: { michael@0: if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) { michael@0: mOpenTypeSVGEnabled = michael@0: Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false); michael@0: } michael@0: michael@0: return mOpenTypeSVGEnabled > 0; michael@0: } michael@0: michael@0: uint32_t michael@0: gfxPlatform::WordCacheCharLimit() michael@0: { michael@0: if (mWordCacheCharLimit == UNINITIALIZED_VALUE) { michael@0: mWordCacheCharLimit = michael@0: Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32); michael@0: if (mWordCacheCharLimit < 0) { michael@0: mWordCacheCharLimit = 32; michael@0: } michael@0: } michael@0: michael@0: return uint32_t(mWordCacheCharLimit); michael@0: } michael@0: michael@0: uint32_t michael@0: gfxPlatform::WordCacheMaxEntries() michael@0: { michael@0: if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) { michael@0: mWordCacheMaxEntries = michael@0: Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000); michael@0: if (mWordCacheMaxEntries < 0) { michael@0: mWordCacheMaxEntries = 10000; michael@0: } michael@0: } michael@0: michael@0: return uint32_t(mWordCacheMaxEntries); michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::UseGraphiteShaping() michael@0: { michael@0: if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) { michael@0: mGraphiteShapingEnabled = michael@0: Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false); michael@0: } michael@0: michael@0: return mGraphiteShapingEnabled; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode) michael@0: { michael@0: if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) { michael@0: mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT); michael@0: } michael@0: michael@0: int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode); michael@0: michael@0: return (mUseHarfBuzzScripts & shapingType) != 0; michael@0: } michael@0: michael@0: gfxFontEntry* michael@0: gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const uint8_t *aFontData, michael@0: uint32_t aLength) michael@0: { michael@0: // Default implementation does not handle activating downloaded fonts; michael@0: // just free the data and return. michael@0: // Platforms that support @font-face must override this, michael@0: // using the data to instantiate the font, and taking responsibility michael@0: // for freeing it when no longer required. michael@0: if (aFontData) { michael@0: NS_Free((void*)aFontData); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: static void michael@0: AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch()); michael@0: michael@0: nsAutoCString prefName, langGroupString; michael@0: michael@0: aLangGroup->ToUTF8String(langGroupString); michael@0: michael@0: nsAutoCString genericDotLang; michael@0: if (aGenericName) { michael@0: genericDotLang.Assign(aGenericName); michael@0: } else { michael@0: prefName.AssignLiteral("font.default."); michael@0: prefName.Append(langGroupString); michael@0: genericDotLang = Preferences::GetCString(prefName.get()); michael@0: } michael@0: michael@0: genericDotLang.AppendLiteral("."); michael@0: genericDotLang.Append(langGroupString); michael@0: michael@0: // fetch font.name.xxx value michael@0: prefName.AssignLiteral("font.name."); michael@0: prefName.Append(genericDotLang); michael@0: nsAdoptingString nameValue = Preferences::GetString(prefName.get()); michael@0: if (nameValue) { michael@0: if (!aFonts.IsEmpty()) michael@0: aFonts.AppendLiteral(", "); michael@0: aFonts += nameValue; michael@0: } michael@0: michael@0: // fetch font.name-list.xxx value michael@0: prefName.AssignLiteral("font.name-list."); michael@0: prefName.Append(genericDotLang); michael@0: nsAdoptingString nameListValue = Preferences::GetString(prefName.get()); michael@0: if (nameListValue && !nameListValue.Equals(nameValue)) { michael@0: if (!aFonts.IsEmpty()) michael@0: aFonts.AppendLiteral(", "); michael@0: aFonts += nameListValue; michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode) michael@0: { michael@0: aFonts.Truncate(); michael@0: michael@0: AppendGenericFontFromPref(aFonts, aLanguage, nullptr); michael@0: if (aAppendUnicode) michael@0: AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr); michael@0: } michael@0: michael@0: bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback, michael@0: void *aClosure) michael@0: { michael@0: NS_ENSURE_TRUE(Preferences::GetRootBranch(), false); michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < aLangArrayLen; i++) { michael@0: eFontPrefLang prefLang = aLangArray[i]; michael@0: const char *langGroup = GetPrefLangName(prefLang); michael@0: michael@0: nsAutoCString prefName; michael@0: michael@0: prefName.AssignLiteral("font.default."); michael@0: prefName.Append(langGroup); michael@0: nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get()); michael@0: michael@0: genericDotLang.AppendLiteral("."); michael@0: genericDotLang.Append(langGroup); michael@0: michael@0: // fetch font.name.xxx value michael@0: prefName.AssignLiteral("font.name."); michael@0: prefName.Append(genericDotLang); michael@0: nsAdoptingCString nameValue = Preferences::GetCString(prefName.get()); michael@0: if (nameValue) { michael@0: if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure)) michael@0: return false; michael@0: } michael@0: michael@0: // fetch font.name-list.xxx value michael@0: prefName.AssignLiteral("font.name-list."); michael@0: prefName.Append(genericDotLang); michael@0: nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get()); michael@0: if (nameListValue && !nameListValue.Equals(nameValue)) { michael@0: const char kComma = ','; michael@0: const char *p, *p_end; michael@0: nsAutoCString list(nameListValue); michael@0: list.BeginReading(p); michael@0: list.EndReading(p_end); michael@0: while (p < p_end) { michael@0: while (nsCRT::IsAsciiSpace(*p)) { michael@0: if (++p == p_end) michael@0: break; michael@0: } michael@0: if (p == p_end) michael@0: break; michael@0: const char *start = p; michael@0: while (++p != p_end && *p != kComma) michael@0: /* nothing */ ; michael@0: nsAutoCString fontName(Substring(start, p)); michael@0: fontName.CompressWhitespace(false, true); michael@0: if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure)) michael@0: return false; michael@0: p++; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: eFontPrefLang michael@0: gfxPlatform::GetFontPrefLangFor(const char* aLang) michael@0: { michael@0: if (!aLang || !aLang[0]) { michael@0: return eFontPrefLang_Others; michael@0: } michael@0: for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) { michael@0: if (!PL_strcasecmp(gPrefLangNames[i], aLang)) { michael@0: return eFontPrefLang(i); michael@0: } michael@0: } michael@0: return eFontPrefLang_Others; michael@0: } michael@0: michael@0: eFontPrefLang michael@0: gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang) michael@0: { michael@0: if (!aLang) michael@0: return eFontPrefLang_Others; michael@0: nsAutoCString lang; michael@0: aLang->ToUTF8String(lang); michael@0: return GetFontPrefLangFor(lang.get()); michael@0: } michael@0: michael@0: const char* michael@0: gfxPlatform::GetPrefLangName(eFontPrefLang aLang) michael@0: { michael@0: if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) { michael@0: return gPrefLangNames[uint32_t(aLang)]; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: eFontPrefLang michael@0: gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange) michael@0: { michael@0: switch (aUnicodeRange) { michael@0: case kRangeSetLatin: return eFontPrefLang_Western; michael@0: case kRangeCyrillic: return eFontPrefLang_Cyrillic; michael@0: case kRangeGreek: return eFontPrefLang_Greek; michael@0: case kRangeTurkish: return eFontPrefLang_Turkish; michael@0: case kRangeHebrew: return eFontPrefLang_Hebrew; michael@0: case kRangeArabic: return eFontPrefLang_Arabic; michael@0: case kRangeBaltic: return eFontPrefLang_Baltic; michael@0: case kRangeThai: return eFontPrefLang_Thai; michael@0: case kRangeKorean: return eFontPrefLang_Korean; michael@0: case kRangeJapanese: return eFontPrefLang_Japanese; michael@0: case kRangeSChinese: return eFontPrefLang_ChineseCN; michael@0: case kRangeTChinese: return eFontPrefLang_ChineseTW; michael@0: case kRangeDevanagari: return eFontPrefLang_Devanagari; michael@0: case kRangeTamil: return eFontPrefLang_Tamil; michael@0: case kRangeArmenian: return eFontPrefLang_Armenian; michael@0: case kRangeBengali: return eFontPrefLang_Bengali; michael@0: case kRangeCanadian: return eFontPrefLang_Canadian; michael@0: case kRangeEthiopic: return eFontPrefLang_Ethiopic; michael@0: case kRangeGeorgian: return eFontPrefLang_Georgian; michael@0: case kRangeGujarati: return eFontPrefLang_Gujarati; michael@0: case kRangeGurmukhi: return eFontPrefLang_Gurmukhi; michael@0: case kRangeKhmer: return eFontPrefLang_Khmer; michael@0: case kRangeMalayalam: return eFontPrefLang_Malayalam; michael@0: case kRangeOriya: return eFontPrefLang_Oriya; michael@0: case kRangeTelugu: return eFontPrefLang_Telugu; michael@0: case kRangeKannada: return eFontPrefLang_Kannada; michael@0: case kRangeSinhala: return eFontPrefLang_Sinhala; michael@0: case kRangeTibetan: return eFontPrefLang_Tibetan; michael@0: case kRangeSetCJK: return eFontPrefLang_CJKSet; michael@0: default: return eFontPrefLang_Others; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::IsLangCJK(eFontPrefLang aLang) michael@0: { michael@0: switch (aLang) { michael@0: case eFontPrefLang_Japanese: michael@0: case eFontPrefLang_ChineseTW: michael@0: case eFontPrefLang_ChineseCN: michael@0: case eFontPrefLang_ChineseHK: michael@0: case eFontPrefLang_Korean: michael@0: case eFontPrefLang_CJKSet: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: mozilla::layers::DiagnosticTypes michael@0: gfxPlatform::GetLayerDiagnosticTypes() michael@0: { michael@0: mozilla::layers::DiagnosticTypes type = DIAGNOSTIC_NONE; michael@0: if (gfxPrefs::DrawLayerBorders()) { michael@0: type |= mozilla::layers::DIAGNOSTIC_LAYER_BORDERS; michael@0: } michael@0: if (gfxPrefs::DrawTileBorders()) { michael@0: type |= mozilla::layers::DIAGNOSTIC_TILE_BORDERS; michael@0: } michael@0: if (gfxPrefs::DrawBigImageBorders()) { michael@0: type |= mozilla::layers::DIAGNOSTIC_BIGIMAGE_BORDERS; michael@0: } michael@0: if (gfxPrefs::FlashLayerBorders()) { michael@0: type |= mozilla::layers::DIAGNOSTIC_FLASH_BORDERS; michael@0: } michael@0: return type; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) michael@0: { michael@0: if (IsLangCJK(aCharLang)) { michael@0: AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang); michael@0: } else { michael@0: AppendPrefLang(aPrefLangs, aLen, aCharLang); michael@0: } michael@0: michael@0: AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others); michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) michael@0: { michael@0: // prefer the lang specified by the page *if* CJK michael@0: if (IsLangCJK(aPageLang)) { michael@0: AppendPrefLang(aPrefLangs, aLen, aPageLang); michael@0: } michael@0: michael@0: // if not set up, set up the default CJK order, based on accept lang settings and locale michael@0: if (mCJKPrefLangs.Length() == 0) { michael@0: michael@0: // temp array michael@0: eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; michael@0: uint32_t tempLen = 0; michael@0: michael@0: // Add the CJK pref fonts from accept languages, the order should be same order michael@0: nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages"); michael@0: if (!list.IsEmpty()) { michael@0: const char kComma = ','; michael@0: const char *p, *p_end; michael@0: list.BeginReading(p); michael@0: list.EndReading(p_end); michael@0: while (p < p_end) { michael@0: while (nsCRT::IsAsciiSpace(*p)) { michael@0: if (++p == p_end) michael@0: break; michael@0: } michael@0: if (p == p_end) michael@0: break; michael@0: const char *start = p; michael@0: while (++p != p_end && *p != kComma) michael@0: /* nothing */ ; michael@0: nsAutoCString lang(Substring(start, p)); michael@0: lang.CompressWhitespace(false, true); michael@0: eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get()); michael@0: switch (fpl) { michael@0: case eFontPrefLang_Japanese: michael@0: case eFontPrefLang_Korean: michael@0: case eFontPrefLang_ChineseCN: michael@0: case eFontPrefLang_ChineseHK: michael@0: case eFontPrefLang_ChineseTW: michael@0: AppendPrefLang(tempPrefLangs, tempLen, fpl); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: p++; michael@0: } michael@0: } michael@0: michael@0: do { // to allow 'break' to abort this block if a call fails michael@0: nsresult rv; michael@0: nsCOMPtr ls = michael@0: do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) michael@0: break; michael@0: michael@0: nsCOMPtr appLocale; michael@0: rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); michael@0: if (NS_FAILED(rv)) michael@0: break; michael@0: michael@0: nsString localeStr; michael@0: rv = appLocale-> michael@0: GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); michael@0: if (NS_FAILED(rv)) michael@0: break; michael@0: michael@0: const nsAString& lang = Substring(localeStr, 0, 2); michael@0: if (lang.EqualsLiteral("ja")) { michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); michael@0: } else if (lang.EqualsLiteral("zh")) { michael@0: const nsAString& region = Substring(localeStr, 3, 2); michael@0: if (region.EqualsLiteral("CN")) { michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); michael@0: } else if (region.EqualsLiteral("TW")) { michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); michael@0: } else if (region.EqualsLiteral("HK")) { michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); michael@0: } michael@0: } else if (lang.EqualsLiteral("ko")) { michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); michael@0: } michael@0: } while (0); michael@0: michael@0: // last resort... (the order is same as old gfx.) michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); michael@0: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); michael@0: michael@0: // copy into the cached array michael@0: uint32_t j; michael@0: for (j = 0; j < tempLen; j++) { michael@0: mCJKPrefLangs.AppendElement(tempPrefLangs[j]); michael@0: } michael@0: } michael@0: michael@0: // append in cached CJK langs michael@0: uint32_t i, numCJKlangs = mCJKPrefLangs.Length(); michael@0: michael@0: for (i = 0; i < numCJKlangs; i++) { michael@0: AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i])); michael@0: } michael@0: michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang) michael@0: { michael@0: if (aLen >= kMaxLenPrefLangList) return; michael@0: michael@0: // make sure michael@0: uint32_t i = 0; michael@0: while (i < aLen && aPrefLangs[i] != aAddLang) { michael@0: i++; michael@0: } michael@0: michael@0: if (i == aLen) { michael@0: aPrefLangs[aLen] = aAddLang; michael@0: aLen++; michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault, michael@0: uint32_t aContentBitmask, BackendType aContentDefault) michael@0: { michael@0: mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask); michael@0: if (mPreferredCanvasBackend == BackendType::NONE) { michael@0: mPreferredCanvasBackend = aCanvasDefault; michael@0: } michael@0: mFallbackCanvasBackend = michael@0: GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend)); michael@0: michael@0: mContentBackendBitmask = aContentBitmask; michael@0: mContentBackend = GetContentBackendPref(mContentBackendBitmask); michael@0: if (mContentBackend == BackendType::NONE) { michael@0: mContentBackend = aContentDefault; michael@0: // mContentBackendBitmask is our canonical reference for supported michael@0: // backends so we need to add the default if we are using it and michael@0: // overriding the prefs. michael@0: mContentBackendBitmask |= BackendTypeBit(aContentDefault); michael@0: } michael@0: } michael@0: michael@0: /* static */ BackendType michael@0: gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) michael@0: { michael@0: return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask); michael@0: } michael@0: michael@0: /* static */ BackendType michael@0: gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask) michael@0: { michael@0: return GetBackendPref("gfx.content.azure.backends", aBackendBitmask); michael@0: } michael@0: michael@0: /* static */ BackendType michael@0: gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask) michael@0: { michael@0: nsTArray backendList; michael@0: nsCString prefString; michael@0: if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) { michael@0: ParseString(prefString, ',', backendList); michael@0: } michael@0: michael@0: uint32_t allowedBackends = 0; michael@0: BackendType result = BackendType::NONE; michael@0: for (uint32_t i = 0; i < backendList.Length(); ++i) { michael@0: BackendType type = BackendTypeForName(backendList[i]); michael@0: if (BackendTypeBit(type) & aBackendBitmask) { michael@0: allowedBackends |= BackendTypeBit(type); michael@0: if (result == BackendType::NONE) { michael@0: result = type; michael@0: } michael@0: } michael@0: } michael@0: michael@0: aBackendBitmask = allowedBackends; michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::OffMainThreadCompositingEnabled() michael@0: { michael@0: return XRE_GetProcessType() == GeckoProcessType_Default ? michael@0: CompositorParent::CompositorLoop() != nullptr : michael@0: CompositorChild::ChildProcessHasCompositor(); michael@0: } michael@0: michael@0: eCMSMode michael@0: gfxPlatform::GetCMSMode() michael@0: { michael@0: if (gCMSInitialized == false) { michael@0: gCMSInitialized = true; michael@0: michael@0: int32_t mode = gfxPrefs::CMSMode(); michael@0: if (mode >= 0 && mode < eCMSMode_AllCount) { michael@0: gCMSMode = static_cast(mode); michael@0: } michael@0: michael@0: bool enableV4 = gfxPrefs::CMSEnableV4(); michael@0: if (enableV4) { michael@0: qcms_enable_iccv4(); michael@0: } michael@0: } michael@0: return gCMSMode; michael@0: } michael@0: michael@0: int michael@0: gfxPlatform::GetRenderingIntent() michael@0: { michael@0: if (!gCMSIntentInitialized) { michael@0: gCMSIntentInitialized = true; michael@0: michael@0: // gfxPrefs.h is using 0 as the default for the rendering michael@0: // intent preference, based on that being the value for michael@0: // QCMS_INTENT_DEFAULT. Assert here to catch if that ever michael@0: // changes and we can then figure out what to do about it. michael@0: MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0); michael@0: michael@0: /* Try to query the pref system for a rendering intent. */ michael@0: int32_t pIntent = gfxPrefs::CMSRenderingIntent(); michael@0: if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) { michael@0: gCMSIntent = pIntent; michael@0: } else { michael@0: /* If the pref is out of range, use embedded profile. */ michael@0: gCMSIntent = -1; michael@0: } michael@0: } michael@0: return gCMSIntent; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform) michael@0: { michael@0: michael@0: if (transform) { michael@0: /* we want the bytes in RGB order */ michael@0: #ifdef IS_LITTLE_ENDIAN michael@0: /* ABGR puts the bytes in |RGBA| order on little endian */ michael@0: uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR); michael@0: qcms_transform_data(transform, michael@0: (uint8_t *)&packed, (uint8_t *)&packed, michael@0: 1); michael@0: out.~gfxRGBA(); michael@0: new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR); michael@0: #else michael@0: /* ARGB puts the bytes in |ARGB| order on big endian */ michael@0: uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB); michael@0: /* add one to move past the alpha byte */ michael@0: qcms_transform_data(transform, michael@0: (uint8_t *)&packed + 1, (uint8_t *)&packed + 1, michael@0: 1); michael@0: out.~gfxRGBA(); michael@0: new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB); michael@0: #endif michael@0: } michael@0: michael@0: else if (&out != &in) michael@0: out = in; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size) michael@0: { michael@0: mem = nullptr; michael@0: size = 0; michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size) michael@0: { michael@0: nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile"); michael@0: if (!fname.IsEmpty()) { michael@0: qcms_data_from_path(fname, &mem, &size); michael@0: } michael@0: else { michael@0: gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size); michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::CreateCMSOutputProfile() michael@0: { michael@0: if (!gCMSOutputProfile) { michael@0: /* Determine if we're using the internal override to force sRGB as michael@0: an output profile for reftests. See Bug 452125. michael@0: michael@0: Note that we don't normally (outside of tests) set a michael@0: default value of this preference, which means nsIPrefBranch::GetBoolPref michael@0: will typically throw (and leave its out-param untouched). michael@0: */ michael@0: if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) { michael@0: gCMSOutputProfile = GetCMSsRGBProfile(); michael@0: } michael@0: michael@0: if (!gCMSOutputProfile) { michael@0: void* mem = nullptr; michael@0: size_t size = 0; michael@0: michael@0: GetCMSOutputProfileData(mem, size); michael@0: if ((mem != nullptr) && (size > 0)) { michael@0: gCMSOutputProfile = qcms_profile_from_memory(mem, size); michael@0: free(mem); michael@0: } michael@0: } michael@0: michael@0: /* Determine if the profile looks bogus. If so, close the profile michael@0: * and use sRGB instead. See bug 460629, */ michael@0: if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) { michael@0: NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(), michael@0: "Builtin sRGB profile tagged as bogus!!!"); michael@0: qcms_profile_release(gCMSOutputProfile); michael@0: gCMSOutputProfile = nullptr; michael@0: } michael@0: michael@0: if (!gCMSOutputProfile) { michael@0: gCMSOutputProfile = GetCMSsRGBProfile(); michael@0: } michael@0: /* Precache the LUT16 Interpolations for the output profile. See michael@0: bug 444661 for details. */ michael@0: qcms_profile_precache_output_transform(gCMSOutputProfile); michael@0: } michael@0: } michael@0: michael@0: qcms_profile * michael@0: gfxPlatform::GetCMSOutputProfile() michael@0: { michael@0: return gCMSOutputProfile; michael@0: } michael@0: michael@0: qcms_profile * michael@0: gfxPlatform::GetCMSsRGBProfile() michael@0: { michael@0: if (!gCMSsRGBProfile) { michael@0: michael@0: /* Create the profile using qcms. */ michael@0: gCMSsRGBProfile = qcms_profile_sRGB(); michael@0: } michael@0: return gCMSsRGBProfile; michael@0: } michael@0: michael@0: qcms_transform * michael@0: gfxPlatform::GetCMSRGBTransform() michael@0: { michael@0: if (!gCMSRGBTransform) { michael@0: qcms_profile *inProfile, *outProfile; michael@0: outProfile = GetCMSOutputProfile(); michael@0: inProfile = GetCMSsRGBProfile(); michael@0: michael@0: if (!inProfile || !outProfile) michael@0: return nullptr; michael@0: michael@0: gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8, michael@0: outProfile, QCMS_DATA_RGB_8, michael@0: QCMS_INTENT_PERCEPTUAL); michael@0: } michael@0: michael@0: return gCMSRGBTransform; michael@0: } michael@0: michael@0: qcms_transform * michael@0: gfxPlatform::GetCMSInverseRGBTransform() michael@0: { michael@0: if (!gCMSInverseRGBTransform) { michael@0: qcms_profile *inProfile, *outProfile; michael@0: inProfile = GetCMSOutputProfile(); michael@0: outProfile = GetCMSsRGBProfile(); michael@0: michael@0: if (!inProfile || !outProfile) michael@0: return nullptr; michael@0: michael@0: gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8, michael@0: outProfile, QCMS_DATA_RGB_8, michael@0: QCMS_INTENT_PERCEPTUAL); michael@0: } michael@0: michael@0: return gCMSInverseRGBTransform; michael@0: } michael@0: michael@0: qcms_transform * michael@0: gfxPlatform::GetCMSRGBATransform() michael@0: { michael@0: if (!gCMSRGBATransform) { michael@0: qcms_profile *inProfile, *outProfile; michael@0: outProfile = GetCMSOutputProfile(); michael@0: inProfile = GetCMSsRGBProfile(); michael@0: michael@0: if (!inProfile || !outProfile) michael@0: return nullptr; michael@0: michael@0: gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8, michael@0: outProfile, QCMS_DATA_RGBA_8, michael@0: QCMS_INTENT_PERCEPTUAL); michael@0: } michael@0: michael@0: return gCMSRGBATransform; michael@0: } michael@0: michael@0: /* Shuts down various transforms and profiles for CMS. */ michael@0: static void ShutdownCMS() michael@0: { michael@0: michael@0: if (gCMSRGBTransform) { michael@0: qcms_transform_release(gCMSRGBTransform); michael@0: gCMSRGBTransform = nullptr; michael@0: } michael@0: if (gCMSInverseRGBTransform) { michael@0: qcms_transform_release(gCMSInverseRGBTransform); michael@0: gCMSInverseRGBTransform = nullptr; michael@0: } michael@0: if (gCMSRGBATransform) { michael@0: qcms_transform_release(gCMSRGBATransform); michael@0: gCMSRGBATransform = nullptr; michael@0: } michael@0: if (gCMSOutputProfile) { michael@0: qcms_profile_release(gCMSOutputProfile); michael@0: michael@0: // handle the aliased case michael@0: if (gCMSsRGBProfile == gCMSOutputProfile) michael@0: gCMSsRGBProfile = nullptr; michael@0: gCMSOutputProfile = nullptr; michael@0: } michael@0: if (gCMSsRGBProfile) { michael@0: qcms_profile_release(gCMSsRGBProfile); michael@0: gCMSsRGBProfile = nullptr; michael@0: } michael@0: michael@0: // Reset the state variables michael@0: gCMSIntent = -2; michael@0: gCMSMode = eCMSMode_Off; michael@0: gCMSInitialized = false; michael@0: } michael@0: michael@0: // default SetupClusterBoundaries, based on Unicode properties; michael@0: // platform subclasses may override if they wish michael@0: void michael@0: gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString) michael@0: { michael@0: if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) { michael@0: // 8-bit text doesn't have clusters. michael@0: // XXX is this true in all languages??? michael@0: // behdad: don't think so. Czech for example IIRC has a michael@0: // 'ch' grapheme. michael@0: // jfkthame: but that's not expected to behave as a grapheme cluster michael@0: // for selection/editing/etc. michael@0: return; michael@0: } michael@0: michael@0: aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength()); michael@0: } michael@0: michael@0: int32_t michael@0: gfxPlatform::GetBidiNumeralOption() michael@0: { michael@0: if (mBidiNumeralOption == UNINITIALIZED_VALUE) { michael@0: mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0); michael@0: } michael@0: return mBidiNumeralOption; michael@0: } michael@0: michael@0: static void michael@0: FlushFontAndWordCaches() michael@0: { michael@0: gfxFontCache *fontCache = gfxFontCache::GetCache(); michael@0: if (fontCache) { michael@0: fontCache->AgeAllGenerations(); michael@0: fontCache->FlushShapedWordCaches(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::FontsPrefsChanged(const char *aPref) michael@0: { michael@0: NS_ASSERTION(aPref != nullptr, "null preference"); michael@0: if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) { michael@0: mAllowDownloadableFonts = UNINITIALIZED_VALUE; michael@0: } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) { michael@0: mFallbackUsesCmaps = UNINITIALIZED_VALUE; michael@0: } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) { michael@0: mWordCacheCharLimit = UNINITIALIZED_VALUE; michael@0: FlushFontAndWordCaches(); michael@0: } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) { michael@0: mWordCacheMaxEntries = UNINITIALIZED_VALUE; michael@0: FlushFontAndWordCaches(); michael@0: } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) { michael@0: mGraphiteShapingEnabled = UNINITIALIZED_VALUE; michael@0: FlushFontAndWordCaches(); michael@0: } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) { michael@0: mUseHarfBuzzScripts = UNINITIALIZED_VALUE; michael@0: FlushFontAndWordCaches(); michael@0: } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) { michael@0: mBidiNumeralOption = UNINITIALIZED_VALUE; michael@0: } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) { michael@0: mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; michael@0: gfxFontCache::GetCache()->AgeAllGenerations(); michael@0: } michael@0: } michael@0: michael@0: michael@0: PRLogModuleInfo* michael@0: gfxPlatform::GetLog(eGfxLog aWhichLog) michael@0: { michael@0: // logs shared across gfx michael@0: #ifdef PR_LOGGING michael@0: static PRLogModuleInfo *sFontlistLog = nullptr; michael@0: static PRLogModuleInfo *sFontInitLog = nullptr; michael@0: static PRLogModuleInfo *sTextrunLog = nullptr; michael@0: static PRLogModuleInfo *sTextrunuiLog = nullptr; michael@0: static PRLogModuleInfo *sCmapDataLog = nullptr; michael@0: static PRLogModuleInfo *sTextPerfLog = nullptr; michael@0: michael@0: // Assume that if one is initialized, all are initialized michael@0: if (!sFontlistLog) { michael@0: sFontlistLog = PR_NewLogModule("fontlist"); michael@0: sFontInitLog = PR_NewLogModule("fontinit"); michael@0: sTextrunLog = PR_NewLogModule("textrun"); michael@0: sTextrunuiLog = PR_NewLogModule("textrunui"); michael@0: sCmapDataLog = PR_NewLogModule("cmapdata"); michael@0: sTextPerfLog = PR_NewLogModule("textperf"); michael@0: } michael@0: michael@0: switch (aWhichLog) { michael@0: case eGfxLog_fontlist: michael@0: return sFontlistLog; michael@0: break; michael@0: case eGfxLog_fontinit: michael@0: return sFontInitLog; michael@0: break; michael@0: case eGfxLog_textrun: michael@0: return sTextrunLog; michael@0: break; michael@0: case eGfxLog_textrunui: michael@0: return sTextrunuiLog; michael@0: break; michael@0: case eGfxLog_cmapdata: michael@0: return sCmapDataLog; michael@0: break; michael@0: case eGfxLog_textperf: michael@0: return sTextPerfLog; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: return nullptr; michael@0: #else michael@0: return nullptr; michael@0: #endif michael@0: } michael@0: michael@0: int michael@0: gfxPlatform::GetScreenDepth() const michael@0: { michael@0: NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!"); michael@0: return 0; michael@0: } michael@0: michael@0: mozilla::gfx::SurfaceFormat michael@0: gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent) michael@0: { michael@0: switch (aContent) { michael@0: case gfxContentType::COLOR: michael@0: switch (GetOffscreenFormat()) { michael@0: case gfxImageFormat::ARGB32: michael@0: return mozilla::gfx::SurfaceFormat::B8G8R8A8; michael@0: case gfxImageFormat::RGB24: michael@0: return mozilla::gfx::SurfaceFormat::B8G8R8X8; michael@0: case gfxImageFormat::RGB16_565: michael@0: return mozilla::gfx::SurfaceFormat::R5G6B5; michael@0: default: michael@0: NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR"); michael@0: return mozilla::gfx::SurfaceFormat::B8G8R8A8; michael@0: } michael@0: case gfxContentType::ALPHA: michael@0: return mozilla::gfx::SurfaceFormat::A8; michael@0: case gfxContentType::COLOR_ALPHA: michael@0: return mozilla::gfx::SurfaceFormat::B8G8R8A8; michael@0: default: michael@0: NS_NOTREACHED("unknown gfxContentType"); michael@0: return mozilla::gfx::SurfaceFormat::B8G8R8A8; michael@0: } michael@0: } michael@0: michael@0: gfxImageFormat michael@0: gfxPlatform::OptimalFormatForContent(gfxContentType aContent) michael@0: { michael@0: switch (aContent) { michael@0: case gfxContentType::COLOR: michael@0: return GetOffscreenFormat(); michael@0: case gfxContentType::ALPHA: michael@0: return gfxImageFormat::A8; michael@0: case gfxContentType::COLOR_ALPHA: michael@0: return gfxImageFormat::ARGB32; michael@0: default: michael@0: NS_NOTREACHED("unknown gfxContentType"); michael@0: return gfxImageFormat::ARGB32; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * There are a number of layers acceleration (or layers in general) preferences michael@0: * that should be consistent for the lifetime of the application (bug 840967). michael@0: * As such, we will evaluate them all as soon as one of them is evaluated michael@0: * and remember the values. Changing these preferences during the run will michael@0: * not have any effect until we restart. michael@0: */ michael@0: static bool sLayersSupportsD3D9 = false; michael@0: static bool sBufferRotationCheckPref = true; michael@0: static bool sPrefBrowserTabsRemoteAutostart = false; michael@0: michael@0: static bool sLayersAccelerationPrefsInitialized = false; michael@0: michael@0: void michael@0: InitLayersAccelerationPrefs() michael@0: { michael@0: if (!sLayersAccelerationPrefsInitialized) michael@0: { michael@0: // If this is called for the first time on a non-main thread, we're screwed. michael@0: // At the moment there's no explicit guarantee that the main thread calls michael@0: // this before the compositor thread, but let's at least make the assumption michael@0: // explicit. michael@0: MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread"); michael@0: michael@0: sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false); michael@0: michael@0: #ifdef XP_WIN michael@0: if (gfxPrefs::LayersAccelerationForceEnabled()) { michael@0: sLayersSupportsD3D9 = true; michael@0: } else { michael@0: nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); michael@0: if (gfxInfo) { michael@0: int32_t status; michael@0: if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) { michael@0: if (status == nsIGfxInfo::FEATURE_NO_INFO) { michael@0: sLayersSupportsD3D9 = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: sLayersAccelerationPrefsInitialized = true; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled() michael@0: { michael@0: InitLayersAccelerationPrefs(); michael@0: return gfxPrefs::LayersOffMainThreadCompositionEnabled() || michael@0: gfxPrefs::LayersOffMainThreadCompositionForceEnabled() || michael@0: gfxPrefs::LayersOffMainThreadCompositionTestingEnabled(); michael@0: } michael@0: michael@0: bool gfxPlatform::OffMainThreadCompositionRequired() michael@0: { michael@0: InitLayersAccelerationPrefs(); michael@0: #if defined(MOZ_WIDGET_GTK) && defined(NIGHTLY_BUILD) michael@0: // Linux users who chose OpenGL are being grandfathered in to OMTC michael@0: return sPrefBrowserTabsRemoteAutostart || michael@0: gfxPrefs::LayersAccelerationForceEnabled(); michael@0: #else michael@0: return sPrefBrowserTabsRemoteAutostart; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::CanUseDirect3D9() michael@0: { michael@0: // this function is called from the compositor thread, so it is not michael@0: // safe to init the prefs etc. from here. michael@0: MOZ_ASSERT(sLayersAccelerationPrefsInitialized); michael@0: return sLayersSupportsD3D9; michael@0: } michael@0: michael@0: bool michael@0: gfxPlatform::BufferRotationEnabled() michael@0: { michael@0: MutexAutoLock autoLock(*gGfxPlatformPrefsLock); michael@0: michael@0: return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled(); michael@0: } michael@0: michael@0: void michael@0: gfxPlatform::DisableBufferRotation() michael@0: { michael@0: MutexAutoLock autoLock(*gGfxPlatformPrefsLock); michael@0: michael@0: sBufferRotationCheckPref = false; michael@0: } michael@0: michael@0: TemporaryRef michael@0: gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont) michael@0: { michael@0: NativeFont nativeFont; michael@0: if (aTarget->GetType() == BackendType::CAIRO || aTarget->GetType() == BackendType::SKIA) { michael@0: nativeFont.mType = NativeFontType::CAIRO_FONT_FACE; michael@0: nativeFont.mFont = aFont->GetCairoScaledFont(); michael@0: return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); michael@0: } michael@0: michael@0: return nullptr; michael@0: }