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.

--HG--
rename : gfx/thebes/gfxPlatform.cpp => gfx/thebes/gfxColorManagement.cpp
rename : gfx/thebes/gfxPlatform.h => gfx/thebes/gfxColorManagement.h
This commit is contained in:
Milan Sreckovic 2013-09-06 12:48:17 -07:00
parent 77d1d37b73
commit 5413b28258
12 changed files with 587 additions and 390 deletions

View File

@ -0,0 +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/. */
#include "gfxColorManagement.h"
#include "mozilla/Preferences.h"
#include "mozilla/Mutex.h"
#include "nsCRTGlue.h"
using namespace mozilla;
gfxColorManagement* gfxColorManagement::sInstance = nullptr;
// 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"
// 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 CMSPrefsObserver MOZ_FINAL : public nsIObserver,
public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
NS_IMPL_ISUPPORTS2(CMSPrefsObserver, nsIObserver, nsISupportsWeakReference)
NS_IMETHODIMP
CMSPrefsObserver::Observe(nsISupports*, const char*, const PRUnichar *aData)
{
return gfxColorManagement::InstanceNC().PreferencesModified(aData);
}
const gfxColorManagement&
gfxColorManagement::Instance()
{
if (!sInstance) {
sInstance = new gfxColorManagement;
}
return *sInstance;
}
gfxColorManagement&
gfxColorManagement::InstanceNC()
{
if (!sInstance) {
sInstance = new gfxColorManagement;
}
return *sInstance;
}
void
gfxColorManagement::Destroy()
{
if (sInstance) {
delete sInstance;
sInstance = nullptr;
}
}
bool
gfxColorManagement::Exists()
{
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");
}
gfxColorManagement::~gfxColorManagement()
{
// Unregister our CMS Override callback.
NS_ASSERTION(mPrefsObserver, "mPrefsObserver is already gone");
if (mPrefsObserver) {
Preferences::RemoveObservers(mPrefsObserver, kObservedCMSPrefs);
mPrefsObserver = nullptr;
}
ResetAll();
delete mPrefLock;
}
NS_IMETHODIMP
gfxColorManagement::PreferencesModified(const PRUnichar* aName)
{
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;
}
void gfxColorManagement::MigratePreferences()
{
// 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);
}
}
void gfxColorManagement::Initialize(qcms_profile* aDefaultPlatformProfile)
{
mDefaultPlatformProfile = aDefaultPlatformProfile;
// Migrate the old preferences first
MigratePreferences();
// 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
}
void gfxColorManagement::ResetAll()
{
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;
}
eCMSMode
gfxColorManagement::GetMode() const
{
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
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
{
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;
}
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
{
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;
}
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
gfxColorManagement::TransformPixel(const gfxRGBA& aIn, gfxRGBA& aOut,
qcms_transform* aTransform) const
{
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
}
else if (&aOut != &aIn)
aOut = aIn;
}
gfxColorManagement::gfxColorManagement(const gfxColorManagement&)
{
NS_ASSERTION(false, "Should not be calling gfxColorManagement copy constructor");
}
gfxColorManagement& gfxColorManagement::operator=(const gfxColorManagement&)
{
NS_ASSERTION(false, "Should not be calling gfxColorManagement::operator=");
return *this;
}

View File

@ -0,0 +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_COLORMANAGEMENT_H
#define GFX_COLORMANAGEMENT_H
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "gfxColor.h"
#include "nsString.h"
#include "qcms.h"
class gfxColorManagement;
namespace mozilla {
class Mutex;
}
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
};
/**
* 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();
};
#endif /* GFX_COLORMANAGEMENT_H */

View File

@ -16,6 +16,7 @@
#include "gfxContext.h"
#include "gfxColor.h"
#include "gfxColorManagement.h"
#include "gfxMatrix.h"
#include "gfxASurface.h"
#include "gfxPattern.h"
@ -1297,13 +1298,15 @@ gfxContext::ClipContainsRect(const gfxRect& aRect)
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
@ -1316,12 +1319,13 @@ gfxContext::SetColor(const gfxRGBA& c)
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

View File

@ -7,6 +7,7 @@
#include "gfxPattern.h"
#include "gfxASurface.h"
#include "gfxPlatform.h"
#include "gfxColorManagement.h"
#include "cairo.h"
@ -79,11 +80,13 @@ 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

View File

@ -81,6 +81,8 @@
#include "nsIGfxInfo.h"
#include "gfxColorManagement.h"
using namespace mozilla;
using namespace mozilla::layers;
@ -89,21 +91,6 @@ 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"
@ -118,30 +105,6 @@ 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"
@ -397,12 +360,8 @@ gfxPlatform::Init()
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);
@ -434,8 +393,6 @@ gfxPlatform::Init()
mozilla::Preferences::AddBoolVarCache(&sDrawFrameCounter,
"layers.frame-counter",
false);
CreateCMSOutputProfile();
}
void
@ -451,16 +408,11 @@ gfxPlatform::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;
@ -1486,255 +1438,12 @@ gfxPlatform::OffMainThreadCompositingEnabled()
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

View File

@ -93,13 +93,6 @@ enum eFontPrefLang {
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,
@ -501,55 +494,6 @@ public:
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();
@ -678,8 +622,6 @@ private:
*/
static void Init();
static void CreateCMSOutputProfile();
friend int RecordingPrefChanged(const char *aPrefName, void *aClosure);
virtual qcms_profile* GetPlatformCMSOutputProfile();
@ -688,7 +630,6 @@ private:
nsRefPtr<gfxASurface> mScreenReferenceSurface;
nsTArray<uint32_t> mCJKPrefLangs;
nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
nsCOMPtr<nsIObserver> mFontPrefsObserver;
nsCOMPtr<nsIObserver> mOrientationSyncPrefsObserver;

View File

@ -16,6 +16,7 @@ EXPORTS += [
'gfxBlur.h',
'gfxCachedTempSurface.h',
'gfxColor.h',
'gfxColorManagement.h',
'gfxContext.h',
'gfxDrawable.h',
'gfxFailure.h',
@ -236,6 +237,7 @@ CPP_SOURCES += [
'gfxBaseSharedMemorySurface.cpp',
'gfxBlur.cpp',
'gfxCachedTempSurface.cpp',
'gfxColorManagement.cpp',
'gfxContext.cpp',
'gfxDrawable.cpp',
'gfxFont.cpp',

View File

@ -45,7 +45,7 @@ mailing address.
#include "RasterImage.h"
#include "gfxColor.h"
#include "gfxPlatform.h"
#include "gfxColorManagement.h"
#include "qcms.h"
#include <algorithm>
@ -504,8 +504,8 @@ nsGIFDecoder2::DoLzw(const uint8_t *q)
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);
}

View File

@ -14,11 +14,10 @@
#include "nspr.h"
#include "nsCRT.h"
#include "gfxColor.h"
#include "gfxColorManagement.h"
#include "jerror.h"
#include "gfxPlatform.h"
extern "C" {
#include "iccjpeg.h"
}
@ -137,7 +136,7 @@ nsJPEGDecoder::SpeedHistogram()
void
nsJPEGDecoder::InitInternal()
{
mCMSMode = gfxPlatform::GetCMSMode();
mCMSMode = gfxColorManagement::Instance().GetMode();
if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
mCMSMode = eCMSMode_Off;
@ -314,17 +313,18 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
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);
}
@ -621,7 +621,7 @@ nsJPEGDecoder::OutputScanlines(bool* suspend)
}
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);
}

View File

@ -15,12 +15,12 @@
#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 {
@ -207,7 +207,7 @@ nsPNGDecoder::InitInternal()
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;
@ -553,15 +553,16 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_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)
@ -571,7 +572,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
decoder->mTransform = qcms_transform_create(decoder->mInProfile,
inType,
gfxPlatform::GetCMSOutputProfile(),
colorManagement.GetOutputProfile(),
outType,
(qcms_intent)intent);
} else {
@ -583,9 +584,9 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop 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();
}
}

View File

@ -33,7 +33,7 @@
#include "nsIWidgetListener.h"
#include "nsIPresShell.h"
#include "gfxPlatform.h"
#include "gfxColorManagement.h"
#include "qcms.h"
#include "mozilla/Preferences.h"
@ -1989,8 +1989,8 @@ NS_IMETHODIMP nsCocoaWindow::SetWindowTitlebarColor(nscolor aColor, bool aActive
// 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);

View File

@ -13,7 +13,7 @@
#include "nsFont.h"
#include "mozilla/Preferences.h"
#include "gfxPlatform.h"
#include "gfxColorManagement.h"
#include "qcms.h"
#ifdef DEBUG
@ -616,9 +616,9 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
}
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);