Bug 907196 - Split CreateCMSOutputProfile profile loading into GetCMSOutputProfileData. r=BenWa, r=jmuizelaar
☠☠ backed out by d9107f528b80 ☠ ☠
authorguozhu cheng <bengol2005@gmail.com>
Thu, 07 Nov 2013 18:20:08 +0800
changeset 163187 ef14be22d6f7963ba708d89daff536cc9fc956ce
parent 163186 f04c846c7492f1bf39abb9eb637f3cd0fee09157
child 163188 64a08871e0381881e85202b4f70af3dda1f59f5d
push id25984
push userryanvm@gmail.com
push dateMon, 13 Jan 2014 22:44:31 +0000
treeherdermozilla-central@425579efbac3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa, jmuizelaar
bugs907196
milestone29.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 907196 - Split CreateCMSOutputProfile profile loading into GetCMSOutputProfileData. r=BenWa, r=jmuizelaar
gfx/qcms/iccread.c
gfx/qcms/qcms.h
gfx/qcms/qcmsint.h
gfx/qcms/transform.c
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/qcms/iccread.c
+++ b/gfx/qcms/iccread.c
@@ -29,29 +29,33 @@
 
 /* It might be worth having a unified limit on content controlled
  * allocation per profile. This would remove the need for many
  * of the arbitrary limits that we used */
 
 typedef uint32_t be32;
 typedef uint16_t be16;
 
-#if 0
-not used yet
-/* __builtin_bswap isn't available in older gccs
- * so open code it for now */
-static be32 cpu_to_be32(int32_t v)
+static be32 cpu_to_be32(uint32_t v)
 {
 #ifdef IS_LITTLE_ENDIAN
 	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
-	//return __builtin_bswap32(v);
+#else
 	return v;
 #endif
 }
+
+static be16 cpu_to_be16(uint16_t v)
+{
+#ifdef IS_LITTLE_ENDIAN
+	return ((v & 0xff) << 8) | ((v & 0xff00) >> 8);
+#else
+	return v;
 #endif
+}
 
 static uint32_t be32_to_cpu(be32 v)
 {
 #ifdef IS_LITTLE_ENDIAN
 	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
 	//return __builtin_bswap32(v);
 #else
 	return v;
@@ -130,16 +134,26 @@ static uInt8Number read_uInt8Number(stru
 	return read_u8(mem, offset);
 }
 
 static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset)
 {
 	return read_u16(mem, offset);
 }
 
+static void write_u32(void *mem, size_t offset, uint32_t value)
+{
+    *((uint32_t *)((unsigned char*)mem + offset)) = cpu_to_be32(value);
+}
+
+static void write_u16(void *mem, size_t offset, uint16_t value)
+{
+    *((uint16_t *)((unsigned char*)mem + offset)) = cpu_to_be16(value);
+}
+
 #define BAD_VALUE_PROFILE NULL
 #define INVALID_PROFILE NULL
 #define NO_MEM_PROFILE NULL
 
 /* An arbitrary 4MB limit on profile size */
 #define MAX_PROFILE_SIZE 1024*1024*4
 #define MAX_TAG_COUNT 1024
 
@@ -843,21 +857,20 @@ static struct curveType *curve_from_gamm
 {
 	struct curveType *curve;
 	int num_entries = 1;
 	curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries);
 	if (!curve)
 		return NULL;
 	curve->count = num_entries;
 	curve->data[0] = float_to_u8Fixed8Number(gamma);
-  curve->type = CURVE_TYPE;
+  	curve->type = CURVE_TYPE;
 	return curve;
 }
 
-
 //XXX: it would be nice if we had a way of ensuring
 // everything in a profile was initialized regardless of how it was created
 
 //XXX: should this also be taking a black_point?
 /* similar to CGColorSpaceCreateCalibratedRGB */
 qcms_profile* qcms_profile_create_rgb_with_gamma(
 		qcms_CIE_xyY white_point,
 		qcms_CIE_xyYTRIPLE primaries,
@@ -1147,46 +1160,63 @@ void qcms_profile_release(qcms_profile *
 	free(profile->blueTRC);
 	free(profile->greenTRC);
 	free(profile->grayTRC);
 	free(profile);
 }
 
 
 #include <stdio.h>
-qcms_profile* qcms_profile_from_file(FILE *file)
+static void qcms_data_from_file(FILE *file, void **mem, size_t *size)
 {
 	uint32_t length, remaining_length;
-	qcms_profile *profile;
 	size_t read_length;
 	be32 length_be;
 	void *data;
 
+	*mem = NULL;
+	*size = 0;
+
 	if (fread(&length_be, 1, sizeof(length_be), file) != sizeof(length_be))
-		return BAD_VALUE_PROFILE;
+		return;
 
 	length = be32_to_cpu(length_be);
 	if (length > MAX_PROFILE_SIZE || length < sizeof(length_be))
-		return BAD_VALUE_PROFILE;
+		return;
 
 	/* allocate room for the entire profile */
 	data = malloc(length);
 	if (!data)
-		return NO_MEM_PROFILE;
+		return;
 
 	/* copy in length to the front so that the buffer will contain the entire profile */
 	*((be32*)data) = length_be;
 	remaining_length = length - sizeof(length_be);
 
 	/* read the rest profile */
 	read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file);
 	if (read_length != remaining_length) {
 		free(data);
+		return;
+	}
+
+	/* successfully get the profile.*/
+	*mem = data;
+	*size = length;
+}
+
+qcms_profile* qcms_profile_from_file(FILE *file)
+{
+	uint32_t length;
+	qcms_profile *profile;
+	void *data;
+
+	qcms_data_from_file(file, &data, &length);
+	if ((data == NULL) || (length == 0))
 		return INVALID_PROFILE;
-	}
 
 	profile = qcms_profile_from_memory(data, length);
 	free(data);
 	return profile;
 }
 
 qcms_profile* qcms_profile_from_path(const char *path)
 {
@@ -1194,21 +1224,155 @@ qcms_profile* qcms_profile_from_path(con
 	FILE *file = fopen(path, "rb");
 	if (file) {
 		profile = qcms_profile_from_file(file);
 		fclose(file);
 	}
 	return profile;
 }
 
+void qcms_data_from_path(const char *path, void **mem, size_t *size)
+{
+	*mem = NULL;
+	*size  = 0;
+
+	FILE *file = fopen(path, "rb");
+	if (file) {
+		qcms_data_from_file(file, mem, size);
+		fclose(file);
+	}
+}
+
 #ifdef _WIN32
 /* Unicode path version */
 qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path)
 {
 	qcms_profile *profile = NULL;
 	FILE *file = _wfopen(path, L"rb");
 	if (file) {
 		profile = qcms_profile_from_file(file);
 		fclose(file);
 	}
 	return profile;
 }
+
+void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size)
+{
+	*mem = NULL;
+	*size  = 0;
+	FILE *file = _wfopen(path, L"rb");
+	if (file) {
+		qcms_data_from_file(file, mem, size);
+		fclose(file);
+	}
+}
 #endif
+
+/*
+* This function constructs an ICC profile memory with given header and tag data,
+* which can be read via qcms_profile_from_memory(). that means, we must satisfy
+* the profiler header type check (which seems not complete till now) and proper
+* information to read data from the tag table and tag data elements memory.
+* 
+* To construct a valid ICC profile, its divided into three steps :
+*	(1) construct the r/g/bXYZ part
+*	(2) construct the r/g/bTRC part
+*	(3) construct the profile header
+* this is a hardcode step just for "create_rgb_with_gamma", it is the only
+* requirement till now, maybe we can make this method more general in future,
+*
+* NOTE : some of the parameters below are hardcode, please refer to the ICC documentation.
+*/
+#define ICC_PROFILE_HEADER_LENGTH 128
+void qcms_data_create_rgb_with_gamma(qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries, float gamma, void **mem, size_t *size)
+{
+	uint32_t length, offset, index, xyz_count, trc_count;
+	size_t tag_table_offset, tag_data_offset;
+	void *data;
+	struct matrix colorants;
+
+	uint32_t TAG_XYZ[3] = {TAG_rXYZ, TAG_gXYZ, TAG_bXYZ};
+	uint32_t TAG_TRC[3] = {TAG_rTRC, TAG_gTRC, TAG_bTRC};
+
+	if ((mem == NULL) || (size == NULL))
+		return;
+
+	*mem = NULL;
+	*size = 0;
+
+	/* 
+	* total length = icc profile header(128) + tag count(4) + 
+	* (tag table item (12) * total tag (6 = 3 rTRC + 3 rXYZ)) + rTRC elements data (3 * 20)
+	* + rXYZ elements data (3*16), and all tag data elements must start at the 4-byte boundary.
+	*/
+	xyz_count = 3; // rXYZ, gXYZ, bXYZ
+	trc_count = 3; // rTRC, gTRC, bTRC
+	length =  ICC_PROFILE_HEADER_LENGTH + 4 + (12 * (xyz_count + trc_count)) + (xyz_count * 20) + (trc_count * 16);
+	
+	// reserve the total memory.
+	data = malloc(length);
+	if (!data)
+		return;
+	memset(data, 0, length);
+
+	// Part1 : write rXYZ, gXYZ and bXYZ
+	if (!get_rgb_colorants(&colorants, white_point, primaries)) {
+		free(data);
+		return;
+	}
+
+	 // the position of first tag's signature in tag table
+	tag_table_offset = ICC_PROFILE_HEADER_LENGTH + 4;
+	tag_data_offset = ICC_PROFILE_HEADER_LENGTH + 4 +
+	   (12 * (xyz_count + trc_count)); // the start of tag data elements.
+
+	for (index = 0; index < xyz_count; ++index) {
+		// tag table
+		write_u32(data, tag_table_offset, TAG_XYZ[index]);
+		write_u32(data, tag_table_offset+4, tag_data_offset);
+		write_u32(data, tag_table_offset+8, 20); // 20 bytes per TAG_(r/g/b)XYZ tag element
+
+		// tag data element
+		write_u32(data, tag_data_offset, XYZ_TYPE);
+		// reserved 4 bytes.
+		write_u32(data, tag_data_offset+8, double_to_s15Fixed16Number(colorants.m[0][index]));
+		write_u32(data, tag_data_offset+12, double_to_s15Fixed16Number(colorants.m[1][index]));
+		write_u32(data, tag_data_offset+16, double_to_s15Fixed16Number(colorants.m[2][index]));
+
+		tag_table_offset += 12;
+		tag_data_offset += 20;
+	}
+
+	// Part2 : write rTRC, gTRC and bTRC
+	for (index = 0; index < trc_count; ++index) {
+		// tag table
+		write_u32(data, tag_table_offset, TAG_TRC[index]);
+		write_u32(data, tag_table_offset+4, tag_data_offset);
+		write_u32(data, tag_table_offset+8, 14); // 14 bytes per TAG_(r/g/b)TRC element
+
+		// tag data element
+		write_u32(data, tag_data_offset, CURVE_TYPE);
+		// reserved 4 bytes.
+		write_u32(data, tag_data_offset+8, 1); // count
+		write_u16(data, tag_data_offset+12, float_to_u8Fixed8Number(gamma));
+
+		tag_table_offset += 12;
+		tag_data_offset += 16;
+	}
+
+	/* Part3 : write profile header
+	 *
+	 * Important header fields are left empty. This generates a profile for internal use only.
+	 * We should be generating: Profile version (04300000h), Profile signature (acsp), 
+	 * PCS illumiant field. Likewise mandatory profile tags are omitted.
+	 */
+	write_u32(data, 0, length); // the total length of this memory
+	write_u32(data, 12, DISPLAY_DEVICE_PROFILE); // profile->class
+	write_u32(data, 16, RGB_SIGNATURE); // profile->color_space
+	write_u32(data, 20, XYZ_SIGNATURE); // profile->pcs
+	write_u32(data, 64, QCMS_INTENT_PERCEPTUAL); // profile->rendering_intent
+
+	write_u32(data, ICC_PROFILE_HEADER_LENGTH, 6); // total tag count
+
+	// prepare the result
+	*mem = data;
+	*size = length;
+}
--- a/gfx/qcms/qcms.h
+++ b/gfx/qcms/qcms.h
@@ -125,26 +125,37 @@ typedef struct
 typedef struct
 {
 	qcms_CIE_xyY red;
 	qcms_CIE_xyY green;
 	qcms_CIE_xyY blue;
 } qcms_CIE_xyYTRIPLE;
 
 qcms_profile* qcms_profile_create_rgb_with_gamma(
-		qcms_CIE_xyY white_point,
-		qcms_CIE_xyYTRIPLE primaries,
-		float gamma);
+                qcms_CIE_xyY white_point,
+                qcms_CIE_xyYTRIPLE primaries,
+                float gamma);
+
+void qcms_data_create_rgb_with_gamma(
+                qcms_CIE_xyY white_point,
+                qcms_CIE_xyYTRIPLE primaries,
+                float gamma,
+                void **mem,
+                size_t *size);
 
 qcms_profile* qcms_profile_from_memory(const void *mem, size_t size);
 
 qcms_profile* qcms_profile_from_file(FILE *file);
 qcms_profile* qcms_profile_from_path(const char *path);
+
+void qcms_data_from_path(const char *path, void **mem, size_t *size);
+
 #ifdef _WIN32
 qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path);
+void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size);
 #endif
 qcms_profile* qcms_profile_sRGB(void);
 void qcms_profile_release(qcms_profile *profile);
 
 qcms_bool qcms_profile_is_bogus(qcms_profile *profile);
 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile);
 icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile);
 
--- a/gfx/qcms/qcmsint.h
+++ b/gfx/qcms/qcmsint.h
@@ -250,16 +250,17 @@ static inline float uInt8Number_to_float
 static inline float uInt16Number_to_float(uInt16Number a)
 {
 	return ((int32_t)a)/65535.f;
 }
 
 
 void precache_release(struct precache_output *p);
 qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries);
+qcms_bool get_rgb_colorants(struct matrix *colorants, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries);
 
 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
                                           unsigned char *src,
                                           unsigned char *dest,
                                           size_t length);
 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
                                           unsigned char *src,
                                           unsigned char *dest,
--- a/gfx/qcms/transform.c
+++ b/gfx/qcms/transform.c
@@ -301,16 +301,24 @@ qcms_bool set_rgb_colorants(qcms_profile
 
 	profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]);
 	profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]);
 	profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]);
 
 	return true;
 }
 
+qcms_bool get_rgb_colorants(struct matrix *colorants, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries)
+{
+	*colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
+	*colorants = adapt_matrix_to_D50(*colorants, white_point);
+
+	return (colorants->invalid ? true : false);
+}
+
 #if 0
 static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
 {
 	int i;
 	float (*mat)[4] = transform->matrix;
 	for (i=0; i<length; i++) {
 		unsigned char device_r = *src++;
 		unsigned char device_g = *src++;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1702,20 +1702,33 @@ gfxPlatform::TransformPixel(const gfxRGB
         new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
 #endif
     }
 
     else if (&out != &in)
         out = in;
 }
 
-qcms_profile *
-gfxPlatform::GetPlatformCMSOutputProfile()
+void
+gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
 {
-    return nullptr;
+    mem = nullptr;
+    size = 0;
+}
+
+void
+gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
+{
+    nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
+    if (!fname.IsEmpty()) {
+        qcms_data_from_path(fname, &mem, &size);
+    }
+    else {
+        gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
+    }
 }
 
 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.
@@ -1724,27 +1737,26 @@ gfxPlatform::CreateCMSOutputProfile()
            default value of this preference, which means nsIPrefBranch::GetBoolPref
            will typically throw (and leave its out-param untouched).
          */
         if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
             gCMSOutputProfile = GetCMSsRGBProfile();
         }
 
         if (!gCMSOutputProfile) {
-            nsAdoptingCString fname = Preferences::GetCString(GFX_PREF_CMS_DISPLAY_PROFILE);
-            if (!fname.IsEmpty()) {
-                gCMSOutputProfile = qcms_profile_from_path(fname);
+            void* mem = nullptr;
+            size_t size = 0;
+
+            GetCMSOutputProfileData(mem, size);
+            if ((mem != nullptr) && (size > 0)) {
+                gCMSOutputProfile = qcms_profile_from_memory(mem, size);
+                free(mem);
             }
         }
 
-        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;
         }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -707,19 +707,21 @@ protected:
 private:
     /**
      * Start up Thebes.
      */
     static void Init();
 
     static void CreateCMSOutputProfile();
 
+    static void GetCMSOutputProfileData(void *&mem, size_t &size);
+
     friend void RecordingPrefChanged(const char *aPrefName, void *aClosure);
 
-    virtual qcms_profile* GetPlatformCMSOutputProfile();
+    virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
 
     virtual bool SupportsOffMainThreadCompositing() { return true; }
 
     nsRefPtr<gfxASurface> mScreenReferenceSurface;
     mozilla::RefPtr<mozilla::gfx::DrawTarget> mScreenReferenceDrawTarget;
     nsTArray<uint32_t> mCJKPrefLangs;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -273,61 +273,67 @@ gfxPlatformGtk::SupportsOffMainThreadCom
 #if defined(MOZ_X11) && !defined(NIGHTLY_BUILD)
   return (PR_GetEnv("MOZ_USE_OMTC") != nullptr) ||
          (PR_GetEnv("MOZ_OMTC_ENABLED") != nullptr);
 #else
   return true;
 #endif
 }
 
-qcms_profile *
-gfxPlatformGtk::GetPlatformCMSOutputProfile()
+void
+gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
 {
+    mem = nullptr;
+    size = 0;
+
 #ifdef MOZ_X11
     const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
     const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
 
     Atom edidAtom, iccAtom;
     Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     // In xpcshell tests, we never initialize X and hence don't have a Display.
     // In this case, there's no output colour management to be done, so we just
-    // return nullptr.
-    if (!dpy) {
-        return nullptr;
-    }
-
+    // return with nullptr.
+    if (!dpy)
+        return;
+ 
     Window root = gdk_x11_get_default_root_xwindow();
 
     Atom retAtom;
     int retFormat;
     unsigned long retLength, retAfter;
     unsigned char *retProperty ;
 
     iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
     if (iccAtom) {
         // read once to get size, once for the data
         if (Success == XGetWindowProperty(dpy, root, iccAtom,
                                           0, INT_MAX /* length */,
                                           False, AnyPropertyType,
                                           &retAtom, &retFormat, &retLength,
                                           &retAfter, &retProperty)) {
-            qcms_profile* profile = nullptr;
 
-            if (retLength > 0)
-                profile = qcms_profile_from_memory(retProperty, retLength);
+            if (retLength > 0) {
+                void *buffer = malloc(retLength);
+                if (buffer) {
+                    memcpy(buffer, retProperty, retLength);
+                    mem = buffer;
+                    size = retLength;
+                }
+            }
 
             XFree(retProperty);
-
-            if (profile) {
+            if (size > 0) {
 #ifdef DEBUG_tor
                 fprintf(stderr,
                         "ICM profile read from %s successfully\n",
                         ICC_PROFILE_ATOM_NAME);
 #endif
-                return profile;
+                return;
             }
         }
     }
 
     edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
     if (edidAtom) {
         if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
                                           False, AnyPropertyType,
@@ -336,17 +342,17 @@ gfxPlatformGtk::GetPlatformCMSOutputProf
             double gamma;
             qcms_CIE_xyY whitePoint;
             qcms_CIE_xyYTRIPLE primaries;
 
             if (retLength != 128) {
 #ifdef DEBUG_tor
                 fprintf(stderr, "Short EDID data\n");
 #endif
-                return nullptr;
+                return;
             }
 
             // Format documented in "VESA E-EDID Implementation Guide"
 
             gamma = (100 + retProperty[0x17]) / 100.0;
             whitePoint.x = ((retProperty[0x21] << 2) |
                             (retProperty[0x1a] >> 2 & 3)) / 1024.0;
             whitePoint.y = ((retProperty[0x22] << 2) |
@@ -378,33 +384,28 @@ gfxPlatformGtk::GetPlatformCMSOutputProf
             fprintf(stderr, "EDID whitepoint: %f %f %f\n",
                     whitePoint.x, whitePoint.y, whitePoint.Y);
             fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
                     primaries.Red.x, primaries.Red.y, primaries.Red.Y,
                     primaries.Green.x, primaries.Green.y, primaries.Green.Y,
                     primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
 #endif
 
-            qcms_profile* profile =
-                qcms_profile_create_rgb_with_gamma(whitePoint, primaries, gamma);
+            qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
 
 #ifdef DEBUG_tor
-            if (profile) {
+            if (size > 0) {
                 fprintf(stderr,
                         "ICM profile read from %s successfully\n",
                         EDID1_ATOM_NAME);
             }
 #endif
-
-            return profile;
         }
     }
 #endif
-
-    return nullptr;
 }
 
 
 #if (MOZ_WIDGET_GTK == 2)
 void
 gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target,
                                GdkDrawable *drawable)
 {
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -94,17 +94,17 @@ public:
     virtual gfxImageFormat GetOffscreenFormat();
 
     virtual int GetScreenDepth() const;
 
 protected:
     static gfxFontconfigUtils *sFontconfigUtils;
 
 private:
-    virtual qcms_profile *GetPlatformCMSOutputProfile();
+    virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
 
     virtual bool SupportsOffMainThreadCompositing();
 #ifdef MOZ_X11
     static bool sUseXRender;
 #endif
 };
 
 #endif /* GFX_PLATFORM_GTK_H */
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -420,33 +420,44 @@ gfxPlatformMac::UseAcceleratedCanvas()
 }
 
 bool
 gfxPlatformMac::SupportsOffMainThreadCompositing()
 {
   return true;
 }
 
-qcms_profile *
-gfxPlatformMac::GetPlatformCMSOutputProfile()
+void
+gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
 {
+    mem = nullptr;
+    size = 0;
+
     CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
     if (!cspace) {
         cspace = ::CGColorSpaceCreateDeviceRGB();
     }
     if (!cspace) {
-        return nullptr;
+        return;
     }
 
     CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace);
 
     ::CFRelease(cspace);
 
     if (!iccp) {
-        return nullptr;
+        return;
     }
 
-    qcms_profile* profile = qcms_profile_from_memory(::CFDataGetBytePtr(iccp), static_cast<size_t>(::CFDataGetLength(iccp)));
+    // copy to external buffer
+    size = static_cast<size_t>(::CFDataGetLength(iccp));
+    if (size > 0) {
+        void *data = malloc(size);
+        if (data) {
+            memcpy(data, ::CFDataGetBytePtr(iccp), size);
+            mem = data;
+        } else {
+            size = 0;
+        }
+    }
 
     ::CFRelease(iccp);
-
-    return profile;
 }
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -77,17 +77,17 @@ public:
     uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
     virtual already_AddRefed<gfxASurface>
     GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 
     virtual already_AddRefed<gfxASurface>
     CreateThebesSurfaceAliasForDrawTarget_hack(mozilla::gfx::DrawTarget *aTarget);
 private:
-    virtual qcms_profile* GetPlatformCMSOutputProfile();
+    virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     virtual bool SupportsOffMainThreadCompositing();
 
     // read in the pref value for the lower threshold on font anti-aliasing
     static uint32_t ReadAntiAliasingThreshold();
 
     uint32_t mFontAntiAliasingThreshold;
 };
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1046,49 +1046,52 @@ gfxWindowsPlatform::FindFontEntry(const 
     nsRefPtr<gfxFontFamily> ff = FindFontFamily(aName);
     if (!ff)
         return nullptr;
 
     bool aNeedsBold;
     return ff->FindFontForStyle(aFontStyle, aNeedsBold);
 }
 
-qcms_profile*
-gfxWindowsPlatform::GetPlatformCMSOutputProfile()
+void
+gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
 {
     WCHAR str[MAX_PATH];
     DWORD size = MAX_PATH;
     BOOL res;
 
+    mem = nullptr;
+    size = 0;
+
     HDC dc = GetDC(nullptr);
     if (!dc)
-        return nullptr;
+        return;
 
 #if _MSC_VER
     __try {
         res = GetICMProfileW(dc, &size, (LPWSTR)&str);
     } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) {
         res = FALSE;
     }
 #else
     res = GetICMProfileW(dc, &size, (LPWSTR)&str);
 #endif
 
     ReleaseDC(nullptr, dc);
     if (!res)
-        return nullptr;
+        return;
 
-    qcms_profile* profile = qcms_profile_from_unicode_path(str);
+    qcms_data_from_unicode_path(str, &mem, &size);
+
 #ifdef DEBUG_tor
-    if (profile)
+    if (size > 0)
         fprintf(stderr,
                 "ICM profile read from %s successfully\n",
                 NS_ConvertUTF16toUTF8(str).get());
 #endif
-    return profile;
 }
 
 bool
 gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
 {
     return mPrefFonts.Get(aKey, array);
 }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -289,15 +289,15 @@ private:
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     bool mD3D11DeviceInitialized;
 
-    virtual qcms_profile* GetPlatformCMSOutputProfile();
+    virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
 #endif /* GFX_WINDOWS_PLATFORM_H */