From 107ed7aaa9e2e72501225c844607d9bda71cbd70 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 8 Sep 2008 14:47:26 -0700 Subject: [PATCH] Force cms to use sRGB as an output profile during reftests - bug 452125.r=vlad --- gfx/thebes/public/gfxPlatform.h | 4 + gfx/thebes/src/gfxPlatform.cpp | 168 +++++++++++++++++------- layout/tools/reftest/reftest-cmdline.js | 6 + layout/tools/reftest/reftest.js | 5 + modules/lcms/src/cmsxform.c | 22 ++++ 5 files changed, 154 insertions(+), 51 deletions(-) diff --git a/gfx/thebes/public/gfxPlatform.h b/gfx/thebes/public/gfxPlatform.h index 5f691a4289fc..9a0196460558 100644 --- a/gfx/thebes/public/gfxPlatform.h +++ b/gfx/thebes/public/gfxPlatform.h @@ -42,6 +42,8 @@ #include "prtypes.h" #include "nsVoidArray.h" +#include "nsIObserver.h" + #include "gfxTypes.h" #include "gfxASurface.h" @@ -266,6 +268,8 @@ protected: private: virtual cmsHPROFILE GetPlatformCMSOutputProfile(); + + nsCOMPtr overrideObserver; }; #endif /* GFX_PLATFORM_H */ diff --git a/gfx/thebes/src/gfxPlatform.cpp b/gfx/thebes/src/gfxPlatform.cpp index f34f4fe800e9..7ffc43e5f2d7 100644 --- a/gfx/thebes/src/gfxPlatform.cpp +++ b/gfx/thebes/src/gfxPlatform.cpp @@ -60,6 +60,8 @@ #include "nsIPref.h" #include "nsServiceManagerUtils.h" +#include "nsWeakReference.h" + #ifdef MOZ_ENABLE_GLITZ #include #endif @@ -70,6 +72,7 @@ #include "plstr.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" +#include "nsIPrefBranch2.h" gfxPlatform *gPlatform = nsnull; int gGlitzState = -1; @@ -82,11 +85,44 @@ static cmsHTRANSFORM gCMSRGBTransform = nsnull; static cmsHTRANSFORM gCMSInverseRGBTransform = nsnull; static cmsHTRANSFORM gCMSRGBATransform = nsnull; +static PRBool gCMSInitialized = PR_FALSE; +static eCMSMode gCMSMode = eCMSMode_Off; +static int gCMSIntent = -2; + static const char *CMPrefName = "gfx.color_management.mode"; static const char *CMPrefNameOld = "gfx.color_management.enabled"; static const char *CMIntentPrefName = "gfx.color_management.rendering_intent"; +static const char *CMProfilePrefName = "gfx.color_management.display_profile"; +static const char *CMForceSRGBPrefName = "gfx.color_management.force_srgb"; + +static void ShutdownCMS(); static void MigratePrefs(); +/* Class to listen for pref changes so that chrome code can dynamically + force sRGB as an output profile. See Bug #452125. */ +class SRGBOverrideObserver : 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; +} + + // 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[] = { @@ -185,6 +221,12 @@ gfxPlatform::Init() /* Pref migration hook. */ MigratePrefs(); + /* Create and register our CMS Override observer. */ + gPlatform->overrideObserver = new SRGBOverrideObserver(); + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) + prefs->AddObserver(CMForceSRGBPrefName, gPlatform->overrideObserver, PR_TRUE); + return NS_OK; } @@ -201,30 +243,12 @@ gfxPlatform::Shutdown() #endif // Free the various non-null transforms and loaded profiles - if (gCMSRGBTransform) { - cmsDeleteTransform(gCMSRGBTransform); - gCMSRGBTransform = nsnull; - } - if (gCMSInverseRGBTransform) { - cmsDeleteTransform(gCMSInverseRGBTransform); - gCMSInverseRGBTransform = nsnull; - } - if (gCMSRGBATransform) { - cmsDeleteTransform(gCMSRGBATransform); - gCMSRGBATransform = nsnull; - } - if (gCMSOutputProfile) { - cmsCloseProfile(gCMSOutputProfile); + ShutdownCMS(); - // handle the aliased case - if (gCMSsRGBProfile == gCMSOutputProfile) - gCMSsRGBProfile = nsnull; - gCMSOutputProfile = nsnull; - } - if (gCMSsRGBProfile) { - cmsCloseProfile(gCMSsRGBProfile); - gCMSsRGBProfile = nsnull; - } + /* Unregister our CMS Override callback. */ + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) + prefs->RemoveObserver(CMForceSRGBPrefName, gPlatform->overrideObserver); delete gPlatform; gPlatform = nsnull; @@ -465,22 +489,19 @@ gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPre eCMSMode gfxPlatform::GetCMSMode() { - static eCMSMode sMode = eCMSMode_Off; - static PRBool initialized = PR_FALSE; - - if (initialized == PR_FALSE) { - initialized = PR_TRUE; + if (gCMSInitialized == PR_FALSE) { + gCMSInitialized = PR_TRUE; nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefs) { PRInt32 mode; nsresult rv = prefs->GetIntPref(CMPrefName, &mode); if (NS_SUCCEEDED(rv) && (mode >= 0) && (mode < eCMSMode_AllCount)) { - sMode = static_cast(mode); + gCMSMode = static_cast(mode); } } } - return sMode; + return gCMSMode; } /* Chris Murphy (CM consultant) suggests this as a default in the event that we @@ -491,10 +512,7 @@ unacceptable performance overhead, so we go with perceptual. */ PRBool gfxPlatform::GetRenderingIntent() { - /* -2 means that we haven't tried querying the pref service yet. */ - static int sIntent = -2; - - if (sIntent == -2) { + if (gCMSIntent == -2) { /* Try to query the pref system for a rendering intent. */ nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -505,19 +523,19 @@ gfxPlatform::GetRenderingIntent() /* If the pref is within range, use it as an override. */ if ((pIntent >= INTENT_MIN) && (pIntent <= INTENT_MAX)) - sIntent = pIntent; + gCMSIntent = pIntent; /* If the pref is out of range, use embedded profile. */ else - sIntent = -1; + gCMSIntent = -1; } } /* If we didn't get a valid intent from prefs, use the default. */ - if (sIntent == -2) - sIntent = INTENT_DEFAULT; + if (gCMSIntent == -2) + gCMSIntent = INTENT_DEFAULT; } - return sIntent; + return gCMSIntent; } @@ -540,18 +558,31 @@ gfxPlatform::GetCMSOutputProfile() nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefs) { - nsXPIDLCString fname; - nsresult rv = - prefs->GetCharPref("gfx.color_management.display_profile", - getter_Copies(fname)); - if (NS_SUCCEEDED(rv) && !fname.IsEmpty()) { - gCMSOutputProfile = cmsOpenProfileFromFile(fname, "r"); -#ifdef DEBUG_tor - if (gCMSOutputProfile) - fprintf(stderr, - "ICM profile read from %s successfully\n", - fname.get()); -#endif + + nsresult rv; + + /* Determine if we're using the internal override to force sRGB as + an output profile for reftests. See Bug 452125. */ + PRBool hasSRGBOverride, doSRGBOverride; + rv = prefs->PrefHasUserValue(CMForceSRGBPrefName, &hasSRGBOverride); + if (NS_SUCCEEDED(rv) && hasSRGBOverride) { + rv = prefs->GetBoolPref(CMForceSRGBPrefName, &doSRGBOverride); + if (NS_SUCCEEDED(rv) && doSRGBOverride) + gCMSOutputProfile = GetCMSsRGBProfile(); + } + + if (!gCMSOutputProfile) { + + nsXPIDLCString fname; + rv = prefs->GetCharPref(CMProfilePrefName, + getter_Copies(fname)); + if (NS_SUCCEEDED(rv) && !fname.IsEmpty()) { + gCMSOutputProfile = cmsOpenProfileFromFile(fname, "r"); + if (gCMSOutputProfile) + fprintf(stderr, + "ICM profile read from %s successfully\n", + fname.get()); + } } } @@ -644,6 +675,41 @@ gfxPlatform::GetCMSRGBATransform() return gCMSRGBATransform; } +/* Shuts down various transforms and profiles for CMS. */ +static void ShutdownCMS() +{ + + if (gCMSRGBTransform) { + cmsDeleteTransform(gCMSRGBTransform); + gCMSRGBTransform = nsnull; + } + if (gCMSInverseRGBTransform) { + cmsDeleteTransform(gCMSInverseRGBTransform); + gCMSInverseRGBTransform = nsnull; + } + if (gCMSRGBATransform) { + cmsDeleteTransform(gCMSRGBATransform); + gCMSRGBATransform = nsnull; + } + if (gCMSOutputProfile) { + cmsCloseProfile(gCMSOutputProfile); + + // handle the aliased case + if (gCMSsRGBProfile == gCMSOutputProfile) + gCMSsRGBProfile = nsnull; + gCMSOutputProfile = nsnull; + } + if (gCMSsRGBProfile) { + cmsCloseProfile(gCMSsRGBProfile); + gCMSsRGBProfile = nsnull; + } + + // Reset the state variables + gCMSIntent = -2; + gCMSMode = eCMSMode_Off; + gCMSInitialized = PR_FALSE; +} + static void MigratePrefs() { diff --git a/layout/tools/reftest/reftest-cmdline.js b/layout/tools/reftest/reftest-cmdline.js index 90de0fc5532d..327cbbd3b501 100644 --- a/layout/tools/reftest/reftest-cmdline.js +++ b/layout/tools/reftest/reftest-cmdline.js @@ -97,6 +97,12 @@ RefTestCmdLineHandler.prototype = cmdLine.handleFlag("reftest", true); } + /* Force sRGB as an output profile for color management before we load a + window. */ + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch2); + prefs.setBoolPref("gfx.color_management.force_srgb", true); + var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] .getService(nsIWindowWatcher); wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank", diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 2022d4c3e6e2..8608353a22a1 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -121,6 +121,11 @@ function OnRefTestLoad() function OnRefTestUnload() { + /* Clear the sRGB forcing pref to leave the profile as we found it. */ + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch2); + prefs.clearUserPref("gfx.color_management.force_srgb"); + gBrowser.removeEventListener("load", OnDocumentLoad, true); } diff --git a/modules/lcms/src/cmsxform.c b/modules/lcms/src/cmsxform.c index 6b23625d3a27..c4f8f180845f 100644 --- a/modules/lcms/src/cmsxform.c +++ b/modules/lcms/src/cmsxform.c @@ -254,6 +254,22 @@ void NullXFORM(_LPcmsTRANSFORM p, output = (LPBYTE) out; n = Size; // Buffer len + // If the input and output formats are the same, + // we don't need to pack and unpack pixels + if (p -> InputFormat == p -> OutputFormat) { + + // Only copy bytes if the buffers aren't the same + if (in != out) { + + // Copy in a nondestructive manner in case + // the buffers overlap for some reason + memmove(out, in, + Size * T_BYTES(p -> InputFormat) * T_CHANNELS(p -> InputFormat)); + } + + return; + } + for (i=0; i < n; i++) { accum = p -> FromInput(p, wIn, accum); @@ -1523,6 +1539,12 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, (p -> ExitColorSpace == icSigRgbData) && !(p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)) { + // If the input profile pointer-matches with the output profile, + // optimize the transformation away into a null xform + if (p -> InputProfile == p -> OutputProfile) { + p -> xform = NullXFORM; + return p; + } // If the floating point path is requested, see if we support it if (p -> dwOriginalFlags & cmsFLAGS_FLOATSHAPER)