Bug 907196 - Split CreateCMSOutputProfile profile loading into GetCMSOutputProfileData. r=BenWa, r=jmuizelaar

This commit is contained in:
guozhu cheng 2013-11-07 18:20:08 +08:00
parent 6d1bd67923
commit bd2c6ee1e0
13 changed files with 289 additions and 68 deletions

View File

@ -34,19 +34,23 @@
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)
{
@ -135,6 +139,16 @@ 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
@ -848,11 +862,10 @@ static struct curveType *curve_from_gamma(float gamma)
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
@ -1152,25 +1165,27 @@ void qcms_profile_release(qcms_profile *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;
@ -1180,9 +1195,24 @@ qcms_profile* qcms_profile_from_file(FILE *file)
read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file);
if (read_length != remaining_length) {
free(data);
return INVALID_PROFILE;
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;
@ -1199,6 +1229,19 @@ qcms_profile* qcms_profile_from_path(const char *path)
return profile;
}
void qcms_data_from_path(const char *path, void **mem, size_t *size)
{
FILE *file = NULL;
*mem = NULL;
*size = 0;
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)
@ -1211,4 +1254,128 @@ qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path)
}
return profile;
}
void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size)
{
FILE *file = NULL;
*mem = NULL;
*size = 0;
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;
}

View File

@ -130,16 +130,27 @@ typedef struct
} 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);

View File

@ -255,6 +255,7 @@ static inline float uInt16Number_to_float(uInt16Number a)
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,

View File

@ -306,6 +306,14 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
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)
{

View File

@ -1707,10 +1707,23 @@ gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *tra
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
@ -1729,15 +1742,14 @@ gfxPlatform::CreateCMSOutputProfile()
}
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;
if (!gCMSOutputProfile) {
gCMSOutputProfile =
gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
GetCMSOutputProfileData(mem, size);
if ((mem != nullptr) && (size > 0)) {
gCMSOutputProfile = qcms_profile_from_memory(mem, size);
free(mem);
}
}
/* Determine if the profile looks bogus. If so, close the profile

View File

@ -712,9 +712,11 @@ private:
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; }

View File

@ -278,9 +278,12 @@ gfxPlatformGtk::SupportsOffMainThreadCompositing()
#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";
@ -289,11 +292,10 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
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;
@ -309,20 +311,24 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
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;
}
}
}
@ -341,7 +347,7 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
#ifdef DEBUG_tor
fprintf(stderr, "Short EDID data\n");
#endif
return nullptr;
return;
}
// Format documented in "VESA E-EDID Implementation Guide"
@ -383,23 +389,18 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
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;
}

View File

@ -99,7 +99,7 @@ protected:
static gfxFontconfigUtils *sFontconfigUtils;
private:
virtual qcms_profile *GetPlatformCMSOutputProfile();
virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
virtual bool SupportsOffMainThreadCompositing();
#ifdef MOZ_X11

View File

@ -425,15 +425,18 @@ 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);
@ -441,12 +444,20 @@ gfxPlatformMac::GetPlatformCMSOutputProfile()
::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;
}

View File

@ -82,7 +82,7 @@ public:
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();

View File

@ -64,6 +64,7 @@
#include <winternl.h>
#include "d3dkmtQueryStatistics.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
@ -1051,16 +1052,19 @@ gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aF
return ff->FindFontForStyle(aFontStyle, aNeedsBold);
}
qcms_profile*
gfxWindowsPlatform::GetPlatformCMSOutputProfile()
void
gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size)
{
WCHAR str[MAX_PATH];
DWORD size = MAX_PATH;
BOOL res;
mem = nullptr;
mem_size = 0;
HDC dc = GetDC(nullptr);
if (!dc)
return nullptr;
return;
#if _MSC_VER
__try {
@ -1074,16 +1078,18 @@ gfxWindowsPlatform::GetPlatformCMSOutputProfile()
ReleaseDC(nullptr, dc);
if (!res)
return nullptr;
return;
#ifdef _WIN32
qcms_data_from_unicode_path(str, &mem, &mem_size);
qcms_profile* profile = qcms_profile_from_unicode_path(str);
#ifdef DEBUG_tor
if (profile)
if (mem_size > 0)
fprintf(stderr,
"ICM profile read from %s successfully\n",
NS_ConvertUTF16toUTF8(str).get());
#endif
return profile;
#endif // DEBUG_tor
#endif // _WIN32
}
bool

View File

@ -294,7 +294,7 @@ private:
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;

View File

@ -257,6 +257,8 @@ jpeg_abort_decompress
jpeg_read_raw_data
#endif
qcms_enable_iccv4
qcms_data_from_unicode_path
qcms_data_from_path
qcms_profile_create_rgb_with_gamma
qcms_profile_from_memory
qcms_profile_from_path