gfx/thebes/gfxPlatform.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifdef MOZ_LOGGING
     7 #define FORCE_PR_LOG /* Allow logging in the release build */
     8 #endif
    10 #include "mozilla/layers/CompositorChild.h"
    11 #include "mozilla/layers/CompositorParent.h"
    12 #include "mozilla/layers/ImageBridgeChild.h"
    13 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
    15 #include "prlog.h"
    17 #include "gfxPlatform.h"
    18 #include "gfxPrefs.h"
    20 #ifdef XP_WIN
    21 #include <process.h>
    22 #define getpid _getpid
    23 #else
    24 #include <unistd.h>
    25 #endif
    27 #include "nsXULAppAPI.h"
    28 #include "nsDirectoryServiceUtils.h"
    29 #include "nsDirectoryServiceDefs.h"
    31 #if defined(XP_WIN)
    32 #include "gfxWindowsPlatform.h"
    33 #include "gfxD2DSurface.h"
    34 #elif defined(XP_MACOSX)
    35 #include "gfxPlatformMac.h"
    36 #include "gfxQuartzSurface.h"
    37 #elif defined(MOZ_WIDGET_GTK)
    38 #include "gfxPlatformGtk.h"
    39 #elif defined(MOZ_WIDGET_QT)
    40 #include "gfxQtPlatform.h"
    41 #elif defined(ANDROID)
    42 #include "gfxAndroidPlatform.h"
    43 #endif
    45 #include "nsGkAtoms.h"
    46 #include "gfxPlatformFontList.h"
    47 #include "gfxContext.h"
    48 #include "gfxImageSurface.h"
    49 #include "nsUnicodeProperties.h"
    50 #include "harfbuzz/hb.h"
    51 #include "gfxGraphiteShaper.h"
    52 #include "gfx2DGlue.h"
    53 #include "gfxGradientCache.h"
    55 #include "nsUnicodeRange.h"
    56 #include "nsServiceManagerUtils.h"
    57 #include "nsTArray.h"
    58 #include "nsILocaleService.h"
    59 #include "nsIObserverService.h"
    60 #include "MainThreadUtils.h"
    62 #include "nsWeakReference.h"
    64 #include "cairo.h"
    65 #include "qcms.h"
    67 #include "plstr.h"
    68 #include "nsCRT.h"
    69 #include "GLContext.h"
    70 #include "GLContextProvider.h"
    72 #ifdef MOZ_WIDGET_ANDROID
    73 #include "TexturePoolOGL.h"
    74 #endif
    76 #include "mozilla/Hal.h"
    77 #ifdef USE_SKIA
    78 #include "skia/SkGraphics.h"
    80 #include "SkiaGLGlue.h"
    81 #else
    82 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
    83 };
    84 #endif
    86 #include "mozilla/Preferences.h"
    87 #include "mozilla/Assertions.h"
    88 #include "mozilla/Attributes.h"
    89 #include "mozilla/Mutex.h"
    91 #include "nsIGfxInfo.h"
    92 #include "nsIXULRuntime.h"
    94 #ifdef MOZ_WIDGET_GONK
    95 namespace mozilla {
    96 namespace layers {
    97 void InitGralloc();
    98 }
    99 }
   100 #endif
   102 using namespace mozilla;
   103 using namespace mozilla::layers;
   105 gfxPlatform *gPlatform = nullptr;
   106 static bool gEverInitialized = false;
   108 static Mutex* gGfxPlatformPrefsLock = nullptr;
   110 // These two may point to the same profile
   111 static qcms_profile *gCMSOutputProfile = nullptr;
   112 static qcms_profile *gCMSsRGBProfile = nullptr;
   114 static qcms_transform *gCMSRGBTransform = nullptr;
   115 static qcms_transform *gCMSInverseRGBTransform = nullptr;
   116 static qcms_transform *gCMSRGBATransform = nullptr;
   118 static bool gCMSInitialized = false;
   119 static eCMSMode gCMSMode = eCMSMode_Off;
   121 static bool gCMSIntentInitialized = false;
   122 static int gCMSIntent = QCMS_INTENT_DEFAULT;
   125 static void ShutdownCMS();
   127 #include "mozilla/gfx/2D.h"
   128 using namespace mozilla::gfx;
   130 /* Class to listen for pref changes so that chrome code can dynamically
   131    force sRGB as an output profile. See Bug #452125. */
   132 class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
   133                                        public nsSupportsWeakReference
   134 {
   135 public:
   136     NS_DECL_ISUPPORTS
   137     NS_DECL_NSIOBSERVER
   138 };
   140 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
   142 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
   144 #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
   145 #define HARFBUZZ_SCRIPTS_DEFAULT  mozilla::unicode::SHAPING_DEFAULT
   146 #define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
   148 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
   150 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
   151 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
   153 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
   155 #define BIDI_NUMERAL_PREF "bidi.numeral"
   157 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
   159 NS_IMETHODIMP
   160 SRGBOverrideObserver::Observe(nsISupports *aSubject,
   161                               const char *aTopic,
   162                               const char16_t* someData)
   163 {
   164     NS_ASSERTION(NS_strcmp(someData,
   165                            MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0,
   166                  "Restarting CMS on wrong pref!");
   167     ShutdownCMS();
   168     return NS_OK;
   169 }
   171 static const char* kObservedPrefs[] = {
   172     "gfx.downloadable_fonts.",
   173     "gfx.font_rendering.",
   174     BIDI_NUMERAL_PREF,
   175     nullptr
   176 };
   178 class FontPrefsObserver MOZ_FINAL : public nsIObserver
   179 {
   180 public:
   181     NS_DECL_ISUPPORTS
   182     NS_DECL_NSIOBSERVER
   183 };
   185 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
   187 NS_IMETHODIMP
   188 FontPrefsObserver::Observe(nsISupports *aSubject,
   189                            const char *aTopic,
   190                            const char16_t *someData)
   191 {
   192     if (!someData) {
   193         NS_ERROR("font pref observer code broken");
   194         return NS_ERROR_UNEXPECTED;
   195     }
   196     NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
   197     gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
   199     return NS_OK;
   200 }
   202 class MemoryPressureObserver MOZ_FINAL : public nsIObserver
   203 {
   204 public:
   205     NS_DECL_ISUPPORTS
   206     NS_DECL_NSIOBSERVER
   207 };
   209 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
   211 NS_IMETHODIMP
   212 MemoryPressureObserver::Observe(nsISupports *aSubject,
   213                                 const char *aTopic,
   214                                 const char16_t *someData)
   215 {
   216     NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
   217     Factory::PurgeAllCaches();
   219     gfxPlatform::GetPlatform()->PurgeSkiaCache();
   220     return NS_OK;
   221 }
   223 // this needs to match the list of pref font.default.xx entries listed in all.js!
   224 // the order *must* match the order in eFontPrefLang
   225 static const char *gPrefLangNames[] = {
   226     "x-western",
   227     "x-central-euro",
   228     "ja",
   229     "zh-TW",
   230     "zh-CN",
   231     "zh-HK",
   232     "ko",
   233     "x-cyrillic",
   234     "x-baltic",
   235     "el",
   236     "tr",
   237     "th",
   238     "he",
   239     "ar",
   240     "x-devanagari",
   241     "x-tamil",
   242     "x-armn",
   243     "x-beng",
   244     "x-cans",
   245     "x-ethi",
   246     "x-geor",
   247     "x-gujr",
   248     "x-guru",
   249     "x-khmr",
   250     "x-mlym",
   251     "x-orya",
   252     "x-telu",
   253     "x-knda",
   254     "x-sinh",
   255     "x-tibt",
   256     "x-unicode",
   257 };
   259 gfxPlatform::gfxPlatform()
   260   : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
   261                                  &gfxPlatform::GetAzureBackendInfo)
   262 {
   263     mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
   264     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
   265     mFallbackUsesCmaps = UNINITIALIZED_VALUE;
   267     mWordCacheCharLimit = UNINITIALIZED_VALUE;
   268     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
   269     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
   270     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
   271     mBidiNumeralOption = UNINITIALIZED_VALUE;
   273     mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default;
   275     mSkiaGlue = nullptr;
   277     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
   278     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
   279     InitBackendPrefs(canvasMask, BackendType::CAIRO,
   280                      contentMask, BackendType::CAIRO);
   281 }
   283 gfxPlatform*
   284 gfxPlatform::GetPlatform()
   285 {
   286     if (!gPlatform) {
   287         Init();
   288     }
   289     return gPlatform;
   290 }
   292 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
   293 {
   294   if (Preferences::GetBool("gfx.2d.recording", false)) {
   295     nsAutoCString fileName;
   296     nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
   298     if (prefFileName) {
   299       fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
   300     } else {
   301       nsCOMPtr<nsIFile> tmpFile;
   302       if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
   303         return;
   304       }
   305       fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
   307       nsresult rv = tmpFile->AppendNative(fileName);
   308       if (NS_FAILED(rv))
   309         return;
   311       rv = tmpFile->GetNativePath(fileName);
   312       if (NS_FAILED(rv))
   313         return;
   314     }
   316     gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
   317     printf_stderr("Recording to %s\n", fileName.get());
   318     Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
   319   } else {
   320     Factory::SetGlobalEventRecorder(nullptr);
   321   }
   322 }
   324 void
   325 gfxPlatform::Init()
   326 {
   327     if (gEverInitialized) {
   328         NS_RUNTIMEABORT("Already started???");
   329     }
   330     gEverInitialized = true;
   332     // Initialize the preferences by creating the singleton.
   333     gfxPrefs::GetSingleton();
   335     gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
   337     /* Initialize the GfxInfo service.
   338      * Note: we can't call functions on GfxInfo that depend
   339      * on gPlatform until after it has been initialized
   340      * below. GfxInfo initialization annotates our
   341      * crash reports so we want to do it before
   342      * we try to load any drivers and do device detection
   343      * incase that code crashes. See bug #591561. */
   344     nsCOMPtr<nsIGfxInfo> gfxInfo;
   345     /* this currently will only succeed on Windows */
   346     gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   348 #if defined(XP_WIN)
   349     gPlatform = new gfxWindowsPlatform;
   350 #elif defined(XP_MACOSX)
   351     gPlatform = new gfxPlatformMac;
   352 #elif defined(MOZ_WIDGET_GTK)
   353     gPlatform = new gfxPlatformGtk;
   354 #elif defined(MOZ_WIDGET_QT)
   355     gPlatform = new gfxQtPlatform;
   356 #elif defined(ANDROID)
   357     gPlatform = new gfxAndroidPlatform;
   358 #else
   359     #error "No gfxPlatform implementation available"
   360 #endif
   362 #ifdef DEBUG
   363     mozilla::gl::GLContext::StaticInit();
   364 #endif
   366     bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
   367                                        GetPrefLayersOffMainThreadCompositionEnabled();
   369     if (!OffMainThreadCompositionRequired()) {
   370       useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
   371     }
   373     if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
   374         CompositorParent::StartUp();
   375         if (gfxPrefs::AsyncVideoEnabled()) {
   376             ImageBridgeChild::StartUp();
   377         }
   378     }
   380     nsresult rv;
   382 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
   383     rv = gfxPlatformFontList::Init();
   384     if (NS_FAILED(rv)) {
   385         NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
   386     }
   387 #endif
   389     gPlatform->mScreenReferenceSurface =
   390         gPlatform->CreateOffscreenSurface(IntSize(1, 1),
   391                                           gfxContentType::COLOR_ALPHA);
   392     if (!gPlatform->mScreenReferenceSurface) {
   393         NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
   394     }
   396     gPlatform->mScreenReferenceDrawTarget =
   397         gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
   398                                                     SurfaceFormat::B8G8R8A8);
   399     if (!gPlatform->mScreenReferenceDrawTarget) {
   400       NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
   401     }
   403     rv = gfxFontCache::Init();
   404     if (NS_FAILED(rv)) {
   405         NS_RUNTIMEABORT("Could not initialize gfxFontCache");
   406     }
   408     /* Create and register our CMS Override observer. */
   409     gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
   410     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
   412     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
   413     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
   415     mozilla::gl::GLContext::PlatformStartup();
   417 #ifdef MOZ_WIDGET_ANDROID
   418     // Texture pool init
   419     mozilla::gl::TexturePoolOGL::Init();
   420 #endif
   422 #ifdef MOZ_WIDGET_GONK
   423     mozilla::layers::InitGralloc();
   424 #endif
   426     Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
   428     CreateCMSOutputProfile();
   430     // Listen to memory pressure event so we can purge DrawTarget caches
   431     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   432     if (obs) {
   433         gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
   434         obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
   435     }
   437     RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
   438 }
   440 void
   441 gfxPlatform::Shutdown()
   442 {
   443     // These may be called before the corresponding subsystems have actually
   444     // started up. That's OK, they can handle it.
   445     gfxFontCache::Shutdown();
   446     gfxFontGroup::Shutdown();
   447     gfxGradientCache::Shutdown();
   448     gfxGraphiteShaper::Shutdown();
   449 #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
   450     gfxPlatformFontList::Shutdown();
   451 #endif
   453     // Free the various non-null transforms and loaded profiles
   454     ShutdownCMS();
   456     // In some cases, gPlatform may not be created but Shutdown() called,
   457     // e.g., during xpcshell tests.
   458     if (gPlatform) {
   459         /* Unregister our CMS Override callback. */
   460         NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
   461         Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
   462         gPlatform->mSRGBOverrideObserver = nullptr;
   464         NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
   465         Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
   466         gPlatform->mFontPrefsObserver = nullptr;
   468         NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
   469         nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   470         if (obs) {
   471             obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
   472         }
   474         gPlatform->mMemoryPressureObserver = nullptr;
   475         gPlatform->mSkiaGlue = nullptr;
   476     }
   478 #ifdef MOZ_WIDGET_ANDROID
   479     // Shut down the texture pool
   480     mozilla::gl::TexturePoolOGL::Shutdown();
   481 #endif
   483     // Shut down the default GL context provider.
   484     mozilla::gl::GLContextProvider::Shutdown();
   486 #if defined(XP_WIN)
   487     // The above shutdown calls operate on the available context providers on
   488     // most platforms.  Windows is a "special snowflake", though, and has three
   489     // context providers available, so we have to shut all of them down.
   490     // We should only support the default GL provider on Windows; then, this
   491     // could go away. Unfortunately, we currently support WGL (the default) for
   492     // WebGL on Optimus.
   493     mozilla::gl::GLContextProviderEGL::Shutdown();
   494 #endif
   496     delete gGfxPlatformPrefsLock;
   498     gfxPrefs::DestroySingleton();
   499     gfxFont::DestroySingletons();
   501     delete gPlatform;
   502     gPlatform = nullptr;
   503 }
   505 gfxPlatform::~gfxPlatform()
   506 {
   507     mScreenReferenceSurface = nullptr;
   508     mScreenReferenceDrawTarget = nullptr;
   510     // The cairo folks think we should only clean up in debug builds,
   511     // but we're generally in the habit of trying to shut down as
   512     // cleanly as possible even in production code, so call this
   513     // cairo_debug_* function unconditionally.
   514     //
   515     // because cairo can assert and thus crash on shutdown, don't do this in release builds
   516 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND)
   517 #ifdef USE_SKIA
   518     // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
   519     // Cairo objects e.g. through SkCairoFTTypeface
   520     SkGraphics::Term();
   521 #endif
   523 #if MOZ_TREE_CAIRO
   524     cairo_debug_reset_static_data();
   525 #endif
   526 #endif
   527 }
   529 bool
   530 gfxPlatform::PreferMemoryOverShmem() const {
   531   MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
   532   return mLayersPreferMemoryOverShmem;
   533 }
   535 already_AddRefed<gfxASurface>
   536 gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
   537                                          gfxContentType aContentType)
   538 {
   539   nsRefPtr<gfxASurface> newSurface;
   540   newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
   542   return newSurface.forget();
   543 }
   545 already_AddRefed<gfxASurface>
   546 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
   547                            gfxImageFormat format)
   548 {
   549     IntSize surfaceSize = aSurface->GetSize().ToIntSize();
   551 #ifdef XP_WIN
   552     if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
   553         gfxWindowsPlatform::RENDER_DIRECT2D) {
   554         return nullptr;
   555     }
   556 #endif
   557     nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format));
   558     if (!optSurface || optSurface->CairoStatus() != 0)
   559         return nullptr;
   561     gfxContext tmpCtx(optSurface);
   562     tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
   563     tmpCtx.SetSource(aSurface);
   564     tmpCtx.Paint();
   566     return optSurface.forget();
   567 }
   569 cairo_user_data_key_t kDrawTarget;
   571 RefPtr<DrawTarget>
   572 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
   573 {
   574   SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType());
   575   RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
   576   aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
   577   return drawTarget;
   578 }
   580 // This is a temporary function used by ContentClient to build a DrawTarget
   581 // around the gfxASurface. This should eventually be replaced by plumbing
   582 // the DrawTarget through directly
   583 RefPtr<DrawTarget>
   584 gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize)
   585 {
   586 #ifdef XP_MACOSX
   587   // this is a bit of a hack that assumes that the buffer associated with the CGContext
   588   // will live around long enough that nothing bad will happen.
   589   if (aSurface->GetType() == gfxSurfaceType::Quartz) {
   590     return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
   591   }
   592 #endif
   593   MOZ_CRASH();
   594   return nullptr;
   595 }
   598 cairo_user_data_key_t kSourceSurface;
   600 /**
   601  * Record the backend that was used to construct the SourceSurface.
   602  * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
   603  * we check to make sure the DrawTarget's backend matches the backend
   604  * for the cached SourceSurface, and only use it if they match. This
   605  * can avoid expensive and unnecessary readbacks.
   606  */
   607 struct SourceSurfaceUserData
   608 {
   609   RefPtr<SourceSurface> mSrcSurface;
   610   BackendType mBackendType;
   611 };
   613 void SourceBufferDestroy(void *srcSurfUD)
   614 {
   615   delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
   616 }
   618 UserDataKey kThebesSurface;
   620 struct DependentSourceSurfaceUserData
   621 {
   622   nsRefPtr<gfxASurface> mSurface;
   623 };
   625 void SourceSurfaceDestroyed(void *aData)
   626 {
   627   delete static_cast<DependentSourceSurfaceUserData*>(aData);
   628 }
   630 #if MOZ_TREE_CAIRO
   631 void SourceSnapshotDetached(cairo_surface_t *nullSurf)
   632 {
   633   gfxImageSurface* origSurf =
   634     static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
   636   origSurf->SetData(&kSourceSurface, nullptr, nullptr);
   637 }
   638 #else
   639 void SourceSnapshotDetached(void *nullSurf)
   640 {
   641   gfxImageSurface* origSurf = static_cast<gfxImageSurface*>(nullSurf);
   642   origSurf->SetData(&kSourceSurface, nullptr, nullptr);
   643 }
   644 #endif
   646 void
   647 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
   648 {
   649   aSurface->SetData(&kSourceSurface, nullptr, nullptr);
   650 }
   652 static TemporaryRef<DataSourceSurface>
   653 CopySurface(gfxASurface* aSurface)
   654 {
   655   const nsIntSize size = aSurface->GetSize();
   656   gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
   657   RefPtr<DataSourceSurface> data =
   658     Factory::CreateDataSourceSurface(ToIntSize(size),
   659                                      ImageFormatToSurfaceFormat(format));
   660   if (!data) {
   661     return nullptr;
   662   }
   664   DataSourceSurface::MappedSurface map;
   665   DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
   666   MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
   668   nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
   669   nsRefPtr<gfxContext> ctx = new gfxContext(image);
   671   ctx->SetSource(aSurface);
   672   ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
   673   ctx->Paint();
   675   data->Unmap();
   677   return data;
   678 }
   680 RefPtr<SourceSurface>
   681 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
   682 {
   683   if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
   684     return nullptr;
   685   }
   687   if (!aTarget) {
   688     if (ScreenReferenceDrawTarget()) {
   689       aTarget = ScreenReferenceDrawTarget();
   690     } else {
   691       return nullptr;
   692     }
   693   }
   695   void *userData = aSurface->GetData(&kSourceSurface);
   697   if (userData) {
   698     SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
   700     if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetType()) {
   701       return surf->mSrcSurface;
   702     }
   703     // We can just continue here as when setting new user data the destroy
   704     // function will be called for the old user data.
   705   }
   707   SurfaceFormat format;
   708   if (aSurface->GetContentType() == gfxContentType::ALPHA) {
   709     format = SurfaceFormat::A8;
   710   } else if (aSurface->GetContentType() == gfxContentType::COLOR) {
   711     format = SurfaceFormat::B8G8R8X8;
   712   } else {
   713     format = SurfaceFormat::B8G8R8A8;
   714   }
   716   RefPtr<SourceSurface> srcBuffer;
   718 #ifdef XP_WIN
   719   if (aSurface->GetType() == gfxSurfaceType::D2D &&
   720       format != SurfaceFormat::A8) {
   721     NativeSurface surf;
   722     surf.mFormat = format;
   723     surf.mType = NativeSurfaceType::D3D10_TEXTURE;
   724     surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
   725     surf.mSize = ToIntSize(aSurface->GetSize());
   726     mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
   727     if (dt) {
   728       dt->Flush();
   729     }
   730     srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
   731   } else
   732 #endif
   733   if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) {
   734     // If this is an xlib cairo surface we don't want to fetch it into memory
   735     // because this is a major slow down.
   736     NativeSurface surf;
   737     surf.mFormat = format;
   738     surf.mType = NativeSurfaceType::CAIRO_SURFACE;
   739     surf.mSurface = aSurface->CairoSurface();
   740     surf.mSize = ToIntSize(aSurface->GetSize());
   741     srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
   743     if (srcBuffer) {
   744       // It's cheap enough to make a new one so we won't keep it around and
   745       // keeping it creates a cycle.
   746       return srcBuffer;
   747     }
   748   }
   750   if (!srcBuffer) {
   751     nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
   753     RefPtr<DataSourceSurface> dataSurf;
   755     if (imgSurface) {
   756       dataSurf = GetWrappedDataSourceSurface(aSurface);
   757     } else {
   758       dataSurf = CopySurface(aSurface);
   759     }
   761     if (!dataSurf) {
   762       return nullptr;
   763     }
   765     srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
   767     if (imgSurface && srcBuffer == dataSurf) {
   768       // Our wrapping surface will hold a reference to its image surface. We cause
   769       // a reference cycle if we add it to the cache. And caching it is pretty
   770       // pointless since we'll just wrap it again next use.
   771      return srcBuffer;
   772     }
   773   }
   775   // Add user data to aSurface so we can cache lookups in the future.
   776   SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
   777   srcSurfUD->mBackendType = aTarget->GetType();
   778   srcSurfUD->mSrcSurface = srcBuffer;
   779   aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
   781   return srcBuffer;
   782 }
   784 RefPtr<DataSourceSurface>
   785 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
   786 {
   787   nsRefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
   788   if (!image) {
   789     return nullptr;
   790   }
   791   RefPtr<DataSourceSurface> result =
   792     Factory::CreateWrappingDataSourceSurface(image->Data(),
   793                                              image->Stride(),
   794                                              ToIntSize(image->GetSize()),
   795                                              ImageFormatToSurfaceFormat(image->Format()));
   797   if (!result) {
   798     return nullptr;
   799   }
   801   // If we wrapped the underlying data of aSurface, then we need to add user data
   802   // to make sure aSurface stays alive until we are done with the data.
   803   DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
   804   srcSurfUD->mSurface = aSurface;
   805   result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
   807   return result;
   808 }
   810 TemporaryRef<ScaledFont>
   811 gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
   812 {
   813   NativeFont nativeFont;
   814   nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
   815   nativeFont.mFont = aFont->GetCairoScaledFont();
   816   RefPtr<ScaledFont> scaledFont =
   817     Factory::CreateScaledFontForNativeFont(nativeFont,
   818                                            aFont->GetAdjustedSize());
   819   return scaledFont;
   820 }
   822 cairo_user_data_key_t kDrawSourceSurface;
   823 static void
   824 DataSourceSurfaceDestroy(void *dataSourceSurface)
   825 {
   826   static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
   827 }
   829 cairo_user_data_key_t kDrawTargetForSurface;
   830 static void
   831 DataDrawTargetDestroy(void *aTarget)
   832 {
   833   static_cast<DrawTarget*>(aTarget)->Release();
   834 }
   836 bool
   837 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
   838 {
   839   if (!aTarget) {
   840     return false;
   841   }
   843   return SupportsAzureContentForType(aTarget->GetType());
   844 }
   846 bool
   847 gfxPlatform::UseAcceleratedSkiaCanvas()
   848 {
   849   return gfxPrefs::CanvasAzureAccelerated() &&
   850          mPreferredCanvasBackend == BackendType::SKIA;
   851 }
   853 void
   854 gfxPlatform::InitializeSkiaCacheLimits()
   855 {
   856   if (UseAcceleratedSkiaCanvas()) {
   857     bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
   858     int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
   859     int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
   861     // Prefs are in megabytes, but we want the sizes in bytes
   862     cacheSizeLimit *= 1024*1024;
   864     if (usingDynamicCache) {
   865       uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
   867       if (totalMemory <= 256*1024*1024) {
   868         // We need a very minimal cache on 256 meg devices
   869         cacheSizeLimit = 2*1024*1024;
   870       } else if (totalMemory > 0) {
   871         cacheSizeLimit = totalMemory / 16;
   872       }
   873     }
   875   #ifdef DEBUG
   876     printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
   877   #endif
   879 #ifdef USE_SKIA_GPU
   880     mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
   881 #endif
   882   }
   883 }
   885 mozilla::gl::SkiaGLGlue*
   886 gfxPlatform::GetSkiaGLGlue()
   887 {
   888 #ifdef USE_SKIA_GPU
   889   if (!mSkiaGlue) {
   890     /* Dummy context. We always draw into a FBO.
   891      *
   892      * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
   893      * stands, this only works on the main thread.
   894      */
   895     mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA();
   896     nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
   897     if (!glContext) {
   898       printf_stderr("Failed to create GLContext for SkiaGL!\n");
   899       return nullptr;
   900     }
   901     mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
   902     MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
   903     InitializeSkiaCacheLimits();
   904   }
   905 #endif
   907   return mSkiaGlue;
   908 }
   910 void
   911 gfxPlatform::PurgeSkiaCache()
   912 {
   913 #ifdef USE_SKIA_GPU
   914   if (!mSkiaGlue)
   915       return;
   917   mSkiaGlue->GetGrContext()->freeGpuResources();
   918 #endif
   919 }
   921 already_AddRefed<gfxASurface>
   922 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
   923 {
   924   if (aTarget->GetType() == BackendType::CAIRO) {
   925     cairo_surface_t* csurf =
   926       static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
   927     if (csurf) {
   928       return gfxASurface::Wrap(csurf);
   929     }
   930   }
   932   // The semantics of this part of the function are sort of weird. If we
   933   // don't have direct support for the backend, we snapshot the first time
   934   // and then return the snapshotted surface for the lifetime of the draw
   935   // target. Sometimes it seems like this works out, but it seems like it
   936   // might result in no updates ever.
   937   RefPtr<SourceSurface> source = aTarget->Snapshot();
   938   RefPtr<DataSourceSurface> data = source->GetDataSurface();
   940   if (!data) {
   941     return nullptr;
   942   }
   944   IntSize size = data->GetSize();
   945   gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
   948   nsRefPtr<gfxASurface> surf =
   949     new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
   950                         data->Stride(), format);
   952   if (surf->CairoStatus()) {
   953     return nullptr;
   954   }
   956   surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
   957   // keep the draw target alive as long as we need its data
   958   aTarget->AddRef();
   959   surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
   961   return surf.forget();
   962 }
   964 RefPtr<DrawTarget>
   965 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
   966 {
   967   // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
   968   // create the best offscreen surface for the current system and situation. We
   969   // can easily take advantage of this for the Cairo backend, so that's what we
   970   // do.
   971   // mozilla::gfx::Factory can get away without having all this knowledge for
   972   // now, but this might need to change in the future (using
   973   // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
   974   // backends).
   975   if (aBackend == BackendType::CAIRO) {
   976     nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize,
   977                                                         ContentForFormat(aFormat));
   978     if (!surf || surf->CairoStatus()) {
   979       return nullptr;
   980     }
   982     return CreateDrawTargetForSurface(surf, aSize);
   983   } else {
   984     return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
   985   }
   986 }
   988 RefPtr<DrawTarget>
   989 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
   990 {
   991   NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
   992   RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
   993   if (target ||
   994       mFallbackCanvasBackend == BackendType::NONE) {
   995     return target;
   996   }
   998   return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
   999 }
  1001 RefPtr<DrawTarget>
  1002 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
  1004   NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
  1005   return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
  1008 RefPtr<DrawTarget>
  1009 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
  1011   NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
  1012   if (mContentBackend == BackendType::CAIRO) {
  1013     nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat));
  1014     return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize);
  1016   return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat);
  1019 /* static */ BackendType
  1020 gfxPlatform::BackendTypeForName(const nsCString& aName)
  1022   if (aName.EqualsLiteral("cairo"))
  1023     return BackendType::CAIRO;
  1024   if (aName.EqualsLiteral("skia"))
  1025     return BackendType::SKIA;
  1026   if (aName.EqualsLiteral("direct2d"))
  1027     return BackendType::DIRECT2D;
  1028   if (aName.EqualsLiteral("cg"))
  1029     return BackendType::COREGRAPHICS;
  1030   return BackendType::NONE;
  1033 nsresult
  1034 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
  1035                          const nsACString& aGenericFamily,
  1036                          nsTArray<nsString>& aListOfFonts)
  1038     return NS_ERROR_NOT_IMPLEMENTED;
  1041 nsresult
  1042 gfxPlatform::UpdateFontList()
  1044     return NS_ERROR_NOT_IMPLEMENTED;
  1047 bool
  1048 gfxPlatform::DownloadableFontsEnabled()
  1050     if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
  1051         mAllowDownloadableFonts =
  1052             Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
  1055     return mAllowDownloadableFonts;
  1058 bool
  1059 gfxPlatform::UseCmapsDuringSystemFallback()
  1061     if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
  1062         mFallbackUsesCmaps =
  1063             Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
  1066     return mFallbackUsesCmaps;
  1069 bool
  1070 gfxPlatform::OpenTypeSVGEnabled()
  1072     if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
  1073         mOpenTypeSVGEnabled =
  1074             Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
  1077     return mOpenTypeSVGEnabled > 0;
  1080 uint32_t
  1081 gfxPlatform::WordCacheCharLimit()
  1083     if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
  1084         mWordCacheCharLimit =
  1085             Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
  1086         if (mWordCacheCharLimit < 0) {
  1087             mWordCacheCharLimit = 32;
  1091     return uint32_t(mWordCacheCharLimit);
  1094 uint32_t
  1095 gfxPlatform::WordCacheMaxEntries()
  1097     if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
  1098         mWordCacheMaxEntries =
  1099             Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
  1100         if (mWordCacheMaxEntries < 0) {
  1101             mWordCacheMaxEntries = 10000;
  1105     return uint32_t(mWordCacheMaxEntries);
  1108 bool
  1109 gfxPlatform::UseGraphiteShaping()
  1111     if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
  1112         mGraphiteShapingEnabled =
  1113             Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
  1116     return mGraphiteShapingEnabled;
  1119 bool
  1120 gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
  1122     if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
  1123         mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
  1126     int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
  1128     return (mUseHarfBuzzScripts & shapingType) != 0;
  1131 gfxFontEntry*
  1132 gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
  1133                               const uint8_t *aFontData,
  1134                               uint32_t aLength)
  1136     // Default implementation does not handle activating downloaded fonts;
  1137     // just free the data and return.
  1138     // Platforms that support @font-face must override this,
  1139     // using the data to instantiate the font, and taking responsibility
  1140     // for freeing it when no longer required.
  1141     if (aFontData) {
  1142         NS_Free((void*)aFontData);
  1144     return nullptr;
  1147 static void
  1148 AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
  1150     NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
  1152     nsAutoCString prefName, langGroupString;
  1154     aLangGroup->ToUTF8String(langGroupString);
  1156     nsAutoCString genericDotLang;
  1157     if (aGenericName) {
  1158         genericDotLang.Assign(aGenericName);
  1159     } else {
  1160         prefName.AssignLiteral("font.default.");
  1161         prefName.Append(langGroupString);
  1162         genericDotLang = Preferences::GetCString(prefName.get());
  1165     genericDotLang.AppendLiteral(".");
  1166     genericDotLang.Append(langGroupString);
  1168     // fetch font.name.xxx value
  1169     prefName.AssignLiteral("font.name.");
  1170     prefName.Append(genericDotLang);
  1171     nsAdoptingString nameValue = Preferences::GetString(prefName.get());
  1172     if (nameValue) {
  1173         if (!aFonts.IsEmpty())
  1174             aFonts.AppendLiteral(", ");
  1175         aFonts += nameValue;
  1178     // fetch font.name-list.xxx value
  1179     prefName.AssignLiteral("font.name-list.");
  1180     prefName.Append(genericDotLang);
  1181     nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
  1182     if (nameListValue && !nameListValue.Equals(nameValue)) {
  1183         if (!aFonts.IsEmpty())
  1184             aFonts.AppendLiteral(", ");
  1185         aFonts += nameListValue;
  1189 void
  1190 gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
  1192     aFonts.Truncate();
  1194     AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
  1195     if (aAppendUnicode)
  1196         AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
  1199 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
  1200                                     void *aClosure)
  1202     NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
  1204     uint32_t    i;
  1205     for (i = 0; i < aLangArrayLen; i++) {
  1206         eFontPrefLang prefLang = aLangArray[i];
  1207         const char *langGroup = GetPrefLangName(prefLang);
  1209         nsAutoCString prefName;
  1211         prefName.AssignLiteral("font.default.");
  1212         prefName.Append(langGroup);
  1213         nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
  1215         genericDotLang.AppendLiteral(".");
  1216         genericDotLang.Append(langGroup);
  1218         // fetch font.name.xxx value
  1219         prefName.AssignLiteral("font.name.");
  1220         prefName.Append(genericDotLang);
  1221         nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
  1222         if (nameValue) {
  1223             if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
  1224                 return false;
  1227         // fetch font.name-list.xxx value
  1228         prefName.AssignLiteral("font.name-list.");
  1229         prefName.Append(genericDotLang);
  1230         nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
  1231         if (nameListValue && !nameListValue.Equals(nameValue)) {
  1232             const char kComma = ',';
  1233             const char *p, *p_end;
  1234             nsAutoCString list(nameListValue);
  1235             list.BeginReading(p);
  1236             list.EndReading(p_end);
  1237             while (p < p_end) {
  1238                 while (nsCRT::IsAsciiSpace(*p)) {
  1239                     if (++p == p_end)
  1240                         break;
  1242                 if (p == p_end)
  1243                     break;
  1244                 const char *start = p;
  1245                 while (++p != p_end && *p != kComma)
  1246                     /* nothing */ ;
  1247                 nsAutoCString fontName(Substring(start, p));
  1248                 fontName.CompressWhitespace(false, true);
  1249                 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
  1250                     return false;
  1251                 p++;
  1256     return true;
  1259 eFontPrefLang
  1260 gfxPlatform::GetFontPrefLangFor(const char* aLang)
  1262     if (!aLang || !aLang[0]) {
  1263         return eFontPrefLang_Others;
  1265     for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
  1266         if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
  1267             return eFontPrefLang(i);
  1270     return eFontPrefLang_Others;
  1273 eFontPrefLang
  1274 gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
  1276     if (!aLang)
  1277         return eFontPrefLang_Others;
  1278     nsAutoCString lang;
  1279     aLang->ToUTF8String(lang);
  1280     return GetFontPrefLangFor(lang.get());
  1283 const char*
  1284 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
  1286     if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
  1287         return gPrefLangNames[uint32_t(aLang)];
  1289     return nullptr;
  1292 eFontPrefLang
  1293 gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
  1295     switch (aUnicodeRange) {
  1296         case kRangeSetLatin:   return eFontPrefLang_Western;
  1297         case kRangeCyrillic:   return eFontPrefLang_Cyrillic;
  1298         case kRangeGreek:      return eFontPrefLang_Greek;
  1299         case kRangeTurkish:    return eFontPrefLang_Turkish;
  1300         case kRangeHebrew:     return eFontPrefLang_Hebrew;
  1301         case kRangeArabic:     return eFontPrefLang_Arabic;
  1302         case kRangeBaltic:     return eFontPrefLang_Baltic;
  1303         case kRangeThai:       return eFontPrefLang_Thai;
  1304         case kRangeKorean:     return eFontPrefLang_Korean;
  1305         case kRangeJapanese:   return eFontPrefLang_Japanese;
  1306         case kRangeSChinese:   return eFontPrefLang_ChineseCN;
  1307         case kRangeTChinese:   return eFontPrefLang_ChineseTW;
  1308         case kRangeDevanagari: return eFontPrefLang_Devanagari;
  1309         case kRangeTamil:      return eFontPrefLang_Tamil;
  1310         case kRangeArmenian:   return eFontPrefLang_Armenian;
  1311         case kRangeBengali:    return eFontPrefLang_Bengali;
  1312         case kRangeCanadian:   return eFontPrefLang_Canadian;
  1313         case kRangeEthiopic:   return eFontPrefLang_Ethiopic;
  1314         case kRangeGeorgian:   return eFontPrefLang_Georgian;
  1315         case kRangeGujarati:   return eFontPrefLang_Gujarati;
  1316         case kRangeGurmukhi:   return eFontPrefLang_Gurmukhi;
  1317         case kRangeKhmer:      return eFontPrefLang_Khmer;
  1318         case kRangeMalayalam:  return eFontPrefLang_Malayalam;
  1319         case kRangeOriya:      return eFontPrefLang_Oriya;
  1320         case kRangeTelugu:     return eFontPrefLang_Telugu;
  1321         case kRangeKannada:    return eFontPrefLang_Kannada;
  1322         case kRangeSinhala:    return eFontPrefLang_Sinhala;
  1323         case kRangeTibetan:    return eFontPrefLang_Tibetan;
  1324         case kRangeSetCJK:     return eFontPrefLang_CJKSet;
  1325         default:               return eFontPrefLang_Others;
  1329 bool
  1330 gfxPlatform::IsLangCJK(eFontPrefLang aLang)
  1332     switch (aLang) {
  1333         case eFontPrefLang_Japanese:
  1334         case eFontPrefLang_ChineseTW:
  1335         case eFontPrefLang_ChineseCN:
  1336         case eFontPrefLang_ChineseHK:
  1337         case eFontPrefLang_Korean:
  1338         case eFontPrefLang_CJKSet:
  1339             return true;
  1340         default:
  1341             return false;
  1345 mozilla::layers::DiagnosticTypes
  1346 gfxPlatform::GetLayerDiagnosticTypes()
  1348   mozilla::layers::DiagnosticTypes type = DIAGNOSTIC_NONE;
  1349   if (gfxPrefs::DrawLayerBorders()) {
  1350     type |= mozilla::layers::DIAGNOSTIC_LAYER_BORDERS;
  1352   if (gfxPrefs::DrawTileBorders()) {
  1353     type |= mozilla::layers::DIAGNOSTIC_TILE_BORDERS;
  1355   if (gfxPrefs::DrawBigImageBorders()) {
  1356     type |= mozilla::layers::DIAGNOSTIC_BIGIMAGE_BORDERS;
  1358   if (gfxPrefs::FlashLayerBorders()) {
  1359     type |= mozilla::layers::DIAGNOSTIC_FLASH_BORDERS;
  1361   return type;
  1364 void
  1365 gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
  1367     if (IsLangCJK(aCharLang)) {
  1368         AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
  1369     } else {
  1370         AppendPrefLang(aPrefLangs, aLen, aCharLang);
  1373     AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
  1376 void
  1377 gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
  1379     // prefer the lang specified by the page *if* CJK
  1380     if (IsLangCJK(aPageLang)) {
  1381         AppendPrefLang(aPrefLangs, aLen, aPageLang);
  1384     // if not set up, set up the default CJK order, based on accept lang settings and locale
  1385     if (mCJKPrefLangs.Length() == 0) {
  1387         // temp array
  1388         eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
  1389         uint32_t tempLen = 0;
  1391         // Add the CJK pref fonts from accept languages, the order should be same order
  1392         nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
  1393         if (!list.IsEmpty()) {
  1394             const char kComma = ',';
  1395             const char *p, *p_end;
  1396             list.BeginReading(p);
  1397             list.EndReading(p_end);
  1398             while (p < p_end) {
  1399                 while (nsCRT::IsAsciiSpace(*p)) {
  1400                     if (++p == p_end)
  1401                         break;
  1403                 if (p == p_end)
  1404                     break;
  1405                 const char *start = p;
  1406                 while (++p != p_end && *p != kComma)
  1407                     /* nothing */ ;
  1408                 nsAutoCString lang(Substring(start, p));
  1409                 lang.CompressWhitespace(false, true);
  1410                 eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
  1411                 switch (fpl) {
  1412                     case eFontPrefLang_Japanese:
  1413                     case eFontPrefLang_Korean:
  1414                     case eFontPrefLang_ChineseCN:
  1415                     case eFontPrefLang_ChineseHK:
  1416                     case eFontPrefLang_ChineseTW:
  1417                         AppendPrefLang(tempPrefLangs, tempLen, fpl);
  1418                         break;
  1419                     default:
  1420                         break;
  1422                 p++;
  1426         do { // to allow 'break' to abort this block if a call fails
  1427             nsresult rv;
  1428             nsCOMPtr<nsILocaleService> ls =
  1429                 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
  1430             if (NS_FAILED(rv))
  1431                 break;
  1433             nsCOMPtr<nsILocale> appLocale;
  1434             rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
  1435             if (NS_FAILED(rv))
  1436                 break;
  1438             nsString localeStr;
  1439             rv = appLocale->
  1440                 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
  1441             if (NS_FAILED(rv))
  1442                 break;
  1444             const nsAString& lang = Substring(localeStr, 0, 2);
  1445             if (lang.EqualsLiteral("ja")) {
  1446                 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
  1447             } else if (lang.EqualsLiteral("zh")) {
  1448                 const nsAString& region = Substring(localeStr, 3, 2);
  1449                 if (region.EqualsLiteral("CN")) {
  1450                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
  1451                 } else if (region.EqualsLiteral("TW")) {
  1452                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
  1453                 } else if (region.EqualsLiteral("HK")) {
  1454                     AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
  1456             } else if (lang.EqualsLiteral("ko")) {
  1457                 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
  1459         } while (0);
  1461         // last resort... (the order is same as old gfx.)
  1462         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
  1463         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
  1464         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
  1465         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
  1466         AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
  1468         // copy into the cached array
  1469         uint32_t j;
  1470         for (j = 0; j < tempLen; j++) {
  1471             mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
  1475     // append in cached CJK langs
  1476     uint32_t  i, numCJKlangs = mCJKPrefLangs.Length();
  1478     for (i = 0; i < numCJKlangs; i++) {
  1479         AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
  1484 void
  1485 gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
  1487     if (aLen >= kMaxLenPrefLangList) return;
  1489     // make sure
  1490     uint32_t  i = 0;
  1491     while (i < aLen && aPrefLangs[i] != aAddLang) {
  1492         i++;
  1495     if (i == aLen) {
  1496         aPrefLangs[aLen] = aAddLang;
  1497         aLen++;
  1501 void
  1502 gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
  1503                               uint32_t aContentBitmask, BackendType aContentDefault)
  1505     mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
  1506     if (mPreferredCanvasBackend == BackendType::NONE) {
  1507         mPreferredCanvasBackend = aCanvasDefault;
  1509     mFallbackCanvasBackend =
  1510         GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
  1512     mContentBackendBitmask = aContentBitmask;
  1513     mContentBackend = GetContentBackendPref(mContentBackendBitmask);
  1514     if (mContentBackend == BackendType::NONE) {
  1515         mContentBackend = aContentDefault;
  1516         // mContentBackendBitmask is our canonical reference for supported
  1517         // backends so we need to add the default if we are using it and
  1518         // overriding the prefs.
  1519         mContentBackendBitmask |= BackendTypeBit(aContentDefault);
  1523 /* static */ BackendType
  1524 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
  1526     return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
  1529 /* static */ BackendType
  1530 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
  1532     return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
  1535 /* static */ BackendType
  1536 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
  1538     nsTArray<nsCString> backendList;
  1539     nsCString prefString;
  1540     if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
  1541         ParseString(prefString, ',', backendList);
  1544     uint32_t allowedBackends = 0;
  1545     BackendType result = BackendType::NONE;
  1546     for (uint32_t i = 0; i < backendList.Length(); ++i) {
  1547         BackendType type = BackendTypeForName(backendList[i]);
  1548         if (BackendTypeBit(type) & aBackendBitmask) {
  1549             allowedBackends |= BackendTypeBit(type);
  1550             if (result == BackendType::NONE) {
  1551                 result = type;
  1556     aBackendBitmask = allowedBackends;
  1557     return result;
  1560 bool
  1561 gfxPlatform::OffMainThreadCompositingEnabled()
  1563   return XRE_GetProcessType() == GeckoProcessType_Default ?
  1564     CompositorParent::CompositorLoop() != nullptr :
  1565     CompositorChild::ChildProcessHasCompositor();
  1568 eCMSMode
  1569 gfxPlatform::GetCMSMode()
  1571     if (gCMSInitialized == false) {
  1572         gCMSInitialized = true;
  1574         int32_t mode = gfxPrefs::CMSMode();
  1575         if (mode >= 0 && mode < eCMSMode_AllCount) {
  1576             gCMSMode = static_cast<eCMSMode>(mode);
  1579         bool enableV4 = gfxPrefs::CMSEnableV4();
  1580         if (enableV4) {
  1581             qcms_enable_iccv4();
  1584     return gCMSMode;
  1587 int
  1588 gfxPlatform::GetRenderingIntent()
  1590     if (!gCMSIntentInitialized) {
  1591         gCMSIntentInitialized = true;
  1593         // gfxPrefs.h is using 0 as the default for the rendering
  1594         // intent preference, based on that being the value for
  1595         // QCMS_INTENT_DEFAULT.  Assert here to catch if that ever
  1596         // changes and we can then figure out what to do about it.
  1597         MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
  1599         /* Try to query the pref system for a rendering intent. */
  1600         int32_t pIntent = gfxPrefs::CMSRenderingIntent();
  1601         if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
  1602             gCMSIntent = pIntent;
  1603         } else {
  1604             /* If the pref is out of range, use embedded profile. */
  1605             gCMSIntent = -1;
  1608     return gCMSIntent;
  1611 void
  1612 gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
  1615     if (transform) {
  1616         /* we want the bytes in RGB order */
  1617 #ifdef IS_LITTLE_ENDIAN
  1618         /* ABGR puts the bytes in |RGBA| order on little endian */
  1619         uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
  1620         qcms_transform_data(transform,
  1621                        (uint8_t *)&packed, (uint8_t *)&packed,
  1622                        1);
  1623         out.~gfxRGBA();
  1624         new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
  1625 #else
  1626         /* ARGB puts the bytes in |ARGB| order on big endian */
  1627         uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
  1628         /* add one to move past the alpha byte */
  1629         qcms_transform_data(transform,
  1630                        (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
  1631                        1);
  1632         out.~gfxRGBA();
  1633         new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
  1634 #endif
  1637     else if (&out != &in)
  1638         out = in;
  1641 void
  1642 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
  1644     mem = nullptr;
  1645     size = 0;
  1648 void
  1649 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
  1651     nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
  1652     if (!fname.IsEmpty()) {
  1653         qcms_data_from_path(fname, &mem, &size);
  1655     else {
  1656         gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
  1660 void
  1661 gfxPlatform::CreateCMSOutputProfile()
  1663     if (!gCMSOutputProfile) {
  1664         /* Determine if we're using the internal override to force sRGB as
  1665            an output profile for reftests. See Bug 452125.
  1667            Note that we don't normally (outside of tests) set a
  1668            default value of this preference, which means nsIPrefBranch::GetBoolPref
  1669            will typically throw (and leave its out-param untouched).
  1670          */
  1671         if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
  1672             gCMSOutputProfile = GetCMSsRGBProfile();
  1675         if (!gCMSOutputProfile) {
  1676             void* mem = nullptr;
  1677             size_t size = 0;
  1679             GetCMSOutputProfileData(mem, size);
  1680             if ((mem != nullptr) && (size > 0)) {
  1681                 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
  1682                 free(mem);
  1686         /* Determine if the profile looks bogus. If so, close the profile
  1687          * and use sRGB instead. See bug 460629, */
  1688         if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
  1689             NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
  1690                          "Builtin sRGB profile tagged as bogus!!!");
  1691             qcms_profile_release(gCMSOutputProfile);
  1692             gCMSOutputProfile = nullptr;
  1695         if (!gCMSOutputProfile) {
  1696             gCMSOutputProfile = GetCMSsRGBProfile();
  1698         /* Precache the LUT16 Interpolations for the output profile. See
  1699            bug 444661 for details. */
  1700         qcms_profile_precache_output_transform(gCMSOutputProfile);
  1704 qcms_profile *
  1705 gfxPlatform::GetCMSOutputProfile()
  1707     return gCMSOutputProfile;
  1710 qcms_profile *
  1711 gfxPlatform::GetCMSsRGBProfile()
  1713     if (!gCMSsRGBProfile) {
  1715         /* Create the profile using qcms. */
  1716         gCMSsRGBProfile = qcms_profile_sRGB();
  1718     return gCMSsRGBProfile;
  1721 qcms_transform *
  1722 gfxPlatform::GetCMSRGBTransform()
  1724     if (!gCMSRGBTransform) {
  1725         qcms_profile *inProfile, *outProfile;
  1726         outProfile = GetCMSOutputProfile();
  1727         inProfile = GetCMSsRGBProfile();
  1729         if (!inProfile || !outProfile)
  1730             return nullptr;
  1732         gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
  1733                                               outProfile, QCMS_DATA_RGB_8,
  1734                                              QCMS_INTENT_PERCEPTUAL);
  1737     return gCMSRGBTransform;
  1740 qcms_transform *
  1741 gfxPlatform::GetCMSInverseRGBTransform()
  1743     if (!gCMSInverseRGBTransform) {
  1744         qcms_profile *inProfile, *outProfile;
  1745         inProfile = GetCMSOutputProfile();
  1746         outProfile = GetCMSsRGBProfile();
  1748         if (!inProfile || !outProfile)
  1749             return nullptr;
  1751         gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
  1752                                                      outProfile, QCMS_DATA_RGB_8,
  1753                                                      QCMS_INTENT_PERCEPTUAL);
  1756     return gCMSInverseRGBTransform;
  1759 qcms_transform *
  1760 gfxPlatform::GetCMSRGBATransform()
  1762     if (!gCMSRGBATransform) {
  1763         qcms_profile *inProfile, *outProfile;
  1764         outProfile = GetCMSOutputProfile();
  1765         inProfile = GetCMSsRGBProfile();
  1767         if (!inProfile || !outProfile)
  1768             return nullptr;
  1770         gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
  1771                                                outProfile, QCMS_DATA_RGBA_8,
  1772                                                QCMS_INTENT_PERCEPTUAL);
  1775     return gCMSRGBATransform;
  1778 /* Shuts down various transforms and profiles for CMS. */
  1779 static void ShutdownCMS()
  1782     if (gCMSRGBTransform) {
  1783         qcms_transform_release(gCMSRGBTransform);
  1784         gCMSRGBTransform = nullptr;
  1786     if (gCMSInverseRGBTransform) {
  1787         qcms_transform_release(gCMSInverseRGBTransform);
  1788         gCMSInverseRGBTransform = nullptr;
  1790     if (gCMSRGBATransform) {
  1791         qcms_transform_release(gCMSRGBATransform);
  1792         gCMSRGBATransform = nullptr;
  1794     if (gCMSOutputProfile) {
  1795         qcms_profile_release(gCMSOutputProfile);
  1797         // handle the aliased case
  1798         if (gCMSsRGBProfile == gCMSOutputProfile)
  1799             gCMSsRGBProfile = nullptr;
  1800         gCMSOutputProfile = nullptr;
  1802     if (gCMSsRGBProfile) {
  1803         qcms_profile_release(gCMSsRGBProfile);
  1804         gCMSsRGBProfile = nullptr;
  1807     // Reset the state variables
  1808     gCMSIntent = -2;
  1809     gCMSMode = eCMSMode_Off;
  1810     gCMSInitialized = false;
  1813 // default SetupClusterBoundaries, based on Unicode properties;
  1814 // platform subclasses may override if they wish
  1815 void
  1816 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
  1818     if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
  1819         // 8-bit text doesn't have clusters.
  1820         // XXX is this true in all languages???
  1821         // behdad: don't think so.  Czech for example IIRC has a
  1822         // 'ch' grapheme.
  1823         // jfkthame: but that's not expected to behave as a grapheme cluster
  1824         // for selection/editing/etc.
  1825         return;
  1828     aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
  1831 int32_t
  1832 gfxPlatform::GetBidiNumeralOption()
  1834     if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
  1835         mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
  1837     return mBidiNumeralOption;
  1840 static void
  1841 FlushFontAndWordCaches()
  1843     gfxFontCache *fontCache = gfxFontCache::GetCache();
  1844     if (fontCache) {
  1845         fontCache->AgeAllGenerations();
  1846         fontCache->FlushShapedWordCaches();
  1850 void
  1851 gfxPlatform::FontsPrefsChanged(const char *aPref)
  1853     NS_ASSERTION(aPref != nullptr, "null preference");
  1854     if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
  1855         mAllowDownloadableFonts = UNINITIALIZED_VALUE;
  1856     } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
  1857         mFallbackUsesCmaps = UNINITIALIZED_VALUE;
  1858     } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
  1859         mWordCacheCharLimit = UNINITIALIZED_VALUE;
  1860         FlushFontAndWordCaches();
  1861     } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
  1862         mWordCacheMaxEntries = UNINITIALIZED_VALUE;
  1863         FlushFontAndWordCaches();
  1864     } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
  1865         mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
  1866         FlushFontAndWordCaches();
  1867     } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
  1868         mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
  1869         FlushFontAndWordCaches();
  1870     } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
  1871         mBidiNumeralOption = UNINITIALIZED_VALUE;
  1872     } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
  1873         mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
  1874         gfxFontCache::GetCache()->AgeAllGenerations();
  1879 PRLogModuleInfo*
  1880 gfxPlatform::GetLog(eGfxLog aWhichLog)
  1882     // logs shared across gfx
  1883 #ifdef PR_LOGGING
  1884     static PRLogModuleInfo *sFontlistLog = nullptr;
  1885     static PRLogModuleInfo *sFontInitLog = nullptr;
  1886     static PRLogModuleInfo *sTextrunLog = nullptr;
  1887     static PRLogModuleInfo *sTextrunuiLog = nullptr;
  1888     static PRLogModuleInfo *sCmapDataLog = nullptr;
  1889     static PRLogModuleInfo *sTextPerfLog = nullptr;
  1891     // Assume that if one is initialized, all are initialized
  1892     if (!sFontlistLog) {
  1893         sFontlistLog = PR_NewLogModule("fontlist");
  1894         sFontInitLog = PR_NewLogModule("fontinit");
  1895         sTextrunLog = PR_NewLogModule("textrun");
  1896         sTextrunuiLog = PR_NewLogModule("textrunui");
  1897         sCmapDataLog = PR_NewLogModule("cmapdata");
  1898         sTextPerfLog = PR_NewLogModule("textperf");
  1901     switch (aWhichLog) {
  1902     case eGfxLog_fontlist:
  1903         return sFontlistLog;
  1904         break;
  1905     case eGfxLog_fontinit:
  1906         return sFontInitLog;
  1907         break;
  1908     case eGfxLog_textrun:
  1909         return sTextrunLog;
  1910         break;
  1911     case eGfxLog_textrunui:
  1912         return sTextrunuiLog;
  1913         break;
  1914     case eGfxLog_cmapdata:
  1915         return sCmapDataLog;
  1916         break;
  1917     case eGfxLog_textperf:
  1918         return sTextPerfLog;
  1919         break;
  1920     default:
  1921         break;
  1924     return nullptr;
  1925 #else
  1926     return nullptr;
  1927 #endif
  1930 int
  1931 gfxPlatform::GetScreenDepth() const
  1933     NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
  1934     return 0;
  1937 mozilla::gfx::SurfaceFormat
  1938 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
  1940   switch (aContent) {
  1941   case gfxContentType::COLOR:
  1942     switch (GetOffscreenFormat()) {
  1943     case gfxImageFormat::ARGB32:
  1944       return mozilla::gfx::SurfaceFormat::B8G8R8A8;
  1945     case gfxImageFormat::RGB24:
  1946       return mozilla::gfx::SurfaceFormat::B8G8R8X8;
  1947     case gfxImageFormat::RGB16_565:
  1948       return mozilla::gfx::SurfaceFormat::R5G6B5;
  1949     default:
  1950       NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
  1951       return mozilla::gfx::SurfaceFormat::B8G8R8A8;
  1953   case gfxContentType::ALPHA:
  1954     return mozilla::gfx::SurfaceFormat::A8;
  1955   case gfxContentType::COLOR_ALPHA:
  1956     return mozilla::gfx::SurfaceFormat::B8G8R8A8;
  1957   default:
  1958     NS_NOTREACHED("unknown gfxContentType");
  1959     return mozilla::gfx::SurfaceFormat::B8G8R8A8;
  1963 gfxImageFormat
  1964 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
  1966   switch (aContent) {
  1967   case gfxContentType::COLOR:
  1968     return GetOffscreenFormat();
  1969   case gfxContentType::ALPHA:
  1970     return gfxImageFormat::A8;
  1971   case gfxContentType::COLOR_ALPHA:
  1972     return gfxImageFormat::ARGB32;
  1973   default:
  1974     NS_NOTREACHED("unknown gfxContentType");
  1975     return gfxImageFormat::ARGB32;
  1979 /**
  1980  * There are a number of layers acceleration (or layers in general) preferences
  1981  * that should be consistent for the lifetime of the application (bug 840967).
  1982  * As such, we will evaluate them all as soon as one of them is evaluated
  1983  * and remember the values.  Changing these preferences during the run will
  1984  * not have any effect until we restart.
  1985  */
  1986 static bool sLayersSupportsD3D9 = false;
  1987 static bool sBufferRotationCheckPref = true;
  1988 static bool sPrefBrowserTabsRemoteAutostart = false;
  1990 static bool sLayersAccelerationPrefsInitialized = false;
  1992 void
  1993 InitLayersAccelerationPrefs()
  1995   if (!sLayersAccelerationPrefsInitialized)
  1997     // If this is called for the first time on a non-main thread, we're screwed.
  1998     // At the moment there's no explicit guarantee that the main thread calls
  1999     // this before the compositor thread, but let's at least make the assumption
  2000     // explicit.
  2001     MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
  2003     sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false);
  2005 #ifdef XP_WIN
  2006     if (gfxPrefs::LayersAccelerationForceEnabled()) {
  2007       sLayersSupportsD3D9 = true;
  2008     } else {
  2009       nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
  2010       if (gfxInfo) {
  2011         int32_t status;
  2012         if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
  2013           if (status == nsIGfxInfo::FEATURE_NO_INFO) {
  2014             sLayersSupportsD3D9 = true;
  2019 #endif
  2021     sLayersAccelerationPrefsInitialized = true;
  2025 bool
  2026 gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
  2028   InitLayersAccelerationPrefs();
  2029   return gfxPrefs::LayersOffMainThreadCompositionEnabled() ||
  2030          gfxPrefs::LayersOffMainThreadCompositionForceEnabled() ||
  2031          gfxPrefs::LayersOffMainThreadCompositionTestingEnabled();
  2034 bool gfxPlatform::OffMainThreadCompositionRequired()
  2036   InitLayersAccelerationPrefs();
  2037 #if defined(MOZ_WIDGET_GTK) && defined(NIGHTLY_BUILD)
  2038   // Linux users who chose OpenGL are being grandfathered in to OMTC
  2039   return sPrefBrowserTabsRemoteAutostart ||
  2040          gfxPrefs::LayersAccelerationForceEnabled();
  2041 #else
  2042   return sPrefBrowserTabsRemoteAutostart;
  2043 #endif
  2046 bool
  2047 gfxPlatform::CanUseDirect3D9()
  2049   // this function is called from the compositor thread, so it is not
  2050   // safe to init the prefs etc. from here.
  2051   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
  2052   return sLayersSupportsD3D9;
  2055 bool
  2056 gfxPlatform::BufferRotationEnabled()
  2058   MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
  2060   return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
  2063 void
  2064 gfxPlatform::DisableBufferRotation()
  2066   MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
  2068   sBufferRotationCheckPref = false;
  2071 TemporaryRef<ScaledFont>
  2072 gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
  2074     NativeFont nativeFont;
  2075     if (aTarget->GetType() == BackendType::CAIRO || aTarget->GetType() == BackendType::SKIA) {
  2076         nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
  2077         nativeFont.mFont = aFont->GetCairoScaledFont();
  2078         return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
  2081     return nullptr;

mercurial