Bug 912794 - Separate out the CMS globals and prefs into a singleton gfxColorManagement. r=ncameron
☠☠ backed out by ca38bd9ec80a ☠ ☠
authorMilan Sreckovic <milan@mozilla.com>
Fri, 06 Sep 2013 12:48:17 -0700
changeset 158955 35575118c650874ab87b5b8bc573e740a287fb38
parent 158954 8c564bfcd0ece3c9fc694e3f9cc489ec18789988
child 158956 49986ca301b50f4dc46a7af3ee1b91d83bd89f40
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersncameron
bugs912794
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 912794 - Separate out the CMS globals and prefs into a singleton gfxColorManagement. r=ncameron Preferences are now initialized at startup, then updated with callbacks. The methods that access the cached values are not checking the preferences. This lets us better control which thread reads the prefs.
gfx/thebes/gfxColorManagement.cpp
gfx/thebes/gfxColorManagement.h
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxPattern.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/moz.build
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsPNGDecoder.cpp
widget/cocoa/nsCocoaWindow.mm
widget/xpwidgets/nsXPLookAndFeel.cpp
copy from gfx/thebes/gfxPlatform.cpp
copy to gfx/thebes/gfxColorManagement.cpp
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxColorManagement.cpp
@@ -1,2032 +1,412 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifdef MOZ_LOGGING
-#define FORCE_PR_LOG /* Allow logging in the release build */
-#endif
-
-#include "mozilla/layers/CompositorChild.h"
-#include "mozilla/layers/CompositorParent.h"
-#include "mozilla/layers/ImageBridgeChild.h"
-
-#include "prlog.h"
-#include "prenv.h"
-
-#include "gfxPlatform.h"
-
-#include "nsXULAppAPI.h"
-
-#if defined(XP_WIN)
-#include "gfxWindowsPlatform.h"
-#include "gfxD2DSurface.h"
-#elif defined(XP_MACOSX)
-#include "gfxPlatformMac.h"
-#include "gfxQuartzSurface.h"
-#elif defined(MOZ_WIDGET_GTK)
-#include "gfxPlatformGtk.h"
-#elif defined(MOZ_WIDGET_QT)
-#include "gfxQtPlatform.h"
-#elif defined(XP_OS2)
-#include "gfxOS2Platform.h"
-#elif defined(ANDROID)
-#include "gfxAndroidPlatform.h"
-#endif
-
-#include "nsGkAtoms.h"
-#include "gfxPlatformFontList.h"
-#include "gfxContext.h"
-#include "gfxImageSurface.h"
-#include "gfxUserFontSet.h"
-#include "nsUnicodeProperties.h"
-#include "harfbuzz/hb.h"
-#include "gfxGraphiteShaper.h"
-
-#include "nsUnicodeRange.h"
-#include "nsServiceManagerUtils.h"
-#include "nsTArray.h"
-#include "nsUnicharUtilCIID.h"
-#include "nsILocaleService.h"
-#include "nsReadableUtils.h"
-
-#include "nsWeakReference.h"
-
-#include "cairo.h"
-#include "qcms.h"
-
-#include "plstr.h"
-#include "nsCRT.h"
-#include "GLContext.h"
-#include "GLContextProvider.h"
-
-#ifdef MOZ_WIDGET_ANDROID
-#include "TexturePoolOGL.h"
-#endif
-
-#ifdef USE_SKIA
-#include "skia/SkGraphics.h"
-#endif
-
-#ifdef USE_SKIA_GPU
-#include "skia/GrContext.h"
-#include "skia/GrGLInterface.h"
-#include "GLContextSkia.h"
-#endif
-
+#include "gfxColorManagement.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
-
-#include "nsIGfxInfo.h"
+#include "nsCRTGlue.h"
 
 using namespace mozilla;
-using namespace mozilla::layers;
 
-gfxPlatform *gPlatform = nullptr;
-static bool gEverInitialized = false;
-
-static Mutex* gGfxPlatformPrefsLock = nullptr;
-
-// These two may point to the same profile
-static qcms_profile *gCMSOutputProfile = nullptr;
-static qcms_profile *gCMSsRGBProfile = nullptr;
-
-static qcms_transform *gCMSRGBTransform = nullptr;
-static qcms_transform *gCMSInverseRGBTransform = nullptr;
-static qcms_transform *gCMSRGBATransform = nullptr;
+gfxColorManagement* gfxColorManagement::sInstance = nullptr;
 
-static bool gCMSInitialized = false;
-static eCMSMode gCMSMode = eCMSMode_Off;
-static int gCMSIntent = -2;
-
-static void ShutdownCMS();
-static void MigratePrefs();
-
-static bool sDrawFrameCounter = false;
+// Avoid the typos in getting the name wrong
+#define kCMSPrefNameForcesRGB       "gfx.color_management.force_srgb"
+#define kCMSPrefNameMode            "gfx.color_management.mode"
+#define kCMSPrefNameEnablev4        "gfx.color_management.enablev4"
+#define kCMSPrefNameRenderingIntent "gfx.color_management.rendering_intent"
+#define kCMSPrefNameDisplayProfile  "gfx.color_management.display_profile"
+#define kCMSObsoletePrefEnabled     "gfx.color_management.enabled"
 
-#include "mozilla/gfx/2D.h"
-using namespace mozilla::gfx;
-
-// logs shared across gfx
-#ifdef PR_LOGGING
-static PRLogModuleInfo *sFontlistLog = nullptr;
-static PRLogModuleInfo *sFontInitLog = nullptr;
-static PRLogModuleInfo *sTextrunLog = nullptr;
-static PRLogModuleInfo *sTextrunuiLog = nullptr;
-static PRLogModuleInfo *sCmapDataLog = nullptr;
-#endif
+// The color mangement preferences to watch
+static const char* kObservedCMSPrefs[] = {
+  kCMSPrefNameForcesRGB,
+  kCMSPrefNameMode,
+  kCMSPrefNameEnablev4,
+  kCMSPrefNameRenderingIntent,
+  kCMSPrefNameDisplayProfile,
+  nullptr
+};
 
 /* Class to listen for pref changes so that chrome code can dynamically
    force sRGB as an output profile. See Bug #452125. */
-class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
-                                       public nsSupportsWeakReference
-{
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-
-NS_IMPL_ISUPPORTS2(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
-
-NS_IMETHODIMP
-SRGBOverrideObserver::Observe(nsISupports *aSubject,
-                              const char *aTopic,
-                              const PRUnichar *someData)
-{
-    NS_ASSERTION(NS_strcmp(someData,
-                   NS_LITERAL_STRING("gfx.color_mangement.force_srgb").get()),
-                 "Restarting CMS on wrong pref!");
-    ShutdownCMS();
-    return NS_OK;
-}
-
-#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
-
-#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
-#define HARFBUZZ_SCRIPTS_DEFAULT  mozilla::unicode::SHAPING_DEFAULT
-#define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
-
-#define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
-
-#define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
-
-#define BIDI_NUMERAL_PREF "bidi.numeral"
-
-static const char* kObservedPrefs[] = {
-    "gfx.downloadable_fonts.",
-    "gfx.font_rendering.",
-    "bidi.numeral",
-    nullptr
-};
-
-class FontPrefsObserver MOZ_FINAL : public nsIObserver
-{
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-
-NS_IMPL_ISUPPORTS1(FontPrefsObserver, nsIObserver)
-
-NS_IMETHODIMP
-FontPrefsObserver::Observe(nsISupports *aSubject,
-                           const char *aTopic,
-                           const PRUnichar *someData)
-{
-    if (!someData) {
-        NS_ERROR("font pref observer code broken");
-        return NS_ERROR_UNEXPECTED;
-    }
-    NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
-    gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
-
-    return NS_OK;
-}
-
-class OrientationSyncPrefsObserver MOZ_FINAL : public nsIObserver
+class CMSPrefsObserver MOZ_FINAL : public nsIObserver,
+                                   public nsSupportsWeakReference
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 };
 
-NS_IMPL_ISUPPORTS1(OrientationSyncPrefsObserver, nsIObserver)
+NS_IMPL_ISUPPORTS2(CMSPrefsObserver, nsIObserver, nsISupportsWeakReference)
 
 NS_IMETHODIMP
-OrientationSyncPrefsObserver::Observe(nsISupports *aSubject,
-                                      const char *aTopic,
-                                      const PRUnichar *someData)
-{
-    if (!someData) {
-        NS_ERROR("orientation sync pref observer broken");
-        return NS_ERROR_UNEXPECTED;
-    }
-    NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
-    gfxPlatform::GetPlatform()->OrientationSyncPrefsObserverChanged();
-
-    return NS_OK;
-}
-
-// this needs to match the list of pref font.default.xx entries listed in all.js!
-// the order *must* match the order in eFontPrefLang
-static const char *gPrefLangNames[] = {
-    "x-western",
-    "x-central-euro",
-    "ja",
-    "zh-TW",
-    "zh-CN",
-    "zh-HK",
-    "ko",
-    "x-cyrillic",
-    "x-baltic",
-    "el",
-    "tr",
-    "th",
-    "he",
-    "ar",
-    "x-devanagari",
-    "x-tamil",
-    "x-armn",
-    "x-beng",
-    "x-cans",
-    "x-ethi",
-    "x-geor",
-    "x-gujr",
-    "x-guru",
-    "x-khmr",
-    "x-mlym",
-    "x-orya",
-    "x-telu",
-    "x-knda",
-    "x-sinh",
-    "x-tibt",
-    "x-unicode",
-    "x-user-def"
-};
-
-gfxPlatform::gfxPlatform()
-  : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
-                                 &gfxPlatform::GetAzureBackendInfo)
-  , mDrawLayerBorders(false)
-  , mDrawTileBorders(false)
-  , mDrawBigImageBorders(false)
-{
-    mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
-    mAllowDownloadableFonts = UNINITIALIZED_VALUE;
-    mFallbackUsesCmaps = UNINITIALIZED_VALUE;
-
-    mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
-    mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
-    mBidiNumeralOption = UNINITIALIZED_VALUE;
-
-    mLayersPreferMemoryOverShmem =
-        XRE_GetProcessType() == GeckoProcessType_Default &&
-        Preferences::GetBool("layers.prefer-memory-over-shmem", true);
-
-    mLayersUseDeprecated =
-        Preferences::GetBool("layers.use-deprecated-textures", true);
-
-    Preferences::AddBoolVarCache(&mDrawLayerBorders,
-                                 "layers.draw-borders",
-                                 false);
-    Preferences::AddBoolVarCache(&mDrawTileBorders,
-                                 "layers.draw-tile-borders",
-                                 false);
-    Preferences::AddBoolVarCache(&mDrawBigImageBorders,
-                                 "layers.draw-bigimage-borders",
-                                 false);
-
-    uint32_t canvasMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA);
-    uint32_t contentMask = 0;
-    InitBackendPrefs(canvasMask, contentMask);
-}
-
-gfxPlatform*
-gfxPlatform::GetPlatform()
-{
-    if (!gPlatform) {
-        Init();
-    }
-    return gPlatform;
-}
-
-int RecordingPrefChanged(const char *aPrefName, void *aClosure)
-{
-  if (Preferences::GetBool("gfx.2d.recording", false)) {
-    nsAutoCString fileName;
-    nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
-
-    if (prefFileName) {
-      fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
-    } else {
-      fileName.AssignLiteral("browserrecording.aer");
-    }
-
-    gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
-    Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
-  } else {
-    Factory::SetGlobalEventRecorder(nullptr);
-  }
-
-  return 0;
-}
-
-void
-gfxPlatform::Init()
+CMSPrefsObserver::Observe(nsISupports*, const char*, const PRUnichar *aData)
 {
-    if (gEverInitialized) {
-        NS_RUNTIMEABORT("Already started???");
-    }
-    gEverInitialized = true;
-
-#ifdef PR_LOGGING
-    sFontlistLog = PR_NewLogModule("fontlist");;
-    sFontInitLog = PR_NewLogModule("fontinit");;
-    sTextrunLog = PR_NewLogModule("textrun");;
-    sTextrunuiLog = PR_NewLogModule("textrunui");;
-    sCmapDataLog = PR_NewLogModule("cmapdata");;
-#endif
-
-    gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
-
-    /* Initialize the GfxInfo service.
-     * Note: we can't call functions on GfxInfo that depend
-     * on gPlatform until after it has been initialized
-     * below. GfxInfo initialization annotates our
-     * crash reports so we want to do it before
-     * we try to load any drivers and do device detection
-     * incase that code crashes. See bug #591561. */
-    nsCOMPtr<nsIGfxInfo> gfxInfo;
-    /* this currently will only succeed on Windows */
-    gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-
-#if defined(XP_WIN)
-    gPlatform = new gfxWindowsPlatform;
-#elif defined(XP_MACOSX)
-    gPlatform = new gfxPlatformMac;
-#elif defined(MOZ_WIDGET_GTK)
-    gPlatform = new gfxPlatformGtk;
-#elif defined(MOZ_WIDGET_QT)
-    gPlatform = new gfxQtPlatform;
-#elif defined(XP_OS2)
-    gPlatform = new gfxOS2Platform;
-#elif defined(ANDROID)
-    gPlatform = new gfxAndroidPlatform;
-#else
-    #error "No gfxPlatform implementation available"
-#endif
-
-#ifdef DEBUG
-    mozilla::gl::GLContext::StaticInit();
-#endif
-
-    bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
-                                       GetPrefLayersOffMainThreadCompositionEnabled();
-
-    if (!OffMainThreadCompositionRequired()) {
-      useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
-    }
-
-    if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
-        CompositorParent::StartUp();
-        if (Preferences::GetBool("layers.async-video.enabled", false)) {
-            ImageBridgeChild::StartUp();
-        }
-    }
-
-    nsresult rv;
-
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
-    rv = gfxPlatformFontList::Init();
-    if (NS_FAILED(rv)) {
-        NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
-    }
-#endif
-
-    gPlatform->mScreenReferenceSurface =
-        gPlatform->CreateOffscreenSurface(gfxIntSize(1,1),
-                                          gfxASurface::CONTENT_COLOR_ALPHA);
-    if (!gPlatform->mScreenReferenceSurface) {
-        NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
-    }
-
-    rv = gfxFontCache::Init();
-    if (NS_FAILED(rv)) {
-        NS_RUNTIMEABORT("Could not initialize gfxFontCache");
-    }
-
-    /* Pref migration hook. */
-    MigratePrefs();
-
-    /* Create and register our CMS Override observer. */
-    gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
-    Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
-
-    gPlatform->mFontPrefsObserver = new FontPrefsObserver();
-    Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
-
-    gPlatform->mOrientationSyncPrefsObserver = new OrientationSyncPrefsObserver();
-    Preferences::AddStrongObserver(gPlatform->mOrientationSyncPrefsObserver, "layers.orientation.sync.timeout");
-
-    gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
-
-    mozilla::Preferences::AddBoolVarCache(&gPlatform->mWidgetUpdateFlashing,
-                                          "nglayout.debug.widget_update_flashing");
-
-    mozilla::gl::GLContext::PlatformStartup();
-
-#ifdef MOZ_WIDGET_ANDROID
-    // Texture pool init
-    mozilla::gl::TexturePoolOGL::Init();
-#endif
-
-    // Force registration of the gfx component, thus arranging for
-    // ::Shutdown to be called.
-    nsCOMPtr<nsISupports> forceReg
-        = do_CreateInstance("@mozilla.org/gfx/init;1");
-
-    Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
-
-    gPlatform->mOrientationSyncMillis = Preferences::GetUint("layers.orientation.sync.timeout", (uint32_t)0);
-
-    mozilla::Preferences::AddBoolVarCache(&sDrawFrameCounter,
-                                          "layers.frame-counter",
-                                          false);
-
-    CreateCMSOutputProfile();
-}
-
-void
-gfxPlatform::Shutdown()
-{
-    // These may be called before the corresponding subsystems have actually
-    // started up. That's OK, they can handle it.
-    gfxFontCache::Shutdown();
-    gfxFontGroup::Shutdown();
-    gfxGraphiteShaper::Shutdown();
-#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
-    gfxPlatformFontList::Shutdown();
-#endif
-
-    // Free the various non-null transforms and loaded profiles
-    ShutdownCMS();
-
-    // In some cases, gPlatform may not be created but Shutdown() called,
-    // e.g., during xpcshell tests.
-    if (gPlatform) {
-        /* Unregister our CMS Override callback. */
-        NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
-        Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
-        gPlatform->mSRGBOverrideObserver = nullptr;
-
-        NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
-        Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
-        gPlatform->mFontPrefsObserver = nullptr;
-    }
-
-#ifdef MOZ_WIDGET_ANDROID
-    // Shut down the texture pool
-    mozilla::gl::TexturePoolOGL::Shutdown();
-#endif
-
-    // Shut down the default GL context provider.
-    mozilla::gl::GLContextProvider::Shutdown();
-
-#if defined(XP_WIN)
-    // The above shutdown calls operate on the available context providers on
-    // most platforms.  Windows is a "special snowflake", though, and has three
-    // context providers available, so we have to shut all of them down.
-    // We should only support the default GL provider on Windows; then, this
-    // could go away. Unfortunately, we currently support WGL (the default) for
-    // WebGL on Optimus.
-    mozilla::gl::GLContextProviderEGL::Shutdown();
-#endif
-
-    // This will block this thread untill the ImageBridge protocol is completely
-    // deleted.
-    ImageBridgeChild::ShutDown();
-
-    CompositorParent::ShutDown();
-
-    delete gGfxPlatformPrefsLock;
-
-    delete gPlatform;
-    gPlatform = nullptr;
-}
-
-gfxPlatform::~gfxPlatform()
-{
-    mScreenReferenceSurface = nullptr;
-
-    // The cairo folks think we should only clean up in debug builds,
-    // but we're generally in the habit of trying to shut down as
-    // cleanly as possible even in production code, so call this
-    // cairo_debug_* function unconditionally.
-    //
-    // because cairo can assert and thus crash on shutdown, don't do this in release builds
-#if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND)
-#ifdef USE_SKIA
-    // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
-    // Cairo objects e.g. through SkCairoFTTypeface
-    SkGraphics::Term();
-#endif
-
-#if MOZ_TREE_CAIRO
-    cairo_debug_reset_static_data();
-#endif
-#endif
-
-#if 0
-    // It would be nice to do this (although it might need to be after
-    // the cairo shutdown that happens in ~gfxPlatform).  It even looks
-    // idempotent.  But it has fatal assertions that fire if stuff is
-    // leaked, and we hit them.
-    FcFini();
-#endif
-}
-
-bool
-gfxPlatform::PreferMemoryOverShmem() const {
-  MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
-  return mLayersPreferMemoryOverShmem;
-}
-
-already_AddRefed<gfxASurface>
-gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                         gfxASurface::gfxContentType aContentType)
-{
-  nsRefPtr<gfxASurface> newSurface;
-  newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
-
-  return newSurface.forget();
-}
-
-already_AddRefed<gfxASurface>
-gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
-                           gfxASurface::gfxImageFormat format)
-{
-    const gfxIntSize& surfaceSize = aSurface->GetSize();
-
-#ifdef XP_WIN
-    if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
-        gfxWindowsPlatform::RENDER_DIRECT2D) {
-        return nullptr;
-    }
-#endif
-    nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format));
-    if (!optSurface || optSurface->CairoStatus() != 0)
-        return nullptr;
-
-    gfxContext tmpCtx(optSurface);
-    tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
-    tmpCtx.SetSource(aSurface);
-    tmpCtx.Paint();
-
-    return optSurface.forget();
-}
-
-cairo_user_data_key_t kDrawTarget;
-
-RefPtr<DrawTarget>
-gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
-{
-  RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize);
-  aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
-  return drawTarget;
-}
-
-// This is a temporary function used by ContentClient to build a DrawTarget
-// around the gfxASurface. This should eventually be replaced by plumbing
-// the DrawTarget through directly
-RefPtr<DrawTarget>
-gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize)
-{
-#ifdef XP_MACOSX
-  // this is a bit of a hack that assumes that the buffer associated with the CGContext
-  // will live around long enough that nothing bad will happen.
-  if (aSurface->GetType() == gfxASurface::SurfaceTypeQuartz) {
-    return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
-  }
-#endif
-  MOZ_CRASH();
-  return nullptr;
-}
-
-
-cairo_user_data_key_t kSourceSurface;
-
-/**
- * Record the backend that was used to construct the SourceSurface.
- * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
- * we check to make sure the DrawTarget's backend matches the backend
- * for the cached SourceSurface, and only use it if they match. This
- * can avoid expensive and unnecessary readbacks.
- */
-struct SourceSurfaceUserData
-{
-  RefPtr<SourceSurface> mSrcSurface;
-  BackendType mBackendType;
-};
-
-void SourceBufferDestroy(void *srcSurfUD)
-{
-  delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
+  return gfxColorManagement::InstanceNC().PreferencesModified(aData);
 }
 
-#if MOZ_TREE_CAIRO
-void SourceSnapshotDetached(cairo_surface_t *nullSurf)
-{
-  gfxImageSurface* origSurf =
-    static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
-
-  origSurf->SetData(&kSourceSurface, nullptr, nullptr);
-}
-#else
-void SourceSnapshotDetached(void *nullSurf)
-{
-  gfxImageSurface* origSurf = static_cast<gfxImageSurface*>(nullSurf);
-  origSurf->SetData(&kSourceSurface, nullptr, nullptr);
-}
-#endif
-
-void
-gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
-{
-  aSurface->SetData(&kSourceSurface, nullptr, nullptr);
-}
-
-RefPtr<SourceSurface>
-gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
+const gfxColorManagement&
+gfxColorManagement::Instance()
 {
-  void *userData = aSurface->GetData(&kSourceSurface);
-
-  if (userData) {
-    SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
-
-    if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetType()) {
-      return surf->mSrcSurface;
-    }
-    // We can just continue here as when setting new user data the destroy
-    // function will be called for the old user data.
-  }
-
-  SurfaceFormat format;
-  if (aSurface->GetContentType() == gfxASurface::CONTENT_ALPHA) {
-    format = FORMAT_A8;
-  } else if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR) {
-    format = FORMAT_B8G8R8X8;
-  } else {
-    format = FORMAT_B8G8R8A8;
-  }
-
-  RefPtr<SourceSurface> srcBuffer;
-
-#ifdef XP_WIN
-  if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D &&
-      format != FORMAT_A8) {
-    NativeSurface surf;
-    surf.mFormat = format;
-    surf.mType = NATIVE_SURFACE_D3D10_TEXTURE;
-    surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
-    mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
-    if (dt) {
-      dt->Flush();
-    }
-    srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
-  } else
-#endif
-  if (aSurface->CairoSurface() && aTarget->GetType() == BACKEND_CAIRO) {
-    // If this is an xlib cairo surface we don't want to fetch it into memory
-    // because this is a major slow down.
-    NativeSurface surf;
-    surf.mFormat = format;
-    surf.mType = NATIVE_SURFACE_CAIRO_SURFACE;
-    surf.mSurface = aSurface->CairoSurface();
-    srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
-
-    if (srcBuffer) {
-      // It's cheap enough to make a new one so we won't keep it around and
-      // keeping it creates a cycle.
-      return srcBuffer;
-    }
+  if (!sInstance) {
+    sInstance = new gfxColorManagement;
   }
-
-  if (!srcBuffer) {
-    nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
-
-    bool isWin32ImageSurf = imgSurface &&
-                            aSurface->GetType() == gfxASurface::SurfaceTypeWin32;
-
-    if (!imgSurface) {
-      imgSurface = new gfxImageSurface(aSurface->GetSize(), OptimalFormatForContent(aSurface->GetContentType()));
-      nsRefPtr<gfxContext> ctx = new gfxContext(imgSurface);
-      ctx->SetSource(aSurface);
-      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-      ctx->Paint();
-    }
-
-    gfxImageFormat cairoFormat = imgSurface->Format();
-    switch(cairoFormat) {
-      case gfxASurface::ImageFormatARGB32:
-        format = FORMAT_B8G8R8A8;
-        break;
-      case gfxASurface::ImageFormatRGB24:
-        format = FORMAT_B8G8R8X8;
-        break;
-      case gfxASurface::ImageFormatA8:
-        format = FORMAT_A8;
-        break;
-      case gfxASurface::ImageFormatRGB16_565:
-        format = FORMAT_R5G6B5;
-        break;
-      default:
-        NS_RUNTIMEABORT("Invalid surface format!");
-    }
-
-    IntSize size = IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height);
-    srcBuffer = aTarget->CreateSourceSurfaceFromData(imgSurface->Data(),
-                                                     size,
-                                                     imgSurface->Stride(),
-                                                     format);
-
-    if (!srcBuffer) {
-      // We need to check if our gfxASurface will keep the underlying data
-      // alive. This is true if gfxASurface actually -is- an ImageSurface or
-      // if it is a gfxWindowsSurface which supports GetAsImageSurface.
-      if (imgSurface != aSurface && !isWin32ImageSurf) {
-        // This shouldn't happen for now, it can be easily supported by making
-        // a copy. For now let's just abort.
-        NS_RUNTIMEABORT("Attempt to create unsupported SourceSurface from"
-            "non-image surface.");
-        return nullptr;
-      }
-
-      srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
-                                                           imgSurface->Stride(),
-                                                           size, format);
-
-    }
-
-#if MOZ_TREE_CAIRO
-    cairo_surface_t *nullSurf =
-	cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
-    cairo_surface_set_user_data(nullSurf,
-                                &kSourceSurface,
-                                imgSurface,
-                                nullptr);
-    cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
-    cairo_surface_destroy(nullSurf);
-#else
-    cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
-#endif
-  }
-
-  SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
-  srcSurfUD->mBackendType = aTarget->GetType();
-  srcSurfUD->mSrcSurface = srcBuffer;
-  aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
-
-  return srcBuffer;
-}
-
-TemporaryRef<ScaledFont>
-gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
-{
-  NativeFont nativeFont;
-  nativeFont.mType = NATIVE_FONT_CAIRO_FONT_FACE;
-  nativeFont.mFont = aFont->GetCairoScaledFont();
-  RefPtr<ScaledFont> scaledFont =
-    Factory::CreateScaledFontForNativeFont(nativeFont,
-                                           aFont->GetAdjustedSize());
-  return scaledFont;
-}
-
-cairo_user_data_key_t kDrawSourceSurface;
-static void
-DataSourceSurfaceDestroy(void *dataSourceSurface)
-{
-  static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
-}
-
-cairo_user_data_key_t kDrawTargetForSurface;
-static void
-DataDrawTargetDestroy(void *aTarget)
-{
-  static_cast<DrawTarget*>(aTarget)->Release();
-}
-
-bool
-gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
-{
-  if (!aTarget) {
-    return false;
-  }
-
-  return SupportsAzureContentForType(aTarget->GetType());
-}
-
-bool
-gfxPlatform::UseAcceleratedSkiaCanvas()
-{
-  return Preferences::GetBool("gfx.canvas.azure.accelerated", false) &&
-         mPreferredCanvasBackend == BACKEND_SKIA;
+  return *sInstance;
 }
 
-already_AddRefed<gfxASurface>
-gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
-{
-  if (aTarget->GetType() == BACKEND_CAIRO) {
-    cairo_surface_t* csurf =
-      static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE));
-    return gfxASurface::Wrap(csurf);
-  }
-
-  // The semantics of this part of the function are sort of weird. If we
-  // don't have direct support for the backend, we snapshot the first time
-  // and then return the snapshotted surface for the lifetime of the draw
-  // target. Sometimes it seems like this works out, but it seems like it
-  // might result in no updates ever.
-  RefPtr<SourceSurface> source = aTarget->Snapshot();
-  RefPtr<DataSourceSurface> data = source->GetDataSurface();
-
-  if (!data) {
-    return nullptr;
-  }
-
-  IntSize size = data->GetSize();
-  gfxASurface::gfxImageFormat format = OptimalFormatForContent(ContentForFormat(data->GetFormat()));
-
-
-  nsRefPtr<gfxASurface> surf =
-    new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
-                        data->Stride(), format);
-
-  surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
-  // keep the draw target alive as long as we need its data
-  aTarget->AddRef();
-  surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
-
-  return surf.forget();
-}
-
-RefPtr<DrawTarget>
-gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
-{
-  // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
-  // create the best offscreen surface for the current system and situation. We
-  // can easily take advantage of this for the Cairo backend, so that's what we
-  // do.
-  // mozilla::gfx::Factory can get away without having all this knowledge for
-  // now, but this might need to change in the future (using
-  // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
-  // backends).
-  if (aBackend == BACKEND_CAIRO) {
-    nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(ThebesIntSize(aSize),
-                                                        ContentForFormat(aFormat));
-    if (!surf || surf->CairoStatus()) {
-      return nullptr;
-    }
-
-    return CreateDrawTargetForSurface(surf, aSize);
-  } else {
-    return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
-  }
-}
-
-RefPtr<DrawTarget>
-gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
-{
-  NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
-  RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
-  if (target ||
-      mFallbackCanvasBackend == BACKEND_NONE) {
-    return target;
-  }
-
-  return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
-}
-
-RefPtr<DrawTarget>
-gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
-{
-  NS_ASSERTION(mContentBackend, "No backend.");
-  return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
-}
-
-RefPtr<DrawTarget>
-gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
-{
-  NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
-  return Factory::CreateDrawTargetForData(mPreferredCanvasBackend, aData, aSize, aStride, aFormat);
-}
-
-/* static */ BackendType
-gfxPlatform::BackendTypeForName(const nsCString& aName)
-{
-  if (aName.EqualsLiteral("cairo"))
-    return BACKEND_CAIRO;
-  if (aName.EqualsLiteral("skia"))
-    return BACKEND_SKIA;
-  if (aName.EqualsLiteral("direct2d"))
-    return BACKEND_DIRECT2D;
-  if (aName.EqualsLiteral("cg"))
-    return BACKEND_COREGRAPHICS;
-  return BACKEND_NONE;
-}
-
-nsresult
-gfxPlatform::GetFontList(nsIAtom *aLangGroup,
-                         const nsACString& aGenericFamily,
-                         nsTArray<nsString>& aListOfFonts)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-nsresult
-gfxPlatform::UpdateFontList()
+gfxColorManagement&
+gfxColorManagement::InstanceNC()
 {
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-bool
-gfxPlatform::DownloadableFontsEnabled()
-{
-    if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
-        mAllowDownloadableFonts =
-            Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
-    }
-
-    return mAllowDownloadableFonts;
-}
-
-bool
-gfxPlatform::UseCmapsDuringSystemFallback()
-{
-    if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
-        mFallbackUsesCmaps =
-            Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
-    }
-
-    return mFallbackUsesCmaps;
-}
-
-bool
-gfxPlatform::OpenTypeSVGEnabled()
-{
-    if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
-        mOpenTypeSVGEnabled =
-            Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
-    }
-
-    return mOpenTypeSVGEnabled > 0;
-}
-
-bool
-gfxPlatform::UseGraphiteShaping()
-{
-    if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
-        mGraphiteShapingEnabled =
-            Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
-    }
-
-    return mGraphiteShapingEnabled;
-}
-
-bool
-gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
-{
-    if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
-        mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
-    }
-
-    int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
-
-    return (mUseHarfBuzzScripts & shapingType) != 0;
-}
-
-gfxFontEntry*
-gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                              const uint8_t *aFontData,
-                              uint32_t aLength)
-{
-    // Default implementation does not handle activating downloaded fonts;
-    // just free the data and return.
-    // Platforms that support @font-face must override this,
-    // using the data to instantiate the font, and taking responsibility
-    // for freeing it when no longer required.
-    if (aFontData) {
-        NS_Free((void*)aFontData);
-    }
-    return nullptr;
-}
-
-static void
-AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
-{
-    NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
-
-    nsAutoCString prefName, langGroupString;
-
-    aLangGroup->ToUTF8String(langGroupString);
-
-    nsAutoCString genericDotLang;
-    if (aGenericName) {
-        genericDotLang.Assign(aGenericName);
-    } else {
-        prefName.AssignLiteral("font.default.");
-        prefName.Append(langGroupString);
-        genericDotLang = Preferences::GetCString(prefName.get());
-    }
-
-    genericDotLang.AppendLiteral(".");
-    genericDotLang.Append(langGroupString);
-
-    // fetch font.name.xxx value
-    prefName.AssignLiteral("font.name.");
-    prefName.Append(genericDotLang);
-    nsAdoptingString nameValue = Preferences::GetString(prefName.get());
-    if (nameValue) {
-        if (!aFonts.IsEmpty())
-            aFonts.AppendLiteral(", ");
-        aFonts += nameValue;
-    }
-
-    // fetch font.name-list.xxx value
-    prefName.AssignLiteral("font.name-list.");
-    prefName.Append(genericDotLang);
-    nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
-    if (nameListValue && !nameListValue.Equals(nameValue)) {
-        if (!aFonts.IsEmpty())
-            aFonts.AppendLiteral(", ");
-        aFonts += nameListValue;
-    }
+  if (!sInstance) {
+    sInstance = new gfxColorManagement;
+  }
+  return *sInstance;
 }
 
 void
-gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
-{
-    aFonts.Truncate();
-
-    AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
-    if (aAppendUnicode)
-        AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
-}
-
-bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
-                                    void *aClosure)
-{
-    NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
-
-    uint32_t    i;
-    for (i = 0; i < aLangArrayLen; i++) {
-        eFontPrefLang prefLang = aLangArray[i];
-        const char *langGroup = GetPrefLangName(prefLang);
-
-        nsAutoCString prefName;
-
-        prefName.AssignLiteral("font.default.");
-        prefName.Append(langGroup);
-        nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
-
-        genericDotLang.AppendLiteral(".");
-        genericDotLang.Append(langGroup);
-
-        // fetch font.name.xxx value
-        prefName.AssignLiteral("font.name.");
-        prefName.Append(genericDotLang);
-        nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
-        if (nameValue) {
-            if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
-                return false;
-        }
-
-        // fetch font.name-list.xxx value
-        prefName.AssignLiteral("font.name-list.");
-        prefName.Append(genericDotLang);
-        nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
-        if (nameListValue && !nameListValue.Equals(nameValue)) {
-            const char kComma = ',';
-            const char *p, *p_end;
-            nsAutoCString list(nameListValue);
-            list.BeginReading(p);
-            list.EndReading(p_end);
-            while (p < p_end) {
-                while (nsCRT::IsAsciiSpace(*p)) {
-                    if (++p == p_end)
-                        break;
-                }
-                if (p == p_end)
-                    break;
-                const char *start = p;
-                while (++p != p_end && *p != kComma)
-                    /* nothing */ ;
-                nsAutoCString fontName(Substring(start, p));
-                fontName.CompressWhitespace(false, true);
-                if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
-                    return false;
-                p++;
-            }
-        }
-    }
-
-    return true;
-}
-
-eFontPrefLang
-gfxPlatform::GetFontPrefLangFor(const char* aLang)
-{
-    if (!aLang || !aLang[0])
-        return eFontPrefLang_Others;
-    for (uint32_t i = 0; i < uint32_t(eFontPrefLang_LangCount); ++i) {
-        if (!PL_strcasecmp(gPrefLangNames[i], aLang))
-            return eFontPrefLang(i);
-    }
-    return eFontPrefLang_Others;
-}
-
-eFontPrefLang
-gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
-{
-    if (!aLang)
-        return eFontPrefLang_Others;
-    nsAutoCString lang;
-    aLang->ToUTF8String(lang);
-    return GetFontPrefLangFor(lang.get());
-}
-
-const char*
-gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
-{
-    if (uint32_t(aLang) < uint32_t(eFontPrefLang_AllCount))
-        return gPrefLangNames[uint32_t(aLang)];
-    return nullptr;
-}
-
-eFontPrefLang
-gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
-{
-    switch (aUnicodeRange) {
-        case kRangeSetLatin:   return eFontPrefLang_Western;
-        case kRangeCyrillic:   return eFontPrefLang_Cyrillic;
-        case kRangeGreek:      return eFontPrefLang_Greek;
-        case kRangeTurkish:    return eFontPrefLang_Turkish;
-        case kRangeHebrew:     return eFontPrefLang_Hebrew;
-        case kRangeArabic:     return eFontPrefLang_Arabic;
-        case kRangeBaltic:     return eFontPrefLang_Baltic;
-        case kRangeThai:       return eFontPrefLang_Thai;
-        case kRangeKorean:     return eFontPrefLang_Korean;
-        case kRangeJapanese:   return eFontPrefLang_Japanese;
-        case kRangeSChinese:   return eFontPrefLang_ChineseCN;
-        case kRangeTChinese:   return eFontPrefLang_ChineseTW;
-        case kRangeDevanagari: return eFontPrefLang_Devanagari;
-        case kRangeTamil:      return eFontPrefLang_Tamil;
-        case kRangeArmenian:   return eFontPrefLang_Armenian;
-        case kRangeBengali:    return eFontPrefLang_Bengali;
-        case kRangeCanadian:   return eFontPrefLang_Canadian;
-        case kRangeEthiopic:   return eFontPrefLang_Ethiopic;
-        case kRangeGeorgian:   return eFontPrefLang_Georgian;
-        case kRangeGujarati:   return eFontPrefLang_Gujarati;
-        case kRangeGurmukhi:   return eFontPrefLang_Gurmukhi;
-        case kRangeKhmer:      return eFontPrefLang_Khmer;
-        case kRangeMalayalam:  return eFontPrefLang_Malayalam;
-        case kRangeOriya:      return eFontPrefLang_Oriya;
-        case kRangeTelugu:     return eFontPrefLang_Telugu;
-        case kRangeKannada:    return eFontPrefLang_Kannada;
-        case kRangeSinhala:    return eFontPrefLang_Sinhala;
-        case kRangeTibetan:    return eFontPrefLang_Tibetan;
-        case kRangeSetCJK:     return eFontPrefLang_CJKSet;
-        default:               return eFontPrefLang_Others;
-    }
-}
-
-bool
-gfxPlatform::IsLangCJK(eFontPrefLang aLang)
-{
-    switch (aLang) {
-        case eFontPrefLang_Japanese:
-        case eFontPrefLang_ChineseTW:
-        case eFontPrefLang_ChineseCN:
-        case eFontPrefLang_ChineseHK:
-        case eFontPrefLang_Korean:
-        case eFontPrefLang_CJKSet:
-            return true;
-        default:
-            return false;
-    }
-}
-
-mozilla::layers::DiagnosticTypes
-gfxPlatform::GetLayerDiagnosticTypes()
-{
-  mozilla::layers::DiagnosticTypes type = DIAGNOSTIC_NONE;
-  if (mDrawLayerBorders) {
-    type |= mozilla::layers::DIAGNOSTIC_LAYER_BORDERS;
-  }
-  if (mDrawTileBorders) {
-    type |= mozilla::layers::DIAGNOSTIC_TILE_BORDERS;
-  }
-  if (mDrawBigImageBorders) {
-    type |= mozilla::layers::DIAGNOSTIC_BIGIMAGE_BORDERS;
-  }
-  return type;
-}
-
-bool
-gfxPlatform::DrawFrameCounter()
-{
-    return sDrawFrameCounter;
-}
-
-void
-gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
-{
-    if (IsLangCJK(aCharLang)) {
-        AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
-    } else {
-        AppendPrefLang(aPrefLangs, aLen, aCharLang);
-    }
-
-    AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
-}
-
-void
-gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
-{
-    // prefer the lang specified by the page *if* CJK
-    if (IsLangCJK(aPageLang)) {
-        AppendPrefLang(aPrefLangs, aLen, aPageLang);
-    }
-
-    // if not set up, set up the default CJK order, based on accept lang settings and locale
-    if (mCJKPrefLangs.Length() == 0) {
-
-        // temp array
-        eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
-        uint32_t tempLen = 0;
-
-        // Add the CJK pref fonts from accept languages, the order should be same order
-        nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
-        if (!list.IsEmpty()) {
-            const char kComma = ',';
-            const char *p, *p_end;
-            list.BeginReading(p);
-            list.EndReading(p_end);
-            while (p < p_end) {
-                while (nsCRT::IsAsciiSpace(*p)) {
-                    if (++p == p_end)
-                        break;
-                }
-                if (p == p_end)
-                    break;
-                const char *start = p;
-                while (++p != p_end && *p != kComma)
-                    /* nothing */ ;
-                nsAutoCString lang(Substring(start, p));
-                lang.CompressWhitespace(false, true);
-                eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
-                switch (fpl) {
-                    case eFontPrefLang_Japanese:
-                    case eFontPrefLang_Korean:
-                    case eFontPrefLang_ChineseCN:
-                    case eFontPrefLang_ChineseHK:
-                    case eFontPrefLang_ChineseTW:
-                        AppendPrefLang(tempPrefLangs, tempLen, fpl);
-                        break;
-                    default:
-                        break;
-                }
-                p++;
-            }
-        }
-
-        do { // to allow 'break' to abort this block if a call fails
-            nsresult rv;
-            nsCOMPtr<nsILocaleService> ls =
-                do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
-            if (NS_FAILED(rv))
-                break;
-
-            nsCOMPtr<nsILocale> appLocale;
-            rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
-            if (NS_FAILED(rv))
-                break;
-
-            nsString localeStr;
-            rv = appLocale->
-                GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
-            if (NS_FAILED(rv))
-                break;
-
-            const nsAString& lang = Substring(localeStr, 0, 2);
-            if (lang.EqualsLiteral("ja")) {
-                AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
-            } else if (lang.EqualsLiteral("zh")) {
-                const nsAString& region = Substring(localeStr, 3, 2);
-                if (region.EqualsLiteral("CN")) {
-                    AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
-                } else if (region.EqualsLiteral("TW")) {
-                    AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
-                } else if (region.EqualsLiteral("HK")) {
-                    AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
-                }
-            } else if (lang.EqualsLiteral("ko")) {
-                AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
-            }
-        } while (0);
-
-        // last resort... (the order is same as old gfx.)
-        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
-        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
-        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
-        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
-        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
-
-        // copy into the cached array
-        uint32_t j;
-        for (j = 0; j < tempLen; j++) {
-            mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
-        }
-    }
-
-    // append in cached CJK langs
-    uint32_t  i, numCJKlangs = mCJKPrefLangs.Length();
-
-    for (i = 0; i < numCJKlangs; i++) {
-        AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
-    }
-
-}
-
-void
-gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
-{
-    if (aLen >= kMaxLenPrefLangList) return;
-
-    // make sure
-    uint32_t  i = 0;
-    while (i < aLen && aPrefLangs[i] != aAddLang) {
-        i++;
-    }
-
-    if (i == aLen) {
-        aPrefLangs[aLen] = aAddLang;
-        aLen++;
-    }
-}
-
-void
-gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask)
-{
-    mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
-    if (!mPreferredCanvasBackend) {
-      mPreferredCanvasBackend = BACKEND_CAIRO;
-    }
-    mFallbackCanvasBackend = GetCanvasBackendPref(aCanvasBitmask & ~(1 << mPreferredCanvasBackend));
-
-    mContentBackendBitmask = aContentBitmask;
-    mContentBackend = GetContentBackendPref(mContentBackendBitmask);
-}
-
-/* static */ BackendType
-gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
-{
-    return GetBackendPref(nullptr, "gfx.canvas.azure.backends", aBackendBitmask);
-}
-
-/* static */ BackendType
-gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
-{
-    return GetBackendPref("gfx.content.azure.enabled", "gfx.content.azure.backends", aBackendBitmask);
-}
-
-/* static */ BackendType
-gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPrefName, uint32_t &aBackendBitmask)
-{
-    if (aEnabledPrefName &&
-        !Preferences::GetBool(aEnabledPrefName, false)) {
-        aBackendBitmask = 0;
-        return BACKEND_NONE;
-    }
-
-    nsTArray<nsCString> backendList;
-    nsCString prefString;
-    if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
-        ParseString(prefString, ',', backendList);
-    }
-
-    uint32_t allowedBackends = 0;
-    BackendType result = BACKEND_NONE;
-    for (uint32_t i = 0; i < backendList.Length(); ++i) {
-        BackendType type = BackendTypeForName(backendList[i]);
-        if ((1 << type) & aBackendBitmask) {
-            allowedBackends |= (1 << type);
-            if (result == BACKEND_NONE) {
-                result = type;
-            }
-        }
-    }
-
-    aBackendBitmask = allowedBackends;
-    return result;
-}
-
-bool
-gfxPlatform::UseProgressiveTilePainting()
-{
-    static bool sUseProgressiveTilePainting;
-    static bool sUseProgressiveTilePaintingPrefCached = false;
-
-    if (!sUseProgressiveTilePaintingPrefCached) {
-        sUseProgressiveTilePaintingPrefCached = true;
-        mozilla::Preferences::AddBoolVarCache(&sUseProgressiveTilePainting,
-                                              "layers.progressive-paint",
-                                              false);
-    }
-
-    return sUseProgressiveTilePainting;
-}
-
-bool
-gfxPlatform::UseLowPrecisionBuffer()
-{
-    static bool sUseLowPrecisionBuffer;
-    static bool sUseLowPrecisionBufferPrefCached = false;
-
-    if (!sUseLowPrecisionBufferPrefCached) {
-        sUseLowPrecisionBufferPrefCached = true;
-        mozilla::Preferences::AddBoolVarCache(&sUseLowPrecisionBuffer,
-                                              "layers.low-precision-buffer",
-                                              false);
-    }
-
-    return sUseLowPrecisionBuffer;
-}
-
-float
-gfxPlatform::GetLowPrecisionResolution()
-{
-    static float sLowPrecisionResolution;
-    static bool sLowPrecisionResolutionPrefCached = false;
-
-    if (!sLowPrecisionResolutionPrefCached) {
-        int32_t lowPrecisionResolution = 250;
-        sLowPrecisionResolutionPrefCached = true;
-        mozilla::Preferences::AddIntVarCache(&lowPrecisionResolution,
-                                             "layers.low-precision-resolution",
-                                             250);
-        sLowPrecisionResolution = lowPrecisionResolution / 1000.f;
-    }
-
-    return sLowPrecisionResolution;
-}
-
-bool
-gfxPlatform::UseReusableTileStore()
-{
-    static bool sUseReusableTileStore;
-    static bool sUseReusableTileStorePrefCached = false;
-
-    if (!sUseReusableTileStorePrefCached) {
-        sUseReusableTileStorePrefCached = true;
-        mozilla::Preferences::AddBoolVarCache(&sUseReusableTileStore,
-                                              "layers.reuse-invalid-tiles",
-                                              false);
-    }
-
-    return sUseReusableTileStore;
-}
-
-bool
-gfxPlatform::OffMainThreadCompositingEnabled()
-{
-  return XRE_GetProcessType() == GeckoProcessType_Default ?
-    CompositorParent::CompositorLoop() != nullptr :
-    CompositorChild::ChildProcessHasCompositor();
-}
-
-eCMSMode
-gfxPlatform::GetCMSMode()
+gfxColorManagement::Destroy()
 {
-    if (gCMSInitialized == false) {
-        gCMSInitialized = true;
-        nsresult rv;
-
-        int32_t mode;
-        rv = Preferences::GetInt("gfx.color_management.mode", &mode);
-        if (NS_SUCCEEDED(rv) && (mode >= 0) && (mode < eCMSMode_AllCount)) {
-            gCMSMode = static_cast<eCMSMode>(mode);
-        }
-
-        bool enableV4;
-        rv = Preferences::GetBool("gfx.color_management.enablev4", &enableV4);
-        if (NS_SUCCEEDED(rv) && enableV4) {
-            qcms_enable_iccv4();
-        }
-    }
-    return gCMSMode;
-}
-
-int
-gfxPlatform::GetRenderingIntent()
-{
-    if (gCMSIntent == -2) {
-
-        /* Try to query the pref system for a rendering intent. */
-        int32_t pIntent;
-        if (NS_SUCCEEDED(Preferences::GetInt("gfx.color_management.rendering_intent", &pIntent))) {
-            /* If the pref is within range, use it as an override. */
-            if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
-                gCMSIntent = pIntent;
-            }
-            /* If the pref is out of range, use embedded profile. */
-            else {
-                gCMSIntent = -1;
-            }
-        }
-        /* If we didn't get a valid intent from prefs, use the default. */
-        else {
-            gCMSIntent = QCMS_INTENT_DEFAULT;
-        }
-    }
-    return gCMSIntent;
-}
-
-void
-gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
-{
-
-    if (transform) {
-        /* we want the bytes in RGB order */
-#ifdef IS_LITTLE_ENDIAN
-        /* ABGR puts the bytes in |RGBA| order on little endian */
-        uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
-        qcms_transform_data(transform,
-                       (uint8_t *)&packed, (uint8_t *)&packed,
-                       1);
-        out.~gfxRGBA();
-        new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
-#else
-        /* ARGB puts the bytes in |ARGB| order on big endian */
-        uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
-        /* add one to move past the alpha byte */
-        qcms_transform_data(transform,
-                       (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
-                       1);
-        out.~gfxRGBA();
-        new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
-#endif
-    }
-
-    else if (&out != &in)
-        out = in;
-}
-
-qcms_profile *
-gfxPlatform::GetPlatformCMSOutputProfile()
-{
-    return nullptr;
-}
-
-void
-gfxPlatform::CreateCMSOutputProfile()
-{
-    if (!gCMSOutputProfile) {
-        /* Determine if we're using the internal override to force sRGB as
-           an output profile for reftests. See Bug 452125.
-
-           Note that we don't normally (outside of tests) set a
-           default value of this preference, which means nsIPrefBranch::GetBoolPref
-           will typically throw (and leave its out-param untouched).
-         */
-        if (Preferences::GetBool("gfx.color_management.force_srgb", false)) {
-            gCMSOutputProfile = GetCMSsRGBProfile();
-        }
-
-        if (!gCMSOutputProfile) {
-            nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
-            if (!fname.IsEmpty()) {
-                gCMSOutputProfile = qcms_profile_from_path(fname);
-            }
-        }
-
-        if (!gCMSOutputProfile) {
-            gCMSOutputProfile =
-                gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
-        }
-
-        /* Determine if the profile looks bogus. If so, close the profile
-         * and use sRGB instead. See bug 460629, */
-        if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
-            NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
-                         "Builtin sRGB profile tagged as bogus!!!");
-            qcms_profile_release(gCMSOutputProfile);
-            gCMSOutputProfile = nullptr;
-        }
-
-        if (!gCMSOutputProfile) {
-            gCMSOutputProfile = GetCMSsRGBProfile();
-        }
-        /* Precache the LUT16 Interpolations for the output profile. See
-           bug 444661 for details. */
-        qcms_profile_precache_output_transform(gCMSOutputProfile);
-    }
-}
-
-qcms_profile *
-gfxPlatform::GetCMSOutputProfile()
-{
-    return gCMSOutputProfile;
-}
-
-qcms_profile *
-gfxPlatform::GetCMSsRGBProfile()
-{
-    if (!gCMSsRGBProfile) {
-
-        /* Create the profile using qcms. */
-        gCMSsRGBProfile = qcms_profile_sRGB();
-    }
-    return gCMSsRGBProfile;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSRGBTransform()
-{
-    if (!gCMSRGBTransform) {
-        qcms_profile *inProfile, *outProfile;
-        outProfile = GetCMSOutputProfile();
-        inProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
-                                              outProfile, QCMS_DATA_RGB_8,
-                                             QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSRGBTransform;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSInverseRGBTransform()
-{
-    if (!gCMSInverseRGBTransform) {
-        qcms_profile *inProfile, *outProfile;
-        inProfile = GetCMSOutputProfile();
-        outProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
-                                                     outProfile, QCMS_DATA_RGB_8,
-                                                     QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSInverseRGBTransform;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSRGBATransform()
-{
-    if (!gCMSRGBATransform) {
-        qcms_profile *inProfile, *outProfile;
-        outProfile = GetCMSOutputProfile();
-        inProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
-                                               outProfile, QCMS_DATA_RGBA_8,
-                                               QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSRGBATransform;
-}
-
-/* Shuts down various transforms and profiles for CMS. */
-static void ShutdownCMS()
-{
-
-    if (gCMSRGBTransform) {
-        qcms_transform_release(gCMSRGBTransform);
-        gCMSRGBTransform = nullptr;
-    }
-    if (gCMSInverseRGBTransform) {
-        qcms_transform_release(gCMSInverseRGBTransform);
-        gCMSInverseRGBTransform = nullptr;
-    }
-    if (gCMSRGBATransform) {
-        qcms_transform_release(gCMSRGBATransform);
-        gCMSRGBATransform = nullptr;
-    }
-    if (gCMSOutputProfile) {
-        qcms_profile_release(gCMSOutputProfile);
-
-        // handle the aliased case
-        if (gCMSsRGBProfile == gCMSOutputProfile)
-            gCMSsRGBProfile = nullptr;
-        gCMSOutputProfile = nullptr;
-    }
-    if (gCMSsRGBProfile) {
-        qcms_profile_release(gCMSsRGBProfile);
-        gCMSsRGBProfile = nullptr;
-    }
-
-    // Reset the state variables
-    gCMSIntent = -2;
-    gCMSMode = eCMSMode_Off;
-    gCMSInitialized = false;
-}
-
-static void MigratePrefs()
-{
-    /* Migrate from the boolean color_management.enabled pref - we now use
-       color_management.mode. */
-    if (Preferences::HasUserValue("gfx.color_management.enabled")) {
-        if (Preferences::GetBool("gfx.color_management.enabled", false)) {
-            Preferences::SetInt("gfx.color_management.mode", static_cast<int32_t>(eCMSMode_All));
-        }
-        Preferences::ClearUser("gfx.color_management.enabled");
-    }
-}
-
-// default SetupClusterBoundaries, based on Unicode properties;
-// platform subclasses may override if they wish
-void
-gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
-{
-    if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
-        // 8-bit text doesn't have clusters.
-        // XXX is this true in all languages???
-        // behdad: don't think so.  Czech for example IIRC has a
-        // 'ch' grapheme.
-        // jfkthame: but that's not expected to behave as a grapheme cluster
-        // for selection/editing/etc.
-        return;
-    }
-
-    aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
-}
-
-int32_t
-gfxPlatform::GetBidiNumeralOption()
-{
-    if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
-        mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
-    }
-    return mBidiNumeralOption;
-}
-
-void
-gfxPlatform::FontsPrefsChanged(const char *aPref)
-{
-    NS_ASSERTION(aPref != nullptr, "null preference");
-    if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
-        mAllowDownloadableFonts = UNINITIALIZED_VALUE;
-    } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
-        mFallbackUsesCmaps = UNINITIALIZED_VALUE;
-    } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
-        mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
-        gfxFontCache *fontCache = gfxFontCache::GetCache();
-        if (fontCache) {
-            fontCache->AgeAllGenerations();
-            fontCache->FlushShapedWordCaches();
-        }
-    } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
-        mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
-        gfxFontCache *fontCache = gfxFontCache::GetCache();
-        if (fontCache) {
-            fontCache->AgeAllGenerations();
-            fontCache->FlushShapedWordCaches();
-        }
-    } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
-        mBidiNumeralOption = UNINITIALIZED_VALUE;
-    } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
-        mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
-        gfxFontCache::GetCache()->AgeAllGenerations();
-    }
-}
-
-
-PRLogModuleInfo*
-gfxPlatform::GetLog(eGfxLog aWhichLog)
-{
-#ifdef PR_LOGGING
-    switch (aWhichLog) {
-    case eGfxLog_fontlist:
-        return sFontlistLog;
-        break;
-    case eGfxLog_fontinit:
-        return sFontInitLog;
-        break;
-    case eGfxLog_textrun:
-        return sTextrunLog;
-        break;
-    case eGfxLog_textrunui:
-        return sTextrunuiLog;
-        break;
-    case eGfxLog_cmapdata:
-        return sCmapDataLog;
-        break;
-    default:
-        break;
-    }
-
-    return nullptr;
-#else
-    return nullptr;
-#endif
-}
-
-int
-gfxPlatform::GetScreenDepth() const
-{
-    NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
-    return 0;
-}
-
-mozilla::gfx::SurfaceFormat
-gfxPlatform::Optimal2DFormatForContent(gfxASurface::gfxContentType aContent)
-{
-  switch (aContent) {
-  case gfxASurface::CONTENT_COLOR:
-    switch (GetOffscreenFormat()) {
-    case gfxASurface::ImageFormatARGB32:
-      return mozilla::gfx::FORMAT_B8G8R8A8;
-    case gfxASurface::ImageFormatRGB24:
-      return mozilla::gfx::FORMAT_B8G8R8X8;
-    case gfxASurface::ImageFormatRGB16_565:
-      return mozilla::gfx::FORMAT_R5G6B5;
-    default:
-      NS_NOTREACHED("unknown gfxImageFormat for CONTENT_COLOR");
-      return mozilla::gfx::FORMAT_B8G8R8A8;
-    }
-  case gfxASurface::CONTENT_ALPHA:
-    return mozilla::gfx::FORMAT_A8;
-  case gfxASurface::CONTENT_COLOR_ALPHA:
-    return mozilla::gfx::FORMAT_B8G8R8A8;
-  default:
-    NS_NOTREACHED("unknown gfxContentType");
-    return mozilla::gfx::FORMAT_B8G8R8A8;
-  }
-}
-
-gfxImageFormat
-gfxPlatform::OptimalFormatForContent(gfxASurface::gfxContentType aContent)
-{
-  switch (aContent) {
-  case gfxASurface::CONTENT_COLOR:
-    return GetOffscreenFormat();
-  case gfxASurface::CONTENT_ALPHA:
-    return gfxASurface::ImageFormatA8;
-  case gfxASurface::CONTENT_COLOR_ALPHA:
-    return gfxASurface::ImageFormatARGB32;
-  default:
-    NS_NOTREACHED("unknown gfxContentType");
-    return gfxASurface::ImageFormatARGB32;
-  }
-}
-
-void
-gfxPlatform::OrientationSyncPrefsObserverChanged()
-{
-  mOrientationSyncMillis = Preferences::GetUint("layers.orientation.sync.timeout", (uint32_t)0);
-}
-
-uint32_t
-gfxPlatform::GetOrientationSyncMillis() const
-{
-  return mOrientationSyncMillis;
-}
-
-/**
- * There are a number of layers acceleration (or layers in general) preferences
- * that should be consistent for the lifetime of the application (bug 840967).
- * As such, we will evaluate them all as soon as one of them is evaluated
- * and remember the values.  Changing these preferences during the run will
- * not have any effect until we restart.
- */
-static bool sPrefLayersOffMainThreadCompositionEnabled = false;
-static bool sPrefLayersOffMainThreadCompositionTestingEnabled = false;
-static bool sPrefLayersOffMainThreadCompositionForceEnabled = false;
-static bool sPrefLayersAccelerationForceEnabled = false;
-static bool sPrefLayersAccelerationDisabled = false;
-static bool sPrefLayersPreferOpenGL = false;
-static bool sPrefLayersPreferD3D9 = false;
-static bool sLayersSupportsD3D9 = true;
-static int  sPrefLayoutFrameRate = -1;
-static bool sBufferRotationEnabled = false;
-static bool sComponentAlphaEnabled = true;
-static bool sPrefBrowserTabsRemote = false;
-
-static bool sLayersAccelerationPrefsInitialized = false;
-
-void
-InitLayersAccelerationPrefs()
-{
-  if (!sLayersAccelerationPrefsInitialized)
-  {
-    sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
-    sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
-    sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
-    sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
-    sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
-    sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
-    sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
-    sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
-    sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
-    sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
-    sPrefBrowserTabsRemote = Preferences::GetBool("browser.tabs.remote", false);
-
-    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-    if (gfxInfo) {
-      int32_t status;
-      if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
-        if (status != nsIGfxInfo::FEATURE_NO_INFO && !sPrefLayersAccelerationForceEnabled) {
-          sLayersSupportsD3D9 = false;
-        }
-      }
-    }
-
-    sLayersAccelerationPrefsInitialized = true;
+  if (sInstance) {
+    delete sInstance;
+    sInstance = nullptr;
   }
 }
 
 bool
-gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
+gfxColorManagement::Exists()
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayersOffMainThreadCompositionEnabled ||
-         sPrefLayersOffMainThreadCompositionForceEnabled ||
-         sPrefLayersOffMainThreadCompositionTestingEnabled;
+  return sInstance != nullptr;
+}
+
+gfxColorManagement::gfxColorManagement()
+  : mPrefsObserver(nullptr),
+    mPrefLock(nullptr),
+    mPrefEnableV4(false),
+    mPrefForcesRGB(false),
+    mPrefMode(-1),
+    mPrefIntent(-1),
+    mPrefDisplayProfile(),
+#ifdef DEBUG
+    mPrefsInitialized(false),
+#endif
+    mModeSet(false),
+    mMode(eCMSMode_Off),
+    mIntent(-2),
+    mOutputProfile(nullptr),
+    msRGBProfile(nullptr),
+    mRGBTransform(nullptr),
+    mInverseRGBTransform(nullptr),
+    mRGBATransform(nullptr),
+    mDefaultPlatformProfile(nullptr)
+{
+  mPrefLock = new Mutex("gfxColorManagement::mPrefLock");
 }
 
-bool
-gfxPlatform::GetPrefLayersOffMainThreadCompositionForceEnabled()
+gfxColorManagement::~gfxColorManagement()
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayersOffMainThreadCompositionForceEnabled;
+  // Unregister our CMS Override callback.
+  NS_ASSERTION(mPrefsObserver, "mPrefsObserver is already gone");
+  if (mPrefsObserver) {
+    Preferences::RemoveObservers(mPrefsObserver, kObservedCMSPrefs);
+    mPrefsObserver = nullptr;
+  }
+
+  ResetAll();
+  delete mPrefLock;
 }
 
-bool
-gfxPlatform::GetPrefLayersAccelerationForceEnabled()
+NS_IMETHODIMP
+gfxColorManagement::PreferencesModified(const PRUnichar* aName)
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayersAccelerationForceEnabled;
+  if (NS_strcmp(aName, NS_LITERAL_STRING(kCMSPrefNameForcesRGB).get())) {
+    mPrefForcesRGB = Preferences::GetBool(kCMSPrefNameForcesRGB, false);
+    ResetAll();
+
+  } else if (NS_strcmp(aName, NS_LITERAL_STRING(kCMSPrefNameMode).get())) {
+    mPrefMode = Preferences::GetInt(kCMSPrefNameMode, -1);
+
+  } else if (NS_strcmp(aName, NS_LITERAL_STRING(kCMSPrefNameEnablev4).get())) {
+    mPrefEnableV4 = Preferences::GetBool(kCMSPrefNameEnablev4, false);
+
+  } else if (NS_strcmp(aName, NS_LITERAL_STRING(kCMSPrefNameRenderingIntent).get())) {
+    mPrefIntent = Preferences::GetInt(kCMSPrefNameRenderingIntent, -1);
+
+  } else if (NS_strcmp(aName, NS_LITERAL_STRING(kCMSPrefNameDisplayProfile).get())) {
+    MutexAutoLock autoLock(*mPrefLock);
+    mPrefDisplayProfile = Preferences::GetCString(kCMSPrefNameDisplayProfile);
+  }
+  return NS_OK;
 }
 
-bool gfxPlatform::OffMainThreadCompositionRequired()
+void gfxColorManagement::MigratePreferences()
 {
-  InitLayersAccelerationPrefs();
-  return sPrefBrowserTabsRemote;
+  // Migrate from the boolean color_management.enabled pref - we now use
+  // color_management.mode.
+  if (Preferences::HasUserValue(kCMSObsoletePrefEnabled)) {
+    if (Preferences::GetBool(kCMSObsoletePrefEnabled, false)) {
+      Preferences::SetInt(kCMSPrefNameMode, static_cast<int32_t>(eCMSMode_All));
+    }
+    Preferences::ClearUser(kCMSObsoletePrefEnabled);
+  }
 }
 
-bool
-gfxPlatform::GetPrefLayersAccelerationDisabled()
+void gfxColorManagement::Initialize(qcms_profile* aDefaultPlatformProfile)
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayersAccelerationDisabled;
-}
+  mDefaultPlatformProfile = aDefaultPlatformProfile;
+
+  // Migrate the old preferences first
+  MigratePreferences();
 
-bool
-gfxPlatform::GetPrefLayersPreferOpenGL()
-{
-  InitLayersAccelerationPrefs();
-  return sPrefLayersPreferOpenGL;
+  // Get the CMS preferences:
+  mPrefMode = Preferences::GetInt(kCMSPrefNameMode, -1);
+  mPrefEnableV4 = Preferences::GetBool(kCMSPrefNameEnablev4, false);
+  mPrefIntent = Preferences::GetInt(kCMSPrefNameRenderingIntent, -1);
+  mPrefForcesRGB = Preferences::GetBool(kCMSPrefNameForcesRGB, false);
+  {
+    // Paranoid, we likely won't need this in practice
+    MutexAutoLock autoLock(*mPrefLock);
+    mPrefDisplayProfile = Preferences::GetCString(kCMSPrefNameDisplayProfile);
+  }
+
+  // Create and register the CMS Override observer.
+  mPrefsObserver = new CMSPrefsObserver;
+  Preferences::AddWeakObservers(mPrefsObserver, kObservedCMSPrefs);
+
+#ifdef DEBUG
+  mPrefsInitialized = true;
+#endif
 }
 
-bool
-gfxPlatform::GetPrefLayersPreferD3D9()
+void gfxColorManagement::ResetAll()
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayersPreferD3D9;
+  if (mRGBTransform) {
+    qcms_transform_release(mRGBTransform);
+    mRGBTransform = nullptr;
+  }
+  if (mInverseRGBTransform) {
+    qcms_transform_release(mInverseRGBTransform);
+    mInverseRGBTransform = nullptr;
+  }
+  if (mRGBATransform) {
+    qcms_transform_release(mRGBATransform);
+    mRGBATransform = nullptr;
+  }
+  if (mOutputProfile) {
+    qcms_profile_release(mOutputProfile);
+
+    // handle the aliased case
+    if (msRGBProfile == mOutputProfile) {
+      msRGBProfile = nullptr;
+    }
+    mOutputProfile = nullptr;
+  }
+  if (msRGBProfile) {
+    qcms_profile_release(msRGBProfile);
+    msRGBProfile = nullptr;
+  }
+
+  // Reset the state variables
+  mIntent = -2;
+  mMode = eCMSMode_Off;
+  mModeSet = false;
 }
 
-bool
-gfxPlatform::CanUseDirect3D9()
+eCMSMode
+gfxColorManagement::GetMode() const
 {
-  // this function is called from the compositor thread, so it is not
-  // safe to init the prefs etc. from here.
-  MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
-  return sLayersSupportsD3D9;
+  NS_ASSERTION(mPrefsInitialized, "Prefs have not been initialized");
+  if (mModeSet == false) {
+    mModeSet = true;
+
+    if ((mPrefMode >= 0) && (mPrefMode < eCMSMode_AllCount)) {
+      mMode = static_cast<eCMSMode>(mPrefMode);
+    }
+
+    if (mPrefEnableV4) {
+      qcms_enable_iccv4();
+    }
+  }
+  return mMode;
 }
 
 int
-gfxPlatform::GetPrefLayoutFrameRate()
+gfxColorManagement::GetRenderingIntent() const
+{
+  NS_ASSERTION(mPrefsInitialized, "Prefs have not been initialized");
+  if (mIntent == -2) {
+    if (mPrefIntent >= 0) {
+      /* If the pref is within range, use it as an override. */
+      if ((mPrefIntent >= QCMS_INTENT_MIN) && (mPrefIntent <= QCMS_INTENT_MAX)) {
+        mIntent = mPrefIntent;
+      }
+      /* If the pref is out of range, use embedded profile. */
+      else {
+        mIntent = -1;
+      }
+    }
+    /* If we didn't get a valid intent from prefs, use the default. */
+    else {
+      mIntent = QCMS_INTENT_DEFAULT;
+    }
+  }
+  return mIntent;
+}
+
+qcms_profile*
+gfxColorManagement::GetOutputProfile() const
 {
-  InitLayersAccelerationPrefs();
-  return sPrefLayoutFrameRate;
+  NS_ASSERTION(mPrefsInitialized, "Prefs have not been initialized");
+  if (!mOutputProfile) {
+    /* Determine if we're using the internal override to force sRGB as
+       an output profile for reftests. See Bug 452125.
+
+       Note that we don't normally (outside of tests) set a
+       default value of this preference, which means nsIPrefBranch::GetBoolPref
+       will typically throw (and leave its out-param untouched).
+    */
+    if (mPrefForcesRGB) {
+      mOutputProfile = GetsRGBProfile();
+    }
+
+    if (!mOutputProfile) {
+      MutexAutoLock autoLock(*mPrefLock);
+      if (!mPrefDisplayProfile.IsEmpty()) {
+        mOutputProfile = qcms_profile_from_path(mPrefDisplayProfile);
+      }
+    }
+
+    if (!mOutputProfile) {
+      mOutputProfile = mDefaultPlatformProfile;
+    }
+
+    /* Determine if the profile looks bogus. If so, close the profile
+     * and use sRGB instead. See bug 460629, */
+    if (mOutputProfile && qcms_profile_is_bogus(mOutputProfile)) {
+      NS_ASSERTION(mOutputProfile != GetsRGBProfile(),
+                   "Builtin sRGB profile tagged as bogus!!!");
+      qcms_profile_release(mOutputProfile);
+      mOutputProfile = nullptr;
+    }
+
+    if (!mOutputProfile) {
+      mOutputProfile = GetsRGBProfile();
+    }
+    /* Precache the LUT16 Interpolations for the output profile. See
+       bug 444661 for details. */
+    qcms_profile_precache_output_transform(mOutputProfile);
+  }
+  return mOutputProfile;
 }
 
-bool
-gfxPlatform::BufferRotationEnabled()
+qcms_profile *
+gfxColorManagement::GetsRGBProfile() const
+{
+  if (!msRGBProfile) {
+    /* Create the profile using qcms. */
+    msRGBProfile = qcms_profile_sRGB();
+  }
+  return msRGBProfile;
+}
+
+qcms_transform *
+gfxColorManagement::GetRGBTransform() const
+{
+  if (!mRGBTransform) {
+    qcms_profile *inProfile, *outProfile;
+    outProfile = GetOutputProfile();
+    inProfile = GetsRGBProfile();
+
+    if (!inProfile || !outProfile) {
+      return nullptr;
+    }
+
+    mRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
+                                          outProfile, QCMS_DATA_RGB_8,
+                                          QCMS_INTENT_PERCEPTUAL);
+  }
+  return mRGBTransform;
+}
+
+qcms_transform *
+gfxColorManagement::GetInverseRGBTransform() const
 {
-  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
+  NS_ASSERTION(mPrefsInitialized, "Prefs have not been initialized");
+  if (!mInverseRGBTransform) {
+    qcms_profile *inProfile, *outProfile;
+    inProfile = GetOutputProfile();
+    outProfile = GetsRGBProfile();
+
+    if (!inProfile || !outProfile) {
+      return nullptr;
+    }
+
+    mInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
+                                                 outProfile, QCMS_DATA_RGB_8,
+                                                 QCMS_INTENT_PERCEPTUAL);
+  }
+
+  return mInverseRGBTransform;
+}
 
-  InitLayersAccelerationPrefs();
-  return sBufferRotationEnabled;
+qcms_transform *
+gfxColorManagement::GetRGBATransform() const
+{
+  if (!mRGBATransform) {
+    qcms_profile *inProfile, *outProfile;
+    outProfile = GetOutputProfile();
+    inProfile = GetsRGBProfile();
+
+    if (!inProfile || !outProfile) {
+      return nullptr;
+    }
+
+    mRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
+                                           outProfile, QCMS_DATA_RGBA_8,
+                                           QCMS_INTENT_PERCEPTUAL);
+  }
+  return mRGBATransform;
 }
 
 void
-gfxPlatform::DisableBufferRotation()
+gfxColorManagement::TransformPixel(const gfxRGBA& aIn, gfxRGBA& aOut,
+                                   qcms_transform* aTransform) const
 {
-  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
+    if (aTransform) {
+        /* we want the bytes in RGB order */
+#ifdef IS_LITTLE_ENDIAN
+        /* ABGR puts the bytes in |RGBA| order on little endian */
+        uint32_t packed = aIn.Packed(gfxRGBA::PACKED_ABGR);
+        qcms_transform_data(aTransform,
+                       (uint8_t *)&packed, (uint8_t *)&packed,
+                       1);
+        aOut.~gfxRGBA();
+        new (&aOut) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
+#else
+        /* ARGB puts the bytes in |ARGB| order on big endian */
+        uint32_t packed = aIn.Packed(gfxRGBA::PACKED_ARGB);
+        /* add one to move past the alpha byte */
+        qcms_transform_data(aTransform,
+                       (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
+                       1);
+        aOut.~gfxRGBA();
+        new (&aOut) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
+#endif
+    }
 
-  sBufferRotationEnabled = false;
+    else if (&aOut != &aIn)
+        aOut = aIn;
 }
 
-bool
-gfxPlatform::ComponentAlphaEnabled()
+gfxColorManagement::gfxColorManagement(const gfxColorManagement&)
 {
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-  return false;
-#endif
+  NS_ASSERTION(false, "Should not be calling gfxColorManagement copy constructor");
+}
 
-  InitLayersAccelerationPrefs();
-  return sComponentAlphaEnabled;
+gfxColorManagement& gfxColorManagement::operator=(const gfxColorManagement&)
+{
+  NS_ASSERTION(false, "Should not be calling gfxColorManagement::operator=");
+  return *this;
 }
copy from gfx/thebes/gfxPlatform.h
copy to gfx/thebes/gfxColorManagement.h
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxColorManagement.h
@@ -1,717 +1,125 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef GFX_PLATFORM_H
-#define GFX_PLATFORM_H
+#ifndef GFX_COLORMANAGEMENT_H
+#define GFX_COLORMANAGEMENT_H
 
-#include "prlog.h"
-#include "nsTArray.h"
-#include "nsStringGlue.h"
 #include "nsIObserver.h"
-
-#include "gfxTypes.h"
-#include "gfxASurface.h"
+#include "nsCOMPtr.h"
 #include "gfxColor.h"
-
+#include "nsString.h"
 #include "qcms.h"
 
-#include "mozilla/gfx/2D.h"
-#include "gfx2DGlue.h"
-#include "mozilla/RefPtr.h"
-#include "GfxInfoCollector.h"
-
-#include "mozilla/layers/CompositorTypes.h"
-
-#ifdef XP_OS2
-#undef OS2EMX_PLAIN_CHAR
-#endif
-
-class gfxImageSurface;
-class gfxFont;
-class gfxFontGroup;
-struct gfxFontStyle;
-class gfxUserFontSet;
-class gfxFontEntry;
-class gfxProxyFontEntry;
-class gfxPlatformFontList;
-class gfxTextRun;
-class nsIURI;
-class nsIAtom;
-
+class gfxColorManagement;
 namespace mozilla {
-namespace gl {
-class GLContext;
-}
+class Mutex;
 }
 
-extern cairo_user_data_key_t kDrawTarget;
-
-// pref lang id's for font prefs
-// !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
-// !!! don't use as bit mask, this may grow larger !!!
-
-enum eFontPrefLang {
-    eFontPrefLang_Western     =  0,
-    eFontPrefLang_CentEuro    =  1,
-    eFontPrefLang_Japanese    =  2,
-    eFontPrefLang_ChineseTW   =  3,
-    eFontPrefLang_ChineseCN   =  4,
-    eFontPrefLang_ChineseHK   =  5,
-    eFontPrefLang_Korean      =  6,
-    eFontPrefLang_Cyrillic    =  7,
-    eFontPrefLang_Baltic      =  8,
-    eFontPrefLang_Greek       =  9,
-    eFontPrefLang_Turkish     = 10,
-    eFontPrefLang_Thai        = 11,
-    eFontPrefLang_Hebrew      = 12,
-    eFontPrefLang_Arabic      = 13,
-    eFontPrefLang_Devanagari  = 14,
-    eFontPrefLang_Tamil       = 15,
-    eFontPrefLang_Armenian    = 16,
-    eFontPrefLang_Bengali     = 17,
-    eFontPrefLang_Canadian    = 18,
-    eFontPrefLang_Ethiopic    = 19,
-    eFontPrefLang_Georgian    = 20,
-    eFontPrefLang_Gujarati    = 21,
-    eFontPrefLang_Gurmukhi    = 22,
-    eFontPrefLang_Khmer       = 23,
-    eFontPrefLang_Malayalam   = 24,
-    eFontPrefLang_Oriya       = 25,
-    eFontPrefLang_Telugu      = 26,
-    eFontPrefLang_Kannada     = 27,
-    eFontPrefLang_Sinhala     = 28,
-    eFontPrefLang_Tibetan     = 29,
-
-    eFontPrefLang_LangCount   = 30, // except Others and UserDefined.
-
-    eFontPrefLang_Others      = 30, // x-unicode
-    eFontPrefLang_UserDefined = 31,
-
-    eFontPrefLang_CJKSet      = 32, // special code for CJK set
-    eFontPrefLang_AllCount    = 33
-};
-
 enum eCMSMode {
     eCMSMode_Off          = 0,     // No color management
     eCMSMode_All          = 1,     // Color manage everything
     eCMSMode_TaggedOnly   = 2,     // Color manage tagged Images Only
     eCMSMode_AllCount     = 3
 };
 
-enum eGfxLog {
-    // all font enumerations, localized names, fullname/psnames, cmap loads
-    eGfxLog_fontlist         = 0,
-    // timing info on font initialization
-    eGfxLog_fontinit         = 1,
-    // dump text runs, font matching, system fallback for content
-    eGfxLog_textrun          = 2,
-    // dump text runs, font matching, system fallback for chrome
-    eGfxLog_textrunui        = 3,
-    // dump cmap coverage data as they are loaded
-    eGfxLog_cmapdata         = 4
+/**
+ * Preferences, utilities and CMS profile management. These are "global".
+ * The first use should be calling gfxColorManagement::InstanceNC().Initialize()
+ * on the main thread.
+ */
+class gfxColorManagement MOZ_FINAL
+{
+public:
+  /**
+   * Manage the singleton.  Instance() will create it if it isn't there.
+   */
+  static const gfxColorManagement& Instance();
+  static void Destroy();
+  static bool Exists();
+
+  /**
+   * This must be called on the main thread.
+   */
+  void Initialize(qcms_profile* aDefaultPlatformProfile);
+
+  /**
+   * Reset all non-pref values, release various qcms profiles and transforms
+   */
+  void ResetAll();
+
+  /**
+   * The result of this may depend on the default platform profile set in
+   * the Initialize() method.
+   */
+  qcms_profile* GetOutputProfile() const;
+
+  /**
+   *The following are going to set the cached values when first called, after
+   * that reusing them until a relevant pref change or a ResetAll() call.
+   */
+  eCMSMode GetMode() const;
+  int GetRenderingIntent() const;
+
+  qcms_profile* GetsRGBProfile() const;
+  qcms_transform* GetRGBTransform() const;
+  qcms_transform* GetInverseRGBTransform() const;
+  qcms_transform* GetRGBATransform() const;
+
+  /**
+   * Convert a pixel using a cms transform in an endian-aware manner.
+   *
+   * Sets aOut to aIn if aTransform is nullptr.
+   */
+  void TransformPixel(const gfxRGBA& aIn, gfxRGBA& aOut, qcms_transform* aTransform) const;
+
+private:
+  nsCOMPtr<nsIObserver> mPrefsObserver;
+  mozilla::Mutex* mPrefLock;
+  bool mPrefEnableV4;
+  bool mPrefForcesRGB;
+  int32_t mPrefMode;
+  int32_t mPrefIntent;
+  nsAdoptingCString mPrefDisplayProfile;
+#ifdef DEBUG
+  bool mPrefsInitialized;
+#endif
+
+  mutable bool mModeSet;
+  mutable eCMSMode mMode;
+  mutable int mIntent;
+
+  // These two may point to the same profile
+  mutable qcms_profile *mOutputProfile;
+  mutable qcms_profile *msRGBProfile;
+
+  mutable qcms_transform *mRGBTransform;
+  mutable qcms_transform *mInverseRGBTransform;
+  mutable qcms_transform *mRGBATransform;
+
+  qcms_profile* mDefaultPlatformProfile;
+
+private:
+  static gfxColorManagement* sInstance;
+
+  gfxColorManagement();
+  ~gfxColorManagement();
+
+  // =delete would have been nice here, but it isn't supported by all compilers
+  // as of Sep 2013.
+  gfxColorManagement(const gfxColorManagement&);
+  gfxColorManagement& operator=(const gfxColorManagement&);
+
+  void MigratePreferences();
+  NS_IMETHODIMP PreferencesModified(const PRUnichar* prefName);
+
+  // Only friends can get to the non-const version.  This is a bit arbitrary
+  // as we currently don't have a reason to allow others access, but it isn't
+  // really a hard requirement.
+  friend class gfxPlatform;
+  friend class CMSPrefsObserver;
+  static gfxColorManagement& InstanceNC();
 };
 
-// when searching through pref langs, max number of pref langs
-const uint32_t kMaxLenPrefLangList = 32;
-
-#define UNINITIALIZED_VALUE  (-1)
-
-typedef gfxASurface::gfxImageFormat gfxImageFormat;
-
-inline const char*
-GetBackendName(mozilla::gfx::BackendType aBackend)
-{
-  switch (aBackend) {
-      case mozilla::gfx::BACKEND_DIRECT2D:
-        return "direct2d";
-      case mozilla::gfx::BACKEND_COREGRAPHICS_ACCELERATED:
-        return "quartz accelerated";
-      case mozilla::gfx::BACKEND_COREGRAPHICS:
-        return "quartz";
-      case mozilla::gfx::BACKEND_CAIRO:
-        return "cairo";
-      case mozilla::gfx::BACKEND_SKIA:
-        return "skia";
-      case mozilla::gfx::BACKEND_RECORDING:
-        return "recording";
-      case mozilla::gfx::BACKEND_DIRECT2D1_1:
-        return "direct2d 1.1";
-      case mozilla::gfx::BACKEND_NONE:
-        return "none";
-  }
-  MOZ_CRASH("Incomplete switch");
-}
-
-class gfxPlatform {
-public:
-    /**
-     * Return a pointer to the current active platform.
-     * This is a singleton; it contains mostly convenience
-     * functions to obtain platform-specific objects.
-     */
-    static gfxPlatform *GetPlatform();
-
-
-    /**
-     * Shut down Thebes.
-     * Init() arranges for this to be called at an appropriate time.
-     */
-    static void Shutdown();
-
-    /**
-     * Create an offscreen surface of the given dimensions
-     * and image format.
-     */
-    virtual already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
-                                                                 gfxASurface::gfxContentType contentType) = 0;
-
-    /**
-     * Create an offscreen surface of the given dimensions and image format which
-     * can be converted to a gfxImageSurface without copying. If we can provide
-     * a platform-hosted surface, then we will return that instead of an actual
-     * gfxImageSurface.
-     * Sub-classes should override this method if CreateOffscreenSurface returns a
-     * surface which implements GetAsImageSurface
-     */
-    virtual already_AddRefed<gfxASurface>
-      CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                  gfxASurface::gfxContentType aContentType);
-
-    virtual already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface,
-                                                        gfxASurface::gfxImageFormat format);
-
-    /**
-     * Beware that these methods may return DrawTargets which are not fully supported
-     * on the current platform and might fail silently in subtle ways. This is a massive
-     * potential footgun. You should only use these methods for canvas drawing really.
-     * Use extreme caution if you use them for content where you are not 100% sure we
-     * support the DrawTarget we get back.
-     * See SupportsAzureContentForDrawTarget.
-     */
-    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateDrawTargetForSurface(gfxASurface *aSurface, const mozilla::gfx::IntSize& aSize);
-
-    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const mozilla::gfx::IntSize& aSize);
-
-    /*
-     * Creates a SourceSurface for a gfxASurface. This function does no caching,
-     * so the caller should cache the gfxASurface if it will be used frequently.
-     * The returned surface keeps a reference to aTarget, so it is OK to keep the
-     * surface, even if aTarget changes.
-     * aTarget should not keep a reference to the returned surface because that
-     * will cause a cycle.
-     */
-    virtual mozilla::RefPtr<mozilla::gfx::SourceSurface>
-      GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface);
-
-    static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);
-
-    virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
-      GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
-
-    /*
-     * Cairo doesn't give us a way to create a surface pointing to a context
-     * without marking it as copy on write. For canvas we want to create
-     * a surface that points to what is currently being drawn by a canvas
-     * without a copy thus we need to create a special case. This works on
-     * most platforms with GetThebesSurfaceForDrawTarget but fails on Mac
-     * because when we create the surface we vm_copy the memory and never
-     * notify the context that the canvas has drawn to it thus we end up
-     * with a static snapshot.
-     *
-     * This function guarantes that the gfxASurface reflects the DrawTarget.
-     */
-    virtual already_AddRefed<gfxASurface>
-      CreateThebesSurfaceAliasForDrawTarget_hack(mozilla::gfx::DrawTarget *aTarget) {
-      // Overwrite me on platform where GetThebesSurfaceForDrawTarget returns
-      // a snapshot of the draw target.
-      return GetThebesSurfaceForDrawTarget(aTarget);
-    }
-
-    virtual already_AddRefed<gfxASurface>
-      GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
-
-    mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
-
-    mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateOffscreenCanvasDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
-
-    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, 
-                              int32_t aStride, mozilla::gfx::SurfaceFormat aFormat);
-
-    /**
-     * Returns true if we will render content using Azure using a gfxPlatform
-     * provided DrawTarget.
-     * Prefer using SupportsAzureContentForDrawTarget or 
-     * SupportsAzureContentForType.
-     * This function is potentially misleading and dangerous because we might
-     * support a certain Azure backend on the current platform, but when you
-     * ask for a DrawTarget you get one for a different backend which is not
-     * supported for content drawing.
-     */
-    bool SupportsAzureContent() {
-      return GetContentBackend() != mozilla::gfx::BACKEND_NONE;
-    }
-
-    /**
-     * Returns true if we should use Azure to render content with aTarget. For
-     * example, it is possible that we are using Direct2D for rendering and thus
-     * using Azure. But we want to render to a CairoDrawTarget, in which case
-     * SupportsAzureContent will return true but SupportsAzureContentForDrawTarget
-     * will return false.
-     */
-    bool SupportsAzureContentForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
-
-    bool SupportsAzureContentForType(mozilla::gfx::BackendType aType) {
-      return (1 << aType) & mContentBackendBitmask;
-    }
-
-    virtual bool UseAcceleratedSkiaCanvas();
-
-    void GetAzureBackendInfo(mozilla::widget::InfoObject &aObj) {
-      aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
-      aObj.DefineProperty("AzureSkiaAccelerated", UseAcceleratedSkiaCanvas());
-      aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
-      aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
-    }
-
-    mozilla::gfx::BackendType GetPreferredCanvasBackend() {
-      return mPreferredCanvasBackend;
-    }
-
-    /*
-     * Font bits
-     */
-
-    virtual void SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString);
-
-    /**
-     * Fill aListOfFonts with the results of querying the list of font names
-     * that correspond to the given language group or generic font family
-     * (or both, or neither).
-     */
-    virtual nsresult GetFontList(nsIAtom *aLangGroup,
-                                 const nsACString& aGenericFamily,
-                                 nsTArray<nsString>& aListOfFonts);
-
-    /**
-     * Rebuilds the any cached system font lists
-     */
-    virtual nsresult UpdateFontList();
-
-    /**
-     * Create the platform font-list object (gfxPlatformFontList concrete subclass).
-     * This function is responsible to create the appropriate subclass of
-     * gfxPlatformFontList *and* to call its InitFontList() method.
-     */
-    virtual gfxPlatformFontList *CreatePlatformFontList() {
-        NS_NOTREACHED("oops, this platform doesn't have a gfxPlatformFontList implementation");
-        return nullptr;
-    }
-
-    /**
-     * Font name resolver, this returns actual font name(s) by the callback
-     * function. If the font doesn't exist, the callback function is not called.
-     * If the callback function returns false, the aAborted value is set to
-     * true, otherwise, false.
-     */
-    typedef bool (*FontResolverCallback) (const nsAString& aName,
-                                            void *aClosure);
-    virtual nsresult ResolveFontName(const nsAString& aFontName,
-                                     FontResolverCallback aCallback,
-                                     void *aClosure,
-                                     bool& aAborted) = 0;
-
-    /**
-     * Resolving a font name to family name. The result MUST be in the result of GetFontList().
-     * If the name doesn't in the system, aFamilyName will be empty string, but not failed.
-     */
-    virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
-
-    /**
-     * Create the appropriate platform font group
-     */
-    virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies,
-                                          const gfxFontStyle *aStyle,
-                                          gfxUserFontSet *aUserFontSet) = 0;
-                                          
-                                          
-    /**
-     * Look up a local platform font using the full font face name.
-     * (Needed to support @font-face src local().)
-     * Ownership of the returned gfxFontEntry is passed to the caller,
-     * who must either AddRef() or delete.
-     */
-    virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
-                                          const nsAString& aFontName)
-    { return nullptr; }
-
-    /**
-     * Activate a platform font.  (Needed to support @font-face src url().)
-     * aFontData is a NS_Malloc'ed block that must be freed by this function
-     * (or responsibility passed on) when it is no longer needed; the caller
-     * will NOT free it.
-     * Ownership of the returned gfxFontEntry is passed to the caller,
-     * who must either AddRef() or delete.
-     */
-    virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                           const uint8_t *aFontData,
-                                           uint32_t aLength);
-
-    /**
-     * Whether to allow downloadable fonts via @font-face rules
-     */
-    bool DownloadableFontsEnabled();
-
-    /**
-     * True when hinting should be enabled.  This setting shouldn't
-     * change per gecko process, while the process is live.  If so the
-     * results are not defined.
-     *
-     * NB: this bit is only honored by the FT2 backend, currently.
-     */
-    virtual bool FontHintingEnabled() { return true; }
-
-    /**
-     * True when zooming should not require reflow, so glyph metrics and
-     * positioning should not be adjusted for device pixels.
-     * If this is TRUE, then FontHintingEnabled() should be FALSE,
-     * but the converse is not necessarily required; in particular,
-     * B2G always has FontHintingEnabled FALSE, but RequiresLinearZoom
-     * is only true for the browser process, not Gaia or other apps.
-     *
-     * Like FontHintingEnabled (above), this setting shouldn't
-     * change per gecko process, while the process is live.  If so the
-     * results are not defined.
-     *
-     * NB: this bit is only honored by the FT2 backend, currently.
-     */
-    virtual bool RequiresLinearZoom() { return false; }
-
-    /**
-     * Whether to check all font cmaps during system font fallback
-     */
-    bool UseCmapsDuringSystemFallback();
-
-    /**
-     * Whether to render SVG glyphs within an OpenType font wrapper
-     */
-    bool OpenTypeSVGEnabled();
-
-    /**
-     * Whether to use the SIL Graphite rendering engine
-     * (for fonts that include Graphite tables)
-     */
-    bool UseGraphiteShaping();
-
-    /**
-     * Whether to use the harfbuzz shaper (depending on script complexity).
-     *
-     * This allows harfbuzz to be enabled selectively via the preferences.
-     */
-    bool UseHarfBuzzForScript(int32_t aScriptCode);
-
-    // check whether format is supported on a platform or not (if unclear, returns true)
-    virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) { return false; }
-
-    void GetPrefFonts(nsIAtom *aLanguage, nsString& array, bool aAppendUnicode = true);
-
-    // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
-    void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);
-    
-    /**
-     * Iterate over pref fonts given a list of lang groups.  For a single lang
-     * group, multiple pref fonts are possible.  If error occurs, returns false,
-     * true otherwise.  Callback returns false to abort process.
-     */
-    typedef bool (*PrefFontCallback) (eFontPrefLang aLang, const nsAString& aName,
-                                        void *aClosure);
-    static bool ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen,
-                                  PrefFontCallback aCallback,
-                                  void *aClosure);
-
-    // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW)
-    static eFontPrefLang GetFontPrefLangFor(const char* aLang);
-
-    // convert a lang group atom to enum constant
-    static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang);
-
-    // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW")
-    static const char* GetPrefLangName(eFontPrefLang aLang);
-   
-    // map a Unicode range (based on char code) to a font language for Preferences
-    static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange);
-
-    // returns true if a pref lang is CJK
-    static bool IsLangCJK(eFontPrefLang aLang);
-    
-    // helper method to add a pref lang to an array, if not already in array
-    static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang);
-
-    // returns a list of commonly used fonts for a given character
-    // these are *possible* matches, no cmap-checking is done at this level
-    virtual void GetCommonFallbackFonts(const uint32_t /*aCh*/,
-                                        int32_t /*aRunScript*/,
-                                        nsTArray<const char*>& /*aFontList*/)
-    {
-        // platform-specific override, by default do nothing
-    }
-
-    // Break large OMTC tiled thebes layer painting into small paints.
-    static bool UseProgressiveTilePainting();
-
-    // When a critical display-port is set, render the visible area outside of
-    // it into a buffer at a lower precision. Requires tiled buffers.
-    static bool UseLowPrecisionBuffer();
-
-    // Retrieve the resolution that a low precision buffer should render at.
-    static float GetLowPrecisionResolution();
-
-    // Retain some invalid tiles when the valid region of a layer changes and
-    // excludes previously valid tiles.
-    static bool UseReusableTileStore();
-
-    static bool OffMainThreadCompositingEnabled();
-
-    /** Use gfxPlatform::GetPref* methods instead of direct calls to Preferences
-     * to get the values for layers preferences.  These will only be evaluated
-     * only once, and remain the same until restart.
-     */
-    static bool GetPrefLayersOffMainThreadCompositionEnabled();
-    static bool GetPrefLayersOffMainThreadCompositionForceEnabled();
-    static bool GetPrefLayersAccelerationForceEnabled();
-    static bool GetPrefLayersAccelerationDisabled();
-    static bool GetPrefLayersPreferOpenGL();
-    static bool GetPrefLayersPreferD3D9();
-    static bool CanUseDirect3D9();
-    static int  GetPrefLayoutFrameRate();
-
-    static bool OffMainThreadCompositionRequired();
-
-    /**
-     * Is it possible to use buffer rotation
-     */
-    static bool BufferRotationEnabled();
-    static void DisableBufferRotation();
-
-    static bool ComponentAlphaEnabled();
-
-    /**
-     * Are we going to try color management?
-     */
-    static eCMSMode GetCMSMode();
-
-    /**
-     * Determines the rendering intent for color management.
-     *
-     * If the value in the pref gfx.color_management.rendering_intent is a
-     * valid rendering intent as defined in gfx/qcms/qcms.h, that
-     * value is returned. Otherwise, -1 is returned and the embedded intent
-     * should be used.
-     *
-     * See bug 444014 for details.
-     */
-    static int GetRenderingIntent();
-
-    /**
-     * Convert a pixel using a cms transform in an endian-aware manner.
-     *
-     * Sets 'out' to 'in' if transform is nullptr.
-     */
-    static void TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform);
-
-    /**
-     * Return the output device ICC profile.
-     */
-    static qcms_profile* GetCMSOutputProfile();
-
-    /**
-     * Return the sRGB ICC profile.
-     */
-    static qcms_profile* GetCMSsRGBProfile();
-
-    /**
-     * Return sRGB -> output device transform.
-     */
-    static qcms_transform* GetCMSRGBTransform();
-
-    /**
-     * Return output -> sRGB device transform.
-     */
-    static qcms_transform* GetCMSInverseRGBTransform();
-
-    /**
-     * Return sRGBA -> output device transform.
-     */
-    static qcms_transform* GetCMSRGBATransform();
-
-    virtual void FontsPrefsChanged(const char *aPref);
-
-    void OrientationSyncPrefsObserverChanged();
-
-    int32_t GetBidiNumeralOption();
-
-    /**
-     * Returns a 1x1 surface that can be used to create graphics contexts
-     * for measuring text etc as if they will be rendered to the screen
-     */
-    gfxASurface* ScreenReferenceSurface() { return mScreenReferenceSurface; }
-
-    virtual mozilla::gfx::SurfaceFormat Optimal2DFormatForContent(gfxASurface::gfxContentType aContent);
-
-    virtual gfxImageFormat OptimalFormatForContent(gfxASurface::gfxContentType aContent);
-
-    virtual gfxImageFormat GetOffscreenFormat()
-    { return gfxASurface::ImageFormatRGB24; }
-
-    /**
-     * Returns a logger if one is available and logging is enabled
-     */
-    static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
-
-    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
-
-    virtual int GetScreenDepth() const;
-
-    bool WidgetUpdateFlashing() const { return mWidgetUpdateFlashing; }
-
-    uint32_t GetOrientationSyncMillis() const;
-
-    /**
-     * Return the layer debugging options to use browser-wide.
-     */
-    mozilla::layers::DiagnosticTypes GetLayerDiagnosticTypes();
-
-    static bool DrawFrameCounter();
-    static nsIntRect FrameCounterBounds() {
-      int bits = 16;
-      int sizeOfBit = 3;
-      return nsIntRect(0, 0, bits * sizeOfBit, sizeOfBit);
-    }
-
-    /**
-     * Returns true if we should use raw memory to send data to the compositor
-     * rather than using shmems.
-     *
-     * This method should not be called from the compositor thread.
-     */
-    bool PreferMemoryOverShmem() const;
-    bool UseDeprecatedTextures() const { return mLayersUseDeprecated; }
-
-protected:
-    gfxPlatform();
-    virtual ~gfxPlatform();
-
-    void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, 
-                            eFontPrefLang aCharLang, eFontPrefLang aPageLang);
-
-    /**
-     * Helper method, creates a draw target for a specific Azure backend.
-     * Used by CreateOffscreenDrawTarget.
-     */
-    mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateDrawTargetForBackend(mozilla::gfx::BackendType aBackend,
-                                 const mozilla::gfx::IntSize& aSize,
-                                 mozilla::gfx::SurfaceFormat aFormat);
-
-    /**
-     * Initialise the preferred and fallback canvas backends
-     * aBackendBitmask specifies the backends which are acceptable to the caller.
-     * The backend used is determined by aBackendBitmask and the order specified
-     * by the gfx.canvas.azure.backends pref.
-     */
-    void InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask);
-
-    /**
-     * returns the first backend named in the pref gfx.canvas.azure.backends
-     * which is a component of aBackendBitmask, a bitmask of backend types
-     */
-    static mozilla::gfx::BackendType GetCanvasBackendPref(uint32_t aBackendBitmask);
-
-    /**
-     * returns the first backend named in the pref gfx.content.azure.backend
-     * which is a component of aBackendBitmask, a bitmask of backend types
-     */
-    static mozilla::gfx::BackendType GetContentBackendPref(uint32_t &aBackendBitmask);
-
-    /**
-     * If aEnabledPrefName is non-null, checks the aEnabledPrefName pref and
-     * returns BACKEND_NONE if the pref is not enabled.
-     * Otherwise it will return the first backend named in aBackendPrefName
-     * allowed by aBackendBitmask, a bitmask of backend types.
-     * It also modifies aBackendBitmask to only include backends that are
-     * allowed given the prefs.
-     */
-    static mozilla::gfx::BackendType GetBackendPref(const char* aEnabledPrefName,
-                                                    const char* aBackendPrefName,
-                                                    uint32_t &aBackendBitmask);
-    /**
-     * Decode the backend enumberation from a string.
-     */
-    static mozilla::gfx::BackendType BackendTypeForName(const nsCString& aName);
-
-    mozilla::gfx::BackendType GetContentBackend() {
-      return mContentBackend;
-    }
-
-    int8_t  mAllowDownloadableFonts;
-    int8_t  mGraphiteShapingEnabled;
-    int8_t  mOpenTypeSVGEnabled;
-
-    int8_t  mBidiNumeralOption;
-
-    // whether to always search font cmaps globally 
-    // when doing system font fallback
-    int8_t  mFallbackUsesCmaps;
-
-    // which scripts should be shaped with harfbuzz
-    int32_t mUseHarfBuzzScripts;
-
-private:
-    /**
-     * Start up Thebes.
-     */
-    static void Init();
-
-    static void CreateCMSOutputProfile();
-
-    friend int RecordingPrefChanged(const char *aPrefName, void *aClosure);
-
-    virtual qcms_profile* GetPlatformCMSOutputProfile();
-
-    virtual bool SupportsOffMainThreadCompositing() { return true; }
-
-    nsRefPtr<gfxASurface> mScreenReferenceSurface;
-    nsTArray<uint32_t> mCJKPrefLangs;
-    nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
-    nsCOMPtr<nsIObserver> mFontPrefsObserver;
-    nsCOMPtr<nsIObserver> mOrientationSyncPrefsObserver;
-
-    // The preferred draw target backend to use for canvas
-    mozilla::gfx::BackendType mPreferredCanvasBackend;
-    // The fallback draw target backend to use for canvas, if the preferred backend fails
-    mozilla::gfx::BackendType mFallbackCanvasBackend;
-    // The backend to use for content
-    mozilla::gfx::BackendType mContentBackend;
-    // Bitmask of backend types we can use to render content
-    uint32_t mContentBackendBitmask;
-
-    mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
-    bool mWorkAroundDriverBugs;
-
-    mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
-    bool mWidgetUpdateFlashing;
-    uint32_t mOrientationSyncMillis;
-    bool mLayersPreferMemoryOverShmem;
-    bool mLayersUseDeprecated;
-    bool mDrawLayerBorders;
-    bool mDrawTileBorders;
-    bool mDrawBigImageBorders;
-};
-
-#endif /* GFX_PLATFORM_H */
+#endif /* GFX_COLORMANAGEMENT_H */
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/Alignment.h"
 #include "mozilla/Constants.h"
 
 #include "cairo.h"
 
 #include "gfxContext.h"
 
 #include "gfxColor.h"
+#include "gfxColorManagement.h"
 #include "gfxMatrix.h"
 #include "gfxASurface.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
 #include "gfxTeeSurface.h"
 #include "GeckoProfiler.h"
 #include <algorithm>
 
@@ -1292,41 +1293,44 @@ gfxContext::ClipContainsRect(const gfxRe
   }
 }
 
 // rendering sources
 
 void
 gfxContext::SetColor(const gfxRGBA& c)
 {
+  const gfxColorManagement& colorManagement = gfxColorManagement::Instance();
   if (mCairo) {
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+    if (colorManagement.GetMode() == eCMSMode_All) {
 
         gfxRGBA cms;
-        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-        if (transform)
-          gfxPlatform::TransformPixel(c, cms, transform);
+        qcms_transform *transform = colorManagement.GetRGBTransform();
+        if (transform) {
+          colorManagement.TransformPixel(c, cms, transform);
+        }
 
         // Use the original alpha to avoid unnecessary float->byte->float
         // conversion errors
         cairo_set_source_rgba(mCairo, cms.r, cms.g, cms.b, c.a);
     }
     else
         cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
   } else {
     CurrentState().pattern = nullptr;
     CurrentState().sourceSurfCairo = nullptr;
     CurrentState().sourceSurface = nullptr;
 
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+    if (colorManagement.GetMode() == eCMSMode_All) {
 
         gfxRGBA cms;
-        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-        if (transform)
-          gfxPlatform::TransformPixel(c, cms, transform);
+        qcms_transform *transform = colorManagement.GetRGBTransform();
+        if (transform) {
+          colorManagement.TransformPixel(c, cms, transform);
+        }
 
         // Use the original alpha to avoid unnecessary float->byte->float
         // conversion errors
         CurrentState().color = ToColor(cms);
     }
     else
         CurrentState().color = ToColor(c);
   }
--- a/gfx/thebes/gfxPattern.cpp
+++ b/gfx/thebes/gfxPattern.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxTypes.h"
 #include "gfxPattern.h"
 #include "gfxASurface.h"
 #include "gfxPlatform.h"
+#include "gfxColorManagement.h"
 
 #include "cairo.h"
 
 #include <vector>
 
 using namespace mozilla::gfx;
 
 gfxPattern::gfxPattern(cairo_pattern_t *aPattern)
@@ -74,21 +75,23 @@ gfxPattern::CairoPattern()
     return mPattern;
 }
 
 void
 gfxPattern::AddColorStop(gfxFloat offset, const gfxRGBA& c)
 {
   if (mPattern) {
     mStops = nullptr;
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+    const gfxColorManagement& colorManagement = gfxColorManagement::Instance();
+    if (colorManagement.GetMode() == eCMSMode_All) {
         gfxRGBA cms;
-        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-        if (transform)
-          gfxPlatform::TransformPixel(c, cms, transform);
+        qcms_transform *transform = colorManagement.GetRGBTransform();
+        if (transform) {
+          colorManagement.TransformPixel(c, cms, transform);
+        }
 
         // Use the original alpha to avoid unnecessary float->byte->float
         // conversion errors
         cairo_pattern_add_color_stop_rgba(mPattern, offset,
                                           cms.r, cms.g, cms.b, c.a);
     }
     else
         cairo_pattern_add_color_stop_rgba(mPattern, offset, c.r, c.g, c.b, c.a);
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -76,77 +76,40 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 
+#include "gfxColorManagement.h"
+
 using namespace mozilla;
 using namespace mozilla::layers;
 
 gfxPlatform *gPlatform = nullptr;
 static bool gEverInitialized = false;
 
 static Mutex* gGfxPlatformPrefsLock = nullptr;
 
-// These two may point to the same profile
-static qcms_profile *gCMSOutputProfile = nullptr;
-static qcms_profile *gCMSsRGBProfile = nullptr;
-
-static qcms_transform *gCMSRGBTransform = nullptr;
-static qcms_transform *gCMSInverseRGBTransform = nullptr;
-static qcms_transform *gCMSRGBATransform = nullptr;
-
-static bool gCMSInitialized = false;
-static eCMSMode gCMSMode = eCMSMode_Off;
-static int gCMSIntent = -2;
-
-static void ShutdownCMS();
-static void MigratePrefs();
-
 static bool sDrawFrameCounter = false;
 
 #include "mozilla/gfx/2D.h"
 using namespace mozilla::gfx;
 
 // logs shared across gfx
 #ifdef PR_LOGGING
 static PRLogModuleInfo *sFontlistLog = nullptr;
 static PRLogModuleInfo *sFontInitLog = nullptr;
 static PRLogModuleInfo *sTextrunLog = nullptr;
 static PRLogModuleInfo *sTextrunuiLog = nullptr;
 static PRLogModuleInfo *sCmapDataLog = nullptr;
 #endif
 
-/* Class to listen for pref changes so that chrome code can dynamically
-   force sRGB as an output profile. See Bug #452125. */
-class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
-                                       public nsSupportsWeakReference
-{
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-
-NS_IMPL_ISUPPORTS2(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
-
-NS_IMETHODIMP
-SRGBOverrideObserver::Observe(nsISupports *aSubject,
-                              const char *aTopic,
-                              const PRUnichar *someData)
-{
-    NS_ASSERTION(NS_strcmp(someData,
-                   NS_LITERAL_STRING("gfx.color_mangement.force_srgb").get()),
-                 "Restarting CMS on wrong pref!");
-    ShutdownCMS();
-    return NS_OK;
-}
-
 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
 
 #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
 #define HARFBUZZ_SCRIPTS_DEFAULT  mozilla::unicode::SHAPING_DEFAULT
 #define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
 
 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
 
@@ -392,22 +355,18 @@ gfxPlatform::Init()
         NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
     }
 
     rv = gfxFontCache::Init();
     if (NS_FAILED(rv)) {
         NS_RUNTIMEABORT("Could not initialize gfxFontCache");
     }
 
-    /* Pref migration hook. */
-    MigratePrefs();
-
-    /* Create and register our CMS Override observer. */
-    gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
-    Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
+    // Initialize the preferences, and set the fallback profile
+    gfxColorManagement::InstanceNC().Initialize(GetPlatform()->GetPlatformCMSOutputProfile());
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
     gPlatform->mOrientationSyncPrefsObserver = new OrientationSyncPrefsObserver();
     Preferences::AddStrongObserver(gPlatform->mOrientationSyncPrefsObserver, "layers.orientation.sync.timeout");
 
     gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
@@ -429,43 +388,36 @@ gfxPlatform::Init()
 
     Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
 
     gPlatform->mOrientationSyncMillis = Preferences::GetUint("layers.orientation.sync.timeout", (uint32_t)0);
 
     mozilla::Preferences::AddBoolVarCache(&sDrawFrameCounter,
                                           "layers.frame-counter",
                                           false);
-
-    CreateCMSOutputProfile();
 }
 
 void
 gfxPlatform::Shutdown()
 {
     // These may be called before the corresponding subsystems have actually
     // started up. That's OK, they can handle it.
     gfxFontCache::Shutdown();
     gfxFontGroup::Shutdown();
     gfxGraphiteShaper::Shutdown();
 #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
     gfxPlatformFontList::Shutdown();
 #endif
 
     // Free the various non-null transforms and loaded profiles
-    ShutdownCMS();
+    gfxColorManagement::Destroy();
 
     // In some cases, gPlatform may not be created but Shutdown() called,
     // e.g., during xpcshell tests.
     if (gPlatform) {
-        /* Unregister our CMS Override callback. */
-        NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
-        Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
-        gPlatform->mSRGBOverrideObserver = nullptr;
-
         NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
         Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
         gPlatform->mFontPrefsObserver = nullptr;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     // Shut down the texture pool
     mozilla::gl::TexturePoolOGL::Shutdown();
@@ -1481,265 +1433,22 @@ gfxPlatform::UseReusableTileStore()
 bool
 gfxPlatform::OffMainThreadCompositingEnabled()
 {
   return XRE_GetProcessType() == GeckoProcessType_Default ?
     CompositorParent::CompositorLoop() != nullptr :
     CompositorChild::ChildProcessHasCompositor();
 }
 
-eCMSMode
-gfxPlatform::GetCMSMode()
-{
-    if (gCMSInitialized == false) {
-        gCMSInitialized = true;
-        nsresult rv;
-
-        int32_t mode;
-        rv = Preferences::GetInt("gfx.color_management.mode", &mode);
-        if (NS_SUCCEEDED(rv) && (mode >= 0) && (mode < eCMSMode_AllCount)) {
-            gCMSMode = static_cast<eCMSMode>(mode);
-        }
-
-        bool enableV4;
-        rv = Preferences::GetBool("gfx.color_management.enablev4", &enableV4);
-        if (NS_SUCCEEDED(rv) && enableV4) {
-            qcms_enable_iccv4();
-        }
-    }
-    return gCMSMode;
-}
-
-int
-gfxPlatform::GetRenderingIntent()
-{
-    if (gCMSIntent == -2) {
-
-        /* Try to query the pref system for a rendering intent. */
-        int32_t pIntent;
-        if (NS_SUCCEEDED(Preferences::GetInt("gfx.color_management.rendering_intent", &pIntent))) {
-            /* If the pref is within range, use it as an override. */
-            if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
-                gCMSIntent = pIntent;
-            }
-            /* If the pref is out of range, use embedded profile. */
-            else {
-                gCMSIntent = -1;
-            }
-        }
-        /* If we didn't get a valid intent from prefs, use the default. */
-        else {
-            gCMSIntent = QCMS_INTENT_DEFAULT;
-        }
-    }
-    return gCMSIntent;
-}
-
-void
-gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
-{
-
-    if (transform) {
-        /* we want the bytes in RGB order */
-#ifdef IS_LITTLE_ENDIAN
-        /* ABGR puts the bytes in |RGBA| order on little endian */
-        uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
-        qcms_transform_data(transform,
-                       (uint8_t *)&packed, (uint8_t *)&packed,
-                       1);
-        out.~gfxRGBA();
-        new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
-#else
-        /* ARGB puts the bytes in |ARGB| order on big endian */
-        uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
-        /* add one to move past the alpha byte */
-        qcms_transform_data(transform,
-                       (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
-                       1);
-        out.~gfxRGBA();
-        new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
-#endif
-    }
-
-    else if (&out != &in)
-        out = in;
-}
-
 qcms_profile *
 gfxPlatform::GetPlatformCMSOutputProfile()
 {
     return nullptr;
 }
 
-void
-gfxPlatform::CreateCMSOutputProfile()
-{
-    if (!gCMSOutputProfile) {
-        /* Determine if we're using the internal override to force sRGB as
-           an output profile for reftests. See Bug 452125.
-
-           Note that we don't normally (outside of tests) set a
-           default value of this preference, which means nsIPrefBranch::GetBoolPref
-           will typically throw (and leave its out-param untouched).
-         */
-        if (Preferences::GetBool("gfx.color_management.force_srgb", false)) {
-            gCMSOutputProfile = GetCMSsRGBProfile();
-        }
-
-        if (!gCMSOutputProfile) {
-            nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
-            if (!fname.IsEmpty()) {
-                gCMSOutputProfile = qcms_profile_from_path(fname);
-            }
-        }
-
-        if (!gCMSOutputProfile) {
-            gCMSOutputProfile =
-                gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
-        }
-
-        /* Determine if the profile looks bogus. If so, close the profile
-         * and use sRGB instead. See bug 460629, */
-        if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
-            NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
-                         "Builtin sRGB profile tagged as bogus!!!");
-            qcms_profile_release(gCMSOutputProfile);
-            gCMSOutputProfile = nullptr;
-        }
-
-        if (!gCMSOutputProfile) {
-            gCMSOutputProfile = GetCMSsRGBProfile();
-        }
-        /* Precache the LUT16 Interpolations for the output profile. See
-           bug 444661 for details. */
-        qcms_profile_precache_output_transform(gCMSOutputProfile);
-    }
-}
-
-qcms_profile *
-gfxPlatform::GetCMSOutputProfile()
-{
-    return gCMSOutputProfile;
-}
-
-qcms_profile *
-gfxPlatform::GetCMSsRGBProfile()
-{
-    if (!gCMSsRGBProfile) {
-
-        /* Create the profile using qcms. */
-        gCMSsRGBProfile = qcms_profile_sRGB();
-    }
-    return gCMSsRGBProfile;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSRGBTransform()
-{
-    if (!gCMSRGBTransform) {
-        qcms_profile *inProfile, *outProfile;
-        outProfile = GetCMSOutputProfile();
-        inProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
-                                              outProfile, QCMS_DATA_RGB_8,
-                                             QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSRGBTransform;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSInverseRGBTransform()
-{
-    if (!gCMSInverseRGBTransform) {
-        qcms_profile *inProfile, *outProfile;
-        inProfile = GetCMSOutputProfile();
-        outProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
-                                                     outProfile, QCMS_DATA_RGB_8,
-                                                     QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSInverseRGBTransform;
-}
-
-qcms_transform *
-gfxPlatform::GetCMSRGBATransform()
-{
-    if (!gCMSRGBATransform) {
-        qcms_profile *inProfile, *outProfile;
-        outProfile = GetCMSOutputProfile();
-        inProfile = GetCMSsRGBProfile();
-
-        if (!inProfile || !outProfile)
-            return nullptr;
-
-        gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
-                                               outProfile, QCMS_DATA_RGBA_8,
-                                               QCMS_INTENT_PERCEPTUAL);
-    }
-
-    return gCMSRGBATransform;
-}
-
-/* Shuts down various transforms and profiles for CMS. */
-static void ShutdownCMS()
-{
-
-    if (gCMSRGBTransform) {
-        qcms_transform_release(gCMSRGBTransform);
-        gCMSRGBTransform = nullptr;
-    }
-    if (gCMSInverseRGBTransform) {
-        qcms_transform_release(gCMSInverseRGBTransform);
-        gCMSInverseRGBTransform = nullptr;
-    }
-    if (gCMSRGBATransform) {
-        qcms_transform_release(gCMSRGBATransform);
-        gCMSRGBATransform = nullptr;
-    }
-    if (gCMSOutputProfile) {
-        qcms_profile_release(gCMSOutputProfile);
-
-        // handle the aliased case
-        if (gCMSsRGBProfile == gCMSOutputProfile)
-            gCMSsRGBProfile = nullptr;
-        gCMSOutputProfile = nullptr;
-    }
-    if (gCMSsRGBProfile) {
-        qcms_profile_release(gCMSsRGBProfile);
-        gCMSsRGBProfile = nullptr;
-    }
-
-    // Reset the state variables
-    gCMSIntent = -2;
-    gCMSMode = eCMSMode_Off;
-    gCMSInitialized = false;
-}
-
-static void MigratePrefs()
-{
-    /* Migrate from the boolean color_management.enabled pref - we now use
-       color_management.mode. */
-    if (Preferences::HasUserValue("gfx.color_management.enabled")) {
-        if (Preferences::GetBool("gfx.color_management.enabled", false)) {
-            Preferences::SetInt("gfx.color_management.mode", static_cast<int32_t>(eCMSMode_All));
-        }
-        Preferences::ClearUser("gfx.color_management.enabled");
-    }
-}
-
 // default SetupClusterBoundaries, based on Unicode properties;
 // platform subclasses may override if they wish
 void
 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
 {
     if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
         // 8-bit text doesn't have clusters.
         // XXX is this true in all languages???
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -88,23 +88,16 @@ enum eFontPrefLang {
 
     eFontPrefLang_Others      = 30, // x-unicode
     eFontPrefLang_UserDefined = 31,
 
     eFontPrefLang_CJKSet      = 32, // special code for CJK set
     eFontPrefLang_AllCount    = 33
 };
 
-enum eCMSMode {
-    eCMSMode_Off          = 0,     // No color management
-    eCMSMode_All          = 1,     // Color manage everything
-    eCMSMode_TaggedOnly   = 2,     // Color manage tagged Images Only
-    eCMSMode_AllCount     = 3
-};
-
 enum eGfxLog {
     // all font enumerations, localized names, fullname/psnames, cmap loads
     eGfxLog_fontlist         = 0,
     // timing info on font initialization
     eGfxLog_fontinit         = 1,
     // dump text runs, font matching, system fallback for content
     eGfxLog_textrun          = 2,
     // dump text runs, font matching, system fallback for chrome
@@ -496,65 +489,16 @@ public:
     /**
      * Is it possible to use buffer rotation
      */
     static bool BufferRotationEnabled();
     static void DisableBufferRotation();
 
     static bool ComponentAlphaEnabled();
 
-    /**
-     * Are we going to try color management?
-     */
-    static eCMSMode GetCMSMode();
-
-    /**
-     * Determines the rendering intent for color management.
-     *
-     * If the value in the pref gfx.color_management.rendering_intent is a
-     * valid rendering intent as defined in gfx/qcms/qcms.h, that
-     * value is returned. Otherwise, -1 is returned and the embedded intent
-     * should be used.
-     *
-     * See bug 444014 for details.
-     */
-    static int GetRenderingIntent();
-
-    /**
-     * Convert a pixel using a cms transform in an endian-aware manner.
-     *
-     * Sets 'out' to 'in' if transform is nullptr.
-     */
-    static void TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform);
-
-    /**
-     * Return the output device ICC profile.
-     */
-    static qcms_profile* GetCMSOutputProfile();
-
-    /**
-     * Return the sRGB ICC profile.
-     */
-    static qcms_profile* GetCMSsRGBProfile();
-
-    /**
-     * Return sRGB -> output device transform.
-     */
-    static qcms_transform* GetCMSRGBTransform();
-
-    /**
-     * Return output -> sRGB device transform.
-     */
-    static qcms_transform* GetCMSInverseRGBTransform();
-
-    /**
-     * Return sRGBA -> output device transform.
-     */
-    static qcms_transform* GetCMSRGBATransform();
-
     virtual void FontsPrefsChanged(const char *aPref);
 
     void OrientationSyncPrefsObserverChanged();
 
     int32_t GetBidiNumeralOption();
 
     /**
      * Returns a 1x1 surface that can be used to create graphics contexts
@@ -673,27 +617,24 @@ protected:
     int32_t mUseHarfBuzzScripts;
 
 private:
     /**
      * Start up Thebes.
      */
     static void Init();
 
-    static void CreateCMSOutputProfile();
-
     friend int RecordingPrefChanged(const char *aPrefName, void *aClosure);
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     virtual bool SupportsOffMainThreadCompositing() { return true; }
 
     nsRefPtr<gfxASurface> mScreenReferenceSurface;
     nsTArray<uint32_t> mCJKPrefLangs;
-    nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     nsCOMPtr<nsIObserver> mOrientationSyncPrefsObserver;
 
     // The preferred draw target backend to use for canvas
     mozilla::gfx::BackendType mPreferredCanvasBackend;
     // The fallback draw target backend to use for canvas, if the preferred backend fails
     mozilla::gfx::BackendType mFallbackCanvasBackend;
     // The backend to use for content
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -11,16 +11,17 @@ EXPORTS += [
     'gfx2DGlue.h',
     'gfx3DMatrix.h',
     'gfxASurface.h',
     'gfxAlphaRecovery.h',
     'gfxBaseSharedMemorySurface.h',
     'gfxBlur.h',
     'gfxCachedTempSurface.h',
     'gfxColor.h',
+    'gfxColorManagement.h',
     'gfxContext.h',
     'gfxDrawable.h',
     'gfxFailure.h',
     'gfxFont.h',
     'gfxFontConstants.h',
     'gfxFontFeatures.h',
     'gfxFontTest.h',
     'gfxFontUtils.h',
@@ -231,16 +232,17 @@ if CONFIG['INTEL_ARCHITECTURE']:
 
 CPP_SOURCES += [
     'gfx3DMatrix.cpp',
     'gfxASurface.cpp',
     'gfxAlphaRecovery.cpp',
     'gfxBaseSharedMemorySurface.cpp',
     'gfxBlur.cpp',
     'gfxCachedTempSurface.cpp',
+    'gfxColorManagement.cpp',
     'gfxContext.cpp',
     'gfxDrawable.cpp',
     'gfxFont.cpp',
     'gfxFontFeatures.cpp',
     'gfxFontMissingGlyphs.cpp',
     'gfxFontTest.cpp',
     'gfxFontUtils.cpp',
     'gfxGraphiteShaper.cpp',
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -40,17 +40,17 @@ mailing address.
 
 #include <stddef.h>
 
 #include "nsGIFDecoder2.h"
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 
 #include "gfxColor.h"
-#include "gfxPlatform.h"
+#include "gfxColorManagement.h"
 #include "qcms.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace image {
 
 /*
  * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
@@ -499,18 +499,18 @@ nsGIFDecoder2::DoLzw(const uint8_t *q)
 
 /** 
  * Expand the colormap from RGB to Packed ARGB as needed by Cairo.
  * And apply any LCMS transformation.
  */
 static void ConvertColormap(uint32_t *aColormap, uint32_t aColors)
 {
   // Apply CMS transformation if enabled and available
-  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
-    qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
+  if (gfxColorManagement::Instance().GetMode() == eCMSMode_All) {
+    qcms_transform *transform = gfxColorManagement::Instance().GetRGBTransform();
     if (transform)
       qcms_transform_data(transform, aColormap, aColormap, aColors);
   }
   // Convert from the GIF's RGB format to the Cairo format.
   // Work from end to begin, because of the in-place expansion
   uint8_t *from = ((uint8_t *)aColormap) + 3 * aColors;
   uint32_t *to = aColormap + aColors;
 
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -9,21 +9,20 @@
 #include "Orientation.h"
 #include "EXIF.h"
 
 #include "nsIInputStream.h"
 
 #include "nspr.h"
 #include "nsCRT.h"
 #include "gfxColor.h"
+#include "gfxColorManagement.h"
 
 #include "jerror.h"
 
-#include "gfxPlatform.h"
-
 extern "C" {
 #include "iccjpeg.h"
 }
 
 #if defined(IS_BIG_ENDIAN)
 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
 #else
 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
@@ -132,17 +131,17 @@ Telemetry::ID
 nsJPEGDecoder::SpeedHistogram()
 {
   return Telemetry::IMAGE_DECODE_SPEED_JPEG;
 }
 
 void
 nsJPEGDecoder::InitInternal()
 {
-  mCMSMode = gfxPlatform::GetCMSMode();
+  mCMSMode = gfxColorManagement::Instance().GetMode();
   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
     mCMSMode = eCMSMode_Off;
 
   /* We set up the normal JPEG error routines, then override error_exit. */
   mInfo.err = jpeg_std_error(&mErr.pub);
   /*   mInfo.err = jpeg_std_error(&mErr.pub); */
   mErr.pub.error_exit = my_error_exit;
   /* Establish the setjmp return context for my_error_exit to use. */
@@ -309,27 +308,28 @@ nsJPEGDecoder::WriteInternal(const char 
          * code dealt with lcms types. Add something like this
          * back when we gain support for CMYK.
          */
         /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
         if (mInfo.out_color_space == JCS_CMYK)
           type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
 #endif
 
-        if (gfxPlatform::GetCMSOutputProfile()) {
+        const gfxColorManagement& colorManagement = gfxColorManagement::Instance();
+        if (colorManagement.GetOutputProfile()) {
 
           /* Calculate rendering intent. */
-          int intent = gfxPlatform::GetRenderingIntent();
+          int intent = colorManagement.GetRenderingIntent();
           if (intent == -1)
               intent = qcms_profile_get_rendering_intent(mInProfile);
 
           /* Create the color management transform. */
           mTransform = qcms_transform_create(mInProfile,
                                           type,
-                                          gfxPlatform::GetCMSOutputProfile(),
+                                          colorManagement.GetOutputProfile(),
                                           QCMS_DATA_RGB_8,
                                           (qcms_intent)intent);
         }
       } else {
 #ifdef DEBUG_tor
         fprintf(stderr, "ICM profile colorspace mismatch\n");
 #endif
       }
@@ -616,17 +616,17 @@ nsJPEGDecoder::OutputScanlines(bool* sus
           /* Convert from CMYK to RGB */
           /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
           /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
           cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
           sampleRow += mInfo.output_width;
         }
         if (mCMSMode == eCMSMode_All) {
           /* No embedded ICC profile - treat as sRGB */
-          qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
+          qcms_transform *transform = gfxColorManagement::Instance().GetRGBTransform();
           if (transform) {
             qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
           }
         }
       }
 
       // counter for while() loops below
       uint32_t idx = mInfo.output_width;
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -10,22 +10,22 @@
 #include "nsMemory.h"
 #include "nsRect.h"
 
 #include "nsIInputStream.h"
 
 #include "RasterImage.h"
 
 #include "gfxColor.h"
+#include "gfxColorManagement.h"
 #include "nsColor.h"
 
 #include "nspr.h"
 #include "png.h"
 
-#include "gfxPlatform.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace image {
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *
 GetPNGLog()
@@ -202,17 +202,17 @@ void nsPNGDecoder::EndImageFrame()
 void
 nsPNGDecoder::InitInternal()
 {
   // For size decodes, we don't need to initialize the png decoder
   if (IsSizeDecode()) {
     return;
   }
 
-  mCMSMode = gfxPlatform::GetCMSMode();
+  mCMSMode = gfxColorManagement::Instance().GetMode();
   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
     mCMSMode = eCMSMode_Off;
   mDisablePremultipliedAlpha = (mDecodeFlags & DECODER_NO_PREMULTIPLY_ALPHA) != 0;
 
 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
   static png_byte color_chunks[]=
        { 99,  72,  82,  77, '\0',   /* cHRM */
         105,  67,  67,  80, '\0'};  /* iCCP */
@@ -548,49 +548,50 @@ nsPNGDecoder::info_callback(png_structp 
   }
 
   if (bit_depth == 16)
     png_set_scale_16(png_ptr);
 
   qcms_data_type inType = QCMS_DATA_RGBA_8;
   uint32_t intent = -1;
   uint32_t pIntent;
+  const gfxColorManagement& colorManagement = gfxColorManagement::Instance();
   if (decoder->mCMSMode != eCMSMode_Off) {
-    intent = gfxPlatform::GetRenderingIntent();
+    intent = colorManagement.GetRenderingIntent();
     decoder->mInProfile = PNGGetColorProfile(png_ptr, info_ptr,
                                              color_type, &inType, &pIntent);
     /* If we're not mandating an intent, use the one from the image. */
     if (intent == uint32_t(-1))
       intent = pIntent;
   }
-  if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) {
+  if (decoder->mInProfile && colorManagement.GetOutputProfile()) {
     qcms_data_type outType;
 
     if (color_type & PNG_COLOR_MASK_ALPHA || num_trans)
       outType = QCMS_DATA_RGBA_8;
     else
       outType = QCMS_DATA_RGB_8;
 
     decoder->mTransform = qcms_transform_create(decoder->mInProfile,
                                            inType,
-                                           gfxPlatform::GetCMSOutputProfile(),
+                                           colorManagement.GetOutputProfile(),
                                            outType,
                                            (qcms_intent)intent);
   } else {
     png_set_gray_to_rgb(png_ptr);
 
     // only do gamma correction if CMS isn't entirely disabled
     if (decoder->mCMSMode != eCMSMode_Off)
       PNGDoGammaCorrection(png_ptr, info_ptr);
 
     if (decoder->mCMSMode == eCMSMode_All) {
       if (color_type & PNG_COLOR_MASK_ALPHA || num_trans)
-        decoder->mTransform = gfxPlatform::GetCMSRGBATransform();
+        decoder->mTransform = colorManagement.GetRGBATransform();
       else
-        decoder->mTransform = gfxPlatform::GetCMSRGBTransform();
+        decoder->mTransform = colorManagement.GetRGBTransform();
     }
   }
 
   /* let libpng expand interlaced images */
   if (interlace_type == PNG_INTERLACE_ADAM7) {
     /* number_passes = */
     png_set_interlace_handling(png_ptr);
   }
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -28,17 +28,17 @@
 #include "nsStyleConsts.h"
 #include "nsNativeThemeColors.h"
 #include "nsChildView.h"
 #include "nsCocoaFeatures.h"
 #include "nsIScreenManager.h"
 #include "nsIWidgetListener.h"
 #include "nsIPresShell.h"
 
-#include "gfxPlatform.h"
+#include "gfxColorManagement.h"
 #include "qcms.h"
 
 #include "mozilla/Preferences.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
@@ -1984,18 +1984,18 @@ NS_IMETHODIMP nsCocoaWindow::SetWindowTi
   // If they pass a color with a complete transparent alpha component, use the
   // native titlebar appearance.
   if (NS_GET_A(aColor) == 0) {
     [mWindow setTitlebarColor:nil forActiveWindow:(BOOL)aActive]; 
   } else {
     // Transform from sRGBA to monitor RGBA. This seems like it would make trying
     // to match the system appearance lame, so probably we just shouldn't color 
     // correct chrome.
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
-      qcms_transform *transform = gfxPlatform::GetCMSRGBATransform();
+    if (gfxColorManagement::Instance().GetMode() == eCMSMode_All) {
+      qcms_transform *transform = gfxColorManagement::Instance().GetRGBATransform();
       if (transform) {
         uint8_t color[3];
         color[0] = NS_GET_R(aColor);
         color[1] = NS_GET_G(aColor);
         color[2] = NS_GET_B(aColor);
         qcms_transform_data(transform, color, color, 1);
         aColor = NS_RGB(color[0], color[1], color[2]);
       }
--- a/widget/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/xpwidgets/nsXPLookAndFeel.cpp
@@ -8,17 +8,17 @@
 #include "nscore.h"
 
 #include "nsXPLookAndFeel.h"
 #include "nsLookAndFeel.h"
 #include "nsCRT.h"
 #include "nsFont.h"
 #include "mozilla/Preferences.h"
 
-#include "gfxPlatform.h"
+#include "gfxColorManagement.h"
 #include "qcms.h"
 
 #ifdef DEBUG
 #include "nsSize.h"
 #endif
 
 using namespace mozilla;
 
@@ -611,19 +611,19 @@ nsXPLookAndFeel::GetColorImpl(ColorID aI
   if (aID == eColorID_TextHighlightForeground) {
     // The foreground color for the matched text in findbar highlighting
     // Used with nsISelectionController::SELECTION_FIND
     aResult = NS_RGB(0xff, 0xff, 0xff);
     return NS_OK;
   }
 
   if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
-    if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
+    if ((gfxColorManagement::Instance().GetMode() == eCMSMode_All) &&
          !IsSpecialColor(aID, aResult)) {
-      qcms_transform *transform = gfxPlatform::GetCMSInverseRGBTransform();
+      qcms_transform *transform = gfxColorManagement::Instance().GetInverseRGBTransform();
       if (transform) {
         uint8_t color[3];
         color[0] = NS_GET_R(aResult);
         color[1] = NS_GET_G(aResult);
         color[2] = NS_GET_B(aResult);
         qcms_transform_data(transform, color, color, 1);
         aResult = NS_RGB(color[0], color[1], color[2]);
       }