Force cms to use sRGB as an output profile during reftests -
bug 452125.r=vlad
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -37,16 +37,18 @@
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_PLATFORM_H
#define GFX_PLATFORM_H
#include "prtypes.h"
#include "nsVoidArray.h"
+#include "nsIObserver.h"
+
#include "gfxTypes.h"
#include "gfxASurface.h"
#ifdef XP_OS2
#undef OS2EMX_PLAIN_CHAR
#endif
typedef void* cmsHPROFILE;
@@ -261,11 +263,13 @@ public:
static cmsHTRANSFORM GetCMSRGBATransform();
protected:
gfxPlatform() { }
virtual ~gfxPlatform();
private:
virtual cmsHPROFILE GetPlatformCMSOutputProfile();
+
+ nsCOMPtr<nsIObserver> overrideObserver;
};
#endif /* GFX_PLATFORM_H */
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -55,43 +55,79 @@
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxTextRunCache.h"
#include "gfxTextRunWordCache.h"
#include "nsIPref.h"
#include "nsServiceManagerUtils.h"
+#include "nsWeakReference.h"
+
#ifdef MOZ_ENABLE_GLITZ
#include <stdlib.h>
#endif
#include "cairo.h"
#include "lcms.h"
#include "plstr.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
+#include "nsIPrefBranch2.h"
gfxPlatform *gPlatform = nsnull;
int gGlitzState = -1;
// These two may point to the same profile
static cmsHPROFILE gCMSOutputProfile = nsnull;
static cmsHPROFILE gCMSsRGBProfile = nsnull;
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[] = {
"x-western",
"x-central-euro",
"ja",
"zh-TW",
"zh-CN",
@@ -180,56 +216,44 @@ gfxPlatform::Init()
NS_ERROR("Could not initialize gfxTextRunCache");
Shutdown();
return rv;
}
/* Pref migration hook. */
MigratePrefs();
+ /* Create and register our CMS Override observer. */
+ gPlatform->overrideObserver = new SRGBOverrideObserver();
+ nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ if (prefs)
+ prefs->AddObserver(CMForceSRGBPrefName, gPlatform->overrideObserver, PR_TRUE);
+
return NS_OK;
}
void
gfxPlatform::Shutdown()
{
// These may be called before the corresponding subsystems have actually
// started up. That's OK, they can handle it.
gfxTextRunCache::Shutdown();
gfxTextRunWordCache::Shutdown();
gfxFontCache::Shutdown();
#if defined(XP_MACOSX)
gfxQuartzFontCache::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<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ if (prefs)
+ prefs->RemoveObserver(CMForceSRGBPrefName, gPlatform->overrideObserver);
delete gPlatform;
gPlatform = nsnull;
}
gfxPlatform::~gfxPlatform()
{
// The cairo folks think we should only clean up in debug builds,
@@ -460,69 +484,63 @@ gfxPlatform::AppendPrefLang(eFontPrefLan
aPrefLangs[aLen] = aAddLang;
aLen++;
}
}
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<nsIPrefBranch> 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<eCMSMode>(mode);
+ gCMSMode = static_cast<eCMSMode>(mode);
}
}
}
- return sMode;
+ return gCMSMode;
}
/* Chris Murphy (CM consultant) suggests this as a default in the event that we
cannot reproduce relative + Black Point Compensation. BPC brings an
unacceptable performance overhead, so we go with perceptual. */
#define INTENT_DEFAULT INTENT_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<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
PRInt32 pIntent;
nsresult rv = prefs->GetIntPref(CMIntentPrefName, &pIntent);
if (NS_SUCCEEDED(rv)) {
/* 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;
}
cmsHPROFILE
gfxPlatform::GetPlatformCMSOutputProfile()
{
return nsnull;
}
@@ -535,28 +553,41 @@ gfxPlatform::GetCMSOutputProfile()
#ifdef DEBUG_tor
cmsErrorAction(LCMS_ERROR_SHOW);
#else
cmsErrorAction(LCMS_ERROR_IGNORE);
#endif
nsCOMPtr<nsIPrefBranch> 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());
+ }
}
}
if (!gCMSOutputProfile) {
gCMSOutputProfile =
gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
}
@@ -639,16 +670,51 @@ gfxPlatform::GetCMSRGBATransform()
gCMSRGBATransform = cmsCreateTransform(inProfile, TYPE_RGBA_8,
outProfile, TYPE_RGBA_8,
INTENT_PERCEPTUAL, cmsFLAGS_FLOATSHAPER);
}
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()
{
/* Load the pref service. If we don't get it die quietly since this isn't
critical code. */
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (!prefs)
return;
--- a/layout/tools/reftest/reftest-cmdline.js
+++ b/layout/tools/reftest/reftest-cmdline.js
@@ -92,16 +92,22 @@ RefTestCmdLineHandler.prototype =
catch (e) {
return;
}
}
catch (e) {
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",
"chrome,dialog=no,all", args);
cmdLine.preventDefault = true;
},
helpInfo : " -reftest <file> Run layout acceptance tests on given manifest.\n"
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -116,16 +116,21 @@ function OnRefTestLoad()
//gBrowser.loadURI('data:text/plain,' + ex);
dump("REFTEST TEST-FAIL | | EXCEPTION: " + ex + "\n");
DoneTests();
}
}
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);
}
function ReadTopManifest(aFileURL)
{
gURLs = new Array();
var url = gIOService.newURI(aFileURL, null, null);
if (!url || !url.schemeIs("file"))
--- a/modules/lcms/src/cmsxform.c
+++ b/modules/lcms/src/cmsxform.c
@@ -249,16 +249,32 @@ void NullXFORM(_LPcmsTRANSFORM p,
WORD wIn[MAXCHANNELS];
register unsigned int i, n;
accum = (LPBYTE) in;
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);
output = p -> ToOutput(p, wIn, output);
}
}
@@ -1518,16 +1534,22 @@ static
if ((*FromTagPtr == 0) &&
(*ToTagPtr == 0) &&
(!p->PreviewProfile) &&
(p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) &&
(p -> EntryColorSpace == icSigRgbData) &&
(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)
{
#ifndef HAVE_SSE2_INTEL_MNEMONICS
// Turn it off if we can't compile it
p -> dwOriginalFlags &= ~cmsFLAGS_FLOATSHAPER;