Firefox honors embedded ICC intent flag - bug 444014 r=vlad
authorBobby Holley <bholley@mozilla.com>
Wed, 23 Jul 2008 10:33:12 -0700
changeset 16152 68b0caac284dd191e3ddb7a17161f4539666ec0c
parent 16151 aeef0397faa9d4fed32905072f2b6ef716f4bc81
child 16153 fd1c0f6abf6d8cc0822e2012b34e0a37fa2c61d3
push id801
push usertellrob@gmail.com
push dateWed, 23 Jul 2008 17:33:29 +0000
treeherderautoland@68b0caac284d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs444014
milestone1.9.1a2pre
Firefox honors embedded ICC intent flag - bug 444014 r=vlad
gfx/thebes/public/gfxPlatform.h
gfx/thebes/src/gfxPlatform.cpp
modules/lcms/include/lcms.h
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
modules/libpr0n/decoders/png/nsPNGDecoder.cpp
modules/libpref/src/init/all.js
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -211,16 +211,28 @@ public:
     static void AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang);
     
     /**
      * Are we going to try color management?
      */
     static PRBool IsCMSEnabled();
 
     /**
+     * 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 modules/lcms/include/lcms.h, that
+     * value is returned. Otherwise, -1 is returned and the embedded intent
+     * should be used.
+     *
+     * See bug 444014 for details.
+     */
+    static int GetRenderingIntent();
+
+    /**
      * Return the output device ICC profile.
      */
     static cmsHPROFILE GetCMSOutputProfile();
 
     /**
      * Return the sRGB ICC profile.
      */
     static cmsHPROFILE GetCMSsRGBProfile();
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -464,16 +464,55 @@ gfxPlatform::IsCMSEnabled()
             if (NS_SUCCEEDED(rv)) {
                 sEnabled = enabled;
             }
         }
     }
     return sEnabled;
 }
 
+/* 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) {
+
+        /* 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("gfx.color_management.rendering_intent", 
+                                            &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;
+
+                /* If the pref is out of range, use embedded profile. */
+                else
+                    sIntent = -1;
+            }
+        }
+
+        /* If we didn't get a valid intent from prefs, use the default. */
+        if (sIntent == -2) 
+            sIntent = INTENT_DEFAULT;
+    }
+    return sIntent;
+}
+
+
 cmsHPROFILE
 gfxPlatform::GetPlatformCMSOutputProfile()
 {
     return nsnull;
 }
 
 cmsHPROFILE
 gfxPlatform::GetCMSOutputProfile()
--- a/modules/lcms/include/lcms.h
+++ b/modules/lcms/include/lcms.h
@@ -1041,20 +1041,24 @@ LCMSAPI void          LCMSEXPORT cmsSetC
 LCMSAPI void          LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs);
 LCMSAPI void          LCMSEXPORT cmsSetRenderingIntent(cmsHPROFILE hProfile, int RenderingIntent);
 LCMSAPI void          LCMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, DWORD Flags);
 LCMSAPI void          LCMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, DWORD Flags);
 LCMSAPI void          LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID);
 
 // Intents
 
+/* Note - If the numbers here change, the rendering_intent pref in Mozilla's
+   modules/libpref/init/all.js must change as well! */
 #define INTENT_PERCEPTUAL                 0
 #define INTENT_RELATIVE_COLORIMETRIC      1
 #define INTENT_SATURATION                 2
 #define INTENT_ABSOLUTE_COLORIMETRIC      3
+#define INTENT_MIN INTENT_PERCEPTUAL
+#define INTENT_MAX INTENT_ABSOLUTE_COLORIMETRIC
 
 // Flags
 
 #define cmsFLAGS_MATRIXINPUT              0x0001
 #define cmsFLAGS_MATRIXOUTPUT             0x0002
 #define cmsFLAGS_MATRIXONLY               (cmsFLAGS_MATRIXINPUT|cmsFLAGS_MATRIXOUTPUT)
 
 #define cmsFLAGS_NOWHITEONWHITEFIXUP      0x0004    // Don't hot fix scum dot   
--- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
@@ -397,24 +397,33 @@ nsresult nsJPEGDecoder::ProcessData(cons
           PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
                  ("} (unknown colorpsace (2))"));
           return NS_ERROR_UNEXPECTED;
         }
 
         /* 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);
+        
 
-        if (gfxPlatform::GetCMSOutputProfile())
+        if (gfxPlatform::GetCMSOutputProfile()) {
+
+          /* Calculate rendering intent. */
+          int intent = gfxPlatform::GetRenderingIntent();
+          if (intent == -1)
+              intent = cmsTakeRenderingIntent(mInProfile);
+
+          /* Create the color management transform. */
           mTransform = cmsCreateTransform(mInProfile,
                                           type,
                                           gfxPlatform::GetCMSOutputProfile(),
                                           TYPE_RGB_8,
-                                          cmsTakeRenderingIntent(mInProfile),
+                                          intent,
                                           0);
+        }
       } else {
 #ifdef DEBUG_tor
         fprintf(stderr, "ICM profile colorspace mismatch\n");
 #endif
       }
     }
 
     if (!mTransform) {
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
@@ -373,17 +373,17 @@ NS_IMETHODIMP nsPNGDecoder::WriteFrom(ns
 }
 
 // Adapted from http://www.littlecms.com/pngchrm.c example code
 static cmsHPROFILE
 PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr,
                    int color_type, PRUint32 *inType, PRUint32 *intent)
 {
   cmsHPROFILE profile = nsnull;
-  *intent = INTENT_PERCEPTUAL;   // XXX: should this be the default?
+  *intent = INTENT_PERCEPTUAL; // Our default
 
 #ifndef PNG_NO_READ_iCCP
   // First try to see if iCCP chunk is present
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
     png_uint_32 profileLen;
     char *profileData, *profileName;
     int compression;
 
@@ -526,20 +526,24 @@ info_callback(png_structp png_ptr, png_i
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
     png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
     png_set_expand(png_ptr);
   }
 
   if (bit_depth == 16)
     png_set_strip_16(png_ptr);
 
-  PRUint32 inType, intent;
+  PRUint32 inType, intent, pIntent;
   if (gfxPlatform::IsCMSEnabled()) {
+    intent = gfxPlatform::GetRenderingIntent();
     decoder->mInProfile = PNGGetColorProfile(png_ptr, info_ptr,
-                                             color_type, &inType, &intent);
+                                             color_type, &inType, &pIntent);
+    /* If we're not mandating an intent, use the one from the image. */
+    if (intent == -1)
+      intent = pIntent;
   }
   if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) {
     PRUint32 outType;
 
     if (color_type & PNG_COLOR_MASK_ALPHA || num_trans)
       outType = TYPE_RGBA_8;
     else
       outType = TYPE_RGB_8;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -125,16 +125,17 @@ pref("browser.chrome.toolbar_style",    
 // max image size for which it is placed in the tab icon for tabbrowser.
 // if 0, no images are used for tab icons for image documents.
 pref("browser.chrome.image_icons.max_size", 1024);
 
 pref("browser.triple_click_selects_paragraph", true);
 
 pref("gfx.color_management.enabled", false);
 pref("gfx.color_management.display_profile", "");
+pref("gfx.color_management.rendering_intent", 0);
 
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 #ifndef XP_MACOSX
 // Tab focus model bit field:
 // 1 focuses text controls, 2 focuses other form elements, 4 adds links.
 // Most users will want 1, 3, or 7.