gfx/qcms/chain.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* vim: set ts=8 sw=8 noexpandtab: */
     2 //  qcms
     3 //  Copyright (C) 2009 Mozilla Corporation
     4 //  Copyright (C) 1998-2007 Marti Maria
     5 //
     6 // Permission is hereby granted, free of charge, to any person obtaining 
     7 // a copy of this software and associated documentation files (the "Software"), 
     8 // to deal in the Software without restriction, including without limitation 
     9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 
    10 // and/or sell copies of the Software, and to permit persons to whom the Software 
    11 // is furnished to do so, subject to the following conditions:
    12 //
    13 // The above copyright notice and this permission notice shall be included in 
    14 // all copies or substantial portions of the Software.
    15 //
    16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
    18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    24 #include <stdlib.h>
    25 #include <math.h>
    26 #include <assert.h>
    27 #include <string.h> //memcpy
    28 #include "qcmsint.h"
    29 #include "transform_util.h"
    30 #include "matrix.h"
    32 static struct matrix build_lut_matrix(struct lutType *lut)
    33 {
    34 	struct matrix result;
    35 	if (lut) {
    36 		result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
    37 		result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
    38 		result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
    39 		result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
    40 		result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
    41 		result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
    42 		result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
    43 		result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
    44 		result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
    45 		result.invalid = false;
    46 	} else {
    47 		memset(&result, 0, sizeof(struct matrix));
    48 		result.invalid = true;
    49 	}
    50 	return result;
    51 }
    53 static struct matrix build_mAB_matrix(struct lutmABType *lut)
    54 {
    55 	struct matrix result;
    56 	if (lut) {
    57 		result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
    58 		result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
    59 		result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
    60 		result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
    61 		result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
    62 		result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
    63 		result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
    64 		result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
    65 		result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
    66 		result.invalid = false;
    67 	} else {
    68 		memset(&result, 0, sizeof(struct matrix));
    69 		result.invalid = true;
    70 	}
    71 	return result;
    72 }
    74 //Based on lcms cmsLab2XYZ
    75 #define f(t) (t <= (24.0f/116.0f)*(24.0f/116.0f)*(24.0f/116.0f)) ? ((841.0/108.0) * t + (16.0/116.0)) : pow(t,1.0/3.0)
    76 #define f_1(t) (t <= (24.0f/116.0f)) ? ((108.0/841.0) * (t - (16.0/116.0))) : (t * t * t)
    77 static void qcms_transform_module_LAB_to_XYZ(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
    78 {
    79 	size_t i;
    80 	// lcms: D50 XYZ values
    81 	float WhitePointX = 0.9642f;
    82 	float WhitePointY = 1.0f;
    83 	float WhitePointZ = 0.8249f;
    84 	for (i = 0; i < length; i++) {
    85 		float device_L = *src++ * 100.0f;
    86 		float device_a = *src++ * 255.0f - 128.0f;
    87 		float device_b = *src++ * 255.0f - 128.0f;
    88 		float y = (device_L + 16.0f) / 116.0f;
    90 		float X = f_1((y + 0.002f * device_a)) * WhitePointX;
    91 		float Y = f_1(y) * WhitePointY;
    92 		float Z = f_1((y - 0.005f * device_b)) * WhitePointZ;
    93 		*dest++ = X / (1.0 + 32767.0/32768.0);
    94 		*dest++ = Y / (1.0 + 32767.0/32768.0);
    95 		*dest++ = Z / (1.0 + 32767.0/32768.0);
    96 	}
    97 }
    99 //Based on lcms cmsXYZ2Lab
   100 static void qcms_transform_module_XYZ_to_LAB(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   101 {
   102 	size_t i;
   103         // lcms: D50 XYZ values
   104         float WhitePointX = 0.9642f;
   105         float WhitePointY = 1.0f;
   106         float WhitePointZ = 0.8249f;
   107         for (i = 0; i < length; i++) {
   108                 float device_x = *src++ * (1.0 + 32767.0/32768.0) / WhitePointX;
   109                 float device_y = *src++ * (1.0 + 32767.0/32768.0) / WhitePointY;
   110                 float device_z = *src++ * (1.0 + 32767.0/32768.0) / WhitePointZ;
   112 		float fx = f(device_x);
   113 		float fy = f(device_y);
   114 		float fz = f(device_z);
   116                 float L = 116.0f*fy - 16.0f;
   117                 float a = 500.0f*(fx - fy);
   118                 float b = 200.0f*(fy - fz);
   119                 *dest++ = L / 100.0f;
   120                 *dest++ = (a+128.0f) / 255.0f;
   121                 *dest++ = (b+128.0f) / 255.0f;
   122         }
   124 }
   126 static void qcms_transform_module_clut_only(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   127 {
   128 	size_t i;
   129 	int xy_len = 1;
   130 	int x_len = transform->grid_size;
   131 	int len = x_len * x_len;
   132 	float* r_table = transform->r_clut;
   133 	float* g_table = transform->g_clut;
   134 	float* b_table = transform->b_clut;
   136 	for (i = 0; i < length; i++) {
   137 		float linear_r = *src++;
   138 		float linear_g = *src++;
   139 		float linear_b = *src++;
   141 		int x = floorf(linear_r * (transform->grid_size-1));
   142 		int y = floorf(linear_g * (transform->grid_size-1));
   143 		int z = floorf(linear_b * (transform->grid_size-1));
   144 		int x_n = ceilf(linear_r * (transform->grid_size-1));
   145 		int y_n = ceilf(linear_g * (transform->grid_size-1));
   146 		int z_n = ceilf(linear_b * (transform->grid_size-1));
   147 		float x_d = linear_r * (transform->grid_size-1) - x;
   148 		float y_d = linear_g * (transform->grid_size-1) - y;
   149 		float z_d = linear_b * (transform->grid_size-1) - z;
   151 		float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d);
   152 		float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
   153 		float r_y1 = lerp(r_x1, r_x2, y_d);
   154 		float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
   155 		float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d);
   156 		float r_y2 = lerp(r_x3, r_x4, y_d);
   157 		float clut_r = lerp(r_y1, r_y2, z_d);
   159 		float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d);
   160 		float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
   161 		float g_y1 = lerp(g_x1, g_x2, y_d);
   162 		float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
   163 		float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d);
   164 		float g_y2 = lerp(g_x3, g_x4, y_d);
   165 		float clut_g = lerp(g_y1, g_y2, z_d);
   167 		float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d);
   168 		float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
   169 		float b_y1 = lerp(b_x1, b_x2, y_d);
   170 		float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
   171 		float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d);
   172 		float b_y2 = lerp(b_x3, b_x4, y_d);
   173 		float clut_b = lerp(b_y1, b_y2, z_d);
   175 		*dest++ = clamp_float(clut_r);
   176 		*dest++ = clamp_float(clut_g);
   177 		*dest++ = clamp_float(clut_b);
   178 	}
   179 }
   181 static void qcms_transform_module_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   182 {
   183 	size_t i;
   184 	int xy_len = 1;
   185 	int x_len = transform->grid_size;
   186 	int len = x_len * x_len;
   187 	float* r_table = transform->r_clut;
   188 	float* g_table = transform->g_clut;
   189 	float* b_table = transform->b_clut;
   190 	for (i = 0; i < length; i++) {
   191 		float device_r = *src++;
   192 		float device_g = *src++;
   193 		float device_b = *src++;
   194 		float linear_r = lut_interp_linear_float(device_r,
   195 				transform->input_clut_table_r, transform->input_clut_table_length);
   196 		float linear_g = lut_interp_linear_float(device_g,
   197 				transform->input_clut_table_g, transform->input_clut_table_length);
   198 		float linear_b = lut_interp_linear_float(device_b,
   199 				transform->input_clut_table_b, transform->input_clut_table_length);
   201 		int x = floorf(linear_r * (transform->grid_size-1));
   202 		int y = floorf(linear_g * (transform->grid_size-1));
   203 		int z = floorf(linear_b * (transform->grid_size-1));
   204 		int x_n = ceilf(linear_r * (transform->grid_size-1));
   205 		int y_n = ceilf(linear_g * (transform->grid_size-1));
   206 		int z_n = ceilf(linear_b * (transform->grid_size-1));
   207 		float x_d = linear_r * (transform->grid_size-1) - x;
   208 		float y_d = linear_g * (transform->grid_size-1) - y;
   209 		float z_d = linear_b * (transform->grid_size-1) - z;
   211 		float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d);
   212 		float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
   213 		float r_y1 = lerp(r_x1, r_x2, y_d);
   214 		float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
   215 		float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d);
   216 		float r_y2 = lerp(r_x3, r_x4, y_d);
   217 		float clut_r = lerp(r_y1, r_y2, z_d);
   219 		float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d);
   220 		float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
   221 		float g_y1 = lerp(g_x1, g_x2, y_d);
   222 		float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
   223 		float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d);
   224 		float g_y2 = lerp(g_x3, g_x4, y_d);
   225 		float clut_g = lerp(g_y1, g_y2, z_d);
   227 		float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d);
   228 		float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
   229 		float b_y1 = lerp(b_x1, b_x2, y_d);
   230 		float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
   231 		float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d);
   232 		float b_y2 = lerp(b_x3, b_x4, y_d);
   233 		float clut_b = lerp(b_y1, b_y2, z_d);
   235 		float pcs_r = lut_interp_linear_float(clut_r,
   236 				transform->output_clut_table_r, transform->output_clut_table_length);
   237 		float pcs_g = lut_interp_linear_float(clut_g,
   238 				transform->output_clut_table_g, transform->output_clut_table_length);
   239 		float pcs_b = lut_interp_linear_float(clut_b,
   240 				transform->output_clut_table_b, transform->output_clut_table_length);
   242 		*dest++ = clamp_float(pcs_r);
   243 		*dest++ = clamp_float(pcs_g);
   244 		*dest++ = clamp_float(pcs_b);
   245 	}
   246 }
   248 /* NOT USED
   249 static void qcms_transform_module_tetra_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   250 {
   251 	size_t i;
   252 	int xy_len = 1;
   253 	int x_len = transform->grid_size;
   254 	int len = x_len * x_len;
   255 	float* r_table = transform->r_clut;
   256 	float* g_table = transform->g_clut;
   257 	float* b_table = transform->b_clut;
   258 	float c0_r, c1_r, c2_r, c3_r;
   259 	float c0_g, c1_g, c2_g, c3_g;
   260 	float c0_b, c1_b, c2_b, c3_b;
   261 	float clut_r, clut_g, clut_b;
   262 	float pcs_r, pcs_g, pcs_b;
   263 	for (i = 0; i < length; i++) {
   264 		float device_r = *src++;
   265 		float device_g = *src++;
   266 		float device_b = *src++;
   267 		float linear_r = lut_interp_linear_float(device_r,
   268 				transform->input_clut_table_r, transform->input_clut_table_length);
   269 		float linear_g = lut_interp_linear_float(device_g,
   270 				transform->input_clut_table_g, transform->input_clut_table_length);
   271 		float linear_b = lut_interp_linear_float(device_b,
   272 				transform->input_clut_table_b, transform->input_clut_table_length);
   274 		int x = floorf(linear_r * (transform->grid_size-1));
   275 		int y = floorf(linear_g * (transform->grid_size-1));
   276 		int z = floorf(linear_b * (transform->grid_size-1));
   277 		int x_n = ceilf(linear_r * (transform->grid_size-1));
   278 		int y_n = ceilf(linear_g * (transform->grid_size-1));
   279 		int z_n = ceilf(linear_b * (transform->grid_size-1));
   280 		float rx = linear_r * (transform->grid_size-1) - x;
   281 		float ry = linear_g * (transform->grid_size-1) - y;
   282 		float rz = linear_b * (transform->grid_size-1) - z;
   284 		c0_r = CLU(r_table, x, y, z);
   285 		c0_g = CLU(g_table, x, y, z);
   286 		c0_b = CLU(b_table, x, y, z);
   287 		if( rx >= ry ) {
   288 			if (ry >= rz) { //rx >= ry && ry >= rz
   289 				c1_r = CLU(r_table, x_n, y, z) - c0_r;
   290 				c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
   291 				c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
   292 				c1_g = CLU(g_table, x_n, y, z) - c0_g;
   293 				c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
   294 				c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
   295 				c1_b = CLU(b_table, x_n, y, z) - c0_b;
   296 				c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
   297 				c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
   298 			} else {
   299 				if (rx >= rz) { //rx >= rz && rz >= ry
   300 					c1_r = CLU(r_table, x_n, y, z) - c0_r;
   301 					c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
   302 					c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z);
   303 					c1_g = CLU(g_table, x_n, y, z) - c0_g;
   304 					c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
   305 					c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z);
   306 					c1_b = CLU(b_table, x_n, y, z) - c0_b;
   307 					c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
   308 					c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z);
   309 				} else { //rz > rx && rx >= ry
   310 					c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n);
   311 					c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
   312 					c3_r = CLU(r_table, x, y, z_n) - c0_r;
   313 					c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n);
   314 					c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
   315 					c3_g = CLU(g_table, x, y, z_n) - c0_g;
   316 					c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n);
   317 					c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
   318 					c3_b = CLU(b_table, x, y, z_n) - c0_b;
   319 				}
   320 			}
   321 		} else {
   322 			if (rx >= rz) { //ry > rx && rx >= rz
   323 				c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
   324 				c2_r = CLU(r_table, x_n, y_n, z) - c0_r;
   325 				c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
   326 				c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
   327 				c2_g = CLU(g_table, x_n, y_n, z) - c0_g;
   328 				c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
   329 				c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
   330 				c2_b = CLU(b_table, x_n, y_n, z) - c0_b;
   331 				c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
   332 			} else {
   333 				if (ry >= rz) { //ry >= rz && rz > rx 
   334 					c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
   335 					c2_r = CLU(r_table, x, y_n, z) - c0_r;
   336 					c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z);
   337 					c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
   338 					c2_g = CLU(g_table, x, y_n, z) - c0_g;
   339 					c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z);
   340 					c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
   341 					c2_b = CLU(b_table, x, y_n, z) - c0_b;
   342 					c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z);
   343 				} else { //rz > ry && ry > rx
   344 					c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
   345 					c2_r = CLU(r_table, x, y_n, z) - c0_r;
   346 					c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
   347 					c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
   348 					c2_g = CLU(g_table, x, y_n, z) - c0_g;
   349 					c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
   350 					c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
   351 					c2_b = CLU(b_table, x, y_n, z) - c0_b;
   352 					c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
   353 				}
   354 			}
   355 		}
   357 		clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
   358 		clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
   359 		clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
   361 		pcs_r = lut_interp_linear_float(clut_r,
   362 				transform->output_clut_table_r, transform->output_clut_table_length);
   363 		pcs_g = lut_interp_linear_float(clut_g,
   364 				transform->output_clut_table_g, transform->output_clut_table_length);
   365 		pcs_b = lut_interp_linear_float(clut_b,
   366 				transform->output_clut_table_b, transform->output_clut_table_length);
   367 		*dest++ = clamp_float(pcs_r);
   368 		*dest++ = clamp_float(pcs_g);
   369 		*dest++ = clamp_float(pcs_b);
   370 	}
   371 }
   372 */
   374 static void qcms_transform_module_gamma_table(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   375 {
   376 	size_t i;
   377 	float out_r, out_g, out_b;
   378 	for (i = 0; i < length; i++) {
   379 		float in_r = *src++;
   380 		float in_g = *src++;
   381 		float in_b = *src++;
   383 		out_r = lut_interp_linear_float(in_r, transform->input_clut_table_r, 256);
   384 		out_g = lut_interp_linear_float(in_g, transform->input_clut_table_g, 256);
   385 		out_b = lut_interp_linear_float(in_b, transform->input_clut_table_b, 256);
   387 		*dest++ = clamp_float(out_r);
   388 		*dest++ = clamp_float(out_g);
   389 		*dest++ = clamp_float(out_b);
   390 	}
   391 }
   393 static void qcms_transform_module_gamma_lut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   394 {
   395 	size_t i;
   396 	float out_r, out_g, out_b;
   397 	for (i = 0; i < length; i++) {
   398 		float in_r = *src++;
   399 		float in_g = *src++;
   400 		float in_b = *src++;
   402 		out_r = lut_interp_linear(in_r,
   403 				transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
   404 		out_g = lut_interp_linear(in_g,
   405 				transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
   406 		out_b = lut_interp_linear(in_b,
   407 				transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
   409 		*dest++ = clamp_float(out_r);
   410 		*dest++ = clamp_float(out_g);
   411 		*dest++ = clamp_float(out_b);
   412 	}
   413 }
   415 static void qcms_transform_module_matrix_translate(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   416 {
   417 	size_t i;
   418 	struct matrix mat;
   420 	/* store the results in column major mode
   421 	 * this makes doing the multiplication with sse easier */
   422 	mat.m[0][0] = transform->matrix.m[0][0];
   423 	mat.m[1][0] = transform->matrix.m[0][1];
   424 	mat.m[2][0] = transform->matrix.m[0][2];
   425 	mat.m[0][1] = transform->matrix.m[1][0];
   426 	mat.m[1][1] = transform->matrix.m[1][1];
   427 	mat.m[2][1] = transform->matrix.m[1][2];
   428 	mat.m[0][2] = transform->matrix.m[2][0];
   429 	mat.m[1][2] = transform->matrix.m[2][1];
   430 	mat.m[2][2] = transform->matrix.m[2][2];
   432 	for (i = 0; i < length; i++) {
   433 		float in_r = *src++;
   434 		float in_g = *src++;
   435 		float in_b = *src++;
   437 		float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b + transform->tx;
   438 		float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b + transform->ty;
   439 		float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b + transform->tz;
   441 		*dest++ = clamp_float(out_r);
   442 		*dest++ = clamp_float(out_g);
   443 		*dest++ = clamp_float(out_b);
   444 	}
   445 }
   447 static void qcms_transform_module_matrix(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
   448 {
   449 	size_t i;
   450 	struct matrix mat;
   452 	/* store the results in column major mode
   453 	 * this makes doing the multiplication with sse easier */
   454 	mat.m[0][0] = transform->matrix.m[0][0];
   455 	mat.m[1][0] = transform->matrix.m[0][1];
   456 	mat.m[2][0] = transform->matrix.m[0][2];
   457 	mat.m[0][1] = transform->matrix.m[1][0];
   458 	mat.m[1][1] = transform->matrix.m[1][1];
   459 	mat.m[2][1] = transform->matrix.m[1][2];
   460 	mat.m[0][2] = transform->matrix.m[2][0];
   461 	mat.m[1][2] = transform->matrix.m[2][1];
   462 	mat.m[2][2] = transform->matrix.m[2][2];
   464 	for (i = 0; i < length; i++) {
   465 		float in_r = *src++;
   466 		float in_g = *src++;
   467 		float in_b = *src++;
   469 		float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b;
   470 		float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b;
   471 		float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b;
   473 		*dest++ = clamp_float(out_r);
   474 		*dest++ = clamp_float(out_g);
   475 		*dest++ = clamp_float(out_b);
   476 	}
   477 }
   479 static struct qcms_modular_transform* qcms_modular_transform_alloc() {
   480 	return calloc(1, sizeof(struct qcms_modular_transform));
   481 }
   483 static void qcms_modular_transform_release(struct qcms_modular_transform *transform)
   484 {
   485 	struct qcms_modular_transform *next_transform;
   486 	while (transform != NULL) {
   487 		next_transform = transform->next_transform;
   488 		// clut may use a single block of memory.
   489 		// Perhaps we should remove this to simply the code.
   490 		if (transform->input_clut_table_r + transform->input_clut_table_length == transform->input_clut_table_g && transform->input_clut_table_g + transform->input_clut_table_length == transform->input_clut_table_b) {
   491 			if (transform->input_clut_table_r) free(transform->input_clut_table_r);
   492 		} else {
   493 			if (transform->input_clut_table_r) free(transform->input_clut_table_r);
   494 			if (transform->input_clut_table_g) free(transform->input_clut_table_g);
   495 			if (transform->input_clut_table_b) free(transform->input_clut_table_b);
   496 		}
   497 		if (transform->r_clut + 1 == transform->g_clut && transform->g_clut + 1 == transform->b_clut) {
   498 			if (transform->r_clut) free(transform->r_clut);
   499 		} else {
   500 			if (transform->r_clut) free(transform->r_clut);
   501 			if (transform->g_clut) free(transform->g_clut);
   502 			if (transform->b_clut) free(transform->b_clut);
   503 		}
   504 		if (transform->output_clut_table_r + transform->output_clut_table_length == transform->output_clut_table_g && transform->output_clut_table_g+ transform->output_clut_table_length == transform->output_clut_table_b) {
   505 			if (transform->output_clut_table_r) free(transform->output_clut_table_r);
   506 		} else {
   507 			if (transform->output_clut_table_r) free(transform->output_clut_table_r);
   508 			if (transform->output_clut_table_g) free(transform->output_clut_table_g);
   509 			if (transform->output_clut_table_b) free(transform->output_clut_table_b);
   510 		}
   511 		if (transform->output_gamma_lut_r) free(transform->output_gamma_lut_r);
   512 		if (transform->output_gamma_lut_g) free(transform->output_gamma_lut_g);
   513 		if (transform->output_gamma_lut_b) free(transform->output_gamma_lut_b);
   514 		free(transform);
   515 		transform = next_transform;
   516 	}
   517 }
   519 /* Set transform to be the next element in the linked list. */
   520 static void append_transform(struct qcms_modular_transform *transform, struct qcms_modular_transform ***next_transform)
   521 {
   522 	**next_transform = transform;
   523 	while (transform) {
   524 		*next_transform = &(transform->next_transform);
   525 		transform = transform->next_transform;
   526 	}
   527 }
   529 /* reverse the transformation list (used by mBA) */
   530 static struct qcms_modular_transform* reverse_transform(struct qcms_modular_transform *transform) 
   531 {
   532 	struct qcms_modular_transform *prev_transform = NULL;
   533 	while (transform != NULL) {
   534 		struct qcms_modular_transform *next_transform = transform->next_transform;
   535 		transform->next_transform = prev_transform;
   536 		prev_transform = transform;
   537 		transform = next_transform;
   538 	}
   540 	return prev_transform;
   541 }
   543 #define EMPTY_TRANSFORM_LIST NULL
   544 static struct qcms_modular_transform* qcms_modular_transform_create_mAB(struct lutmABType *lut)
   545 {
   546 	struct qcms_modular_transform *first_transform = NULL;
   547 	struct qcms_modular_transform **next_transform = &first_transform;
   548 	struct qcms_modular_transform *transform = NULL;
   550 	if (lut->a_curves[0] != NULL) {
   551 		size_t clut_length;
   552 		float *clut;
   554 		// If the A curve is present this also implies the 
   555 		// presence of a CLUT.
   556 		if (!lut->clut_table) 
   557 			goto fail;
   559 		// Prepare A curve.
   560 		transform = qcms_modular_transform_alloc();
   561 		if (!transform)
   562 			goto fail;
   563 		append_transform(transform, &next_transform);
   564 		transform->input_clut_table_r = build_input_gamma_table(lut->a_curves[0]);
   565 		transform->input_clut_table_g = build_input_gamma_table(lut->a_curves[1]);
   566 		transform->input_clut_table_b = build_input_gamma_table(lut->a_curves[2]);
   567 		transform->transform_module_fn = qcms_transform_module_gamma_table;
   568 		if (lut->num_grid_points[0] != lut->num_grid_points[1] ||
   569 			lut->num_grid_points[1] != lut->num_grid_points[2] ) {
   570 			//XXX: We don't currently support clut that are not squared!
   571 			goto fail;
   572 		}
   574 		// Prepare CLUT
   575 		transform = qcms_modular_transform_alloc();
   576 		if (!transform) 
   577 			goto fail;
   578 		append_transform(transform, &next_transform);
   579 		clut_length = sizeof(float)*pow(lut->num_grid_points[0], 3)*3;
   580 		clut = malloc(clut_length);
   581 		if (!clut)
   582 			goto fail;
   583 		memcpy(clut, lut->clut_table, clut_length);
   584 		transform->r_clut = clut + 0;
   585 		transform->g_clut = clut + 1;
   586 		transform->b_clut = clut + 2;
   587 		transform->grid_size = lut->num_grid_points[0];
   588 		transform->transform_module_fn = qcms_transform_module_clut_only;
   589 	}
   590 	if (lut->m_curves[0] != NULL) {
   591 		// M curve imples the presence of a Matrix
   593 		// Prepare M curve
   594 		transform = qcms_modular_transform_alloc();
   595 		if (!transform)
   596 			goto fail;
   597 		append_transform(transform, &next_transform);
   598 		transform->input_clut_table_r = build_input_gamma_table(lut->m_curves[0]);
   599 		transform->input_clut_table_g = build_input_gamma_table(lut->m_curves[1]);
   600 		transform->input_clut_table_b = build_input_gamma_table(lut->m_curves[2]);
   601 		transform->transform_module_fn = qcms_transform_module_gamma_table;
   603 		// Prepare Matrix
   604 		transform = qcms_modular_transform_alloc();
   605 		if (!transform) 
   606 			goto fail;
   607 		append_transform(transform, &next_transform);
   608 		transform->matrix = build_mAB_matrix(lut);
   609 		if (transform->matrix.invalid)
   610 			goto fail;
   611 		transform->tx = s15Fixed16Number_to_float(lut->e03);
   612 		transform->ty = s15Fixed16Number_to_float(lut->e13);
   613 		transform->tz = s15Fixed16Number_to_float(lut->e23);
   614 		transform->transform_module_fn = qcms_transform_module_matrix_translate;
   615 	}
   616 	if (lut->b_curves[0] != NULL) {
   617 		// Prepare B curve
   618 		transform = qcms_modular_transform_alloc();
   619 		if (!transform) 
   620 			goto fail;
   621 		append_transform(transform, &next_transform);
   622 		transform->input_clut_table_r = build_input_gamma_table(lut->b_curves[0]);
   623 		transform->input_clut_table_g = build_input_gamma_table(lut->b_curves[1]);
   624 		transform->input_clut_table_b = build_input_gamma_table(lut->b_curves[2]);
   625 		transform->transform_module_fn = qcms_transform_module_gamma_table;
   626 	} else {
   627 		// B curve is mandatory
   628 		goto fail;
   629 	}
   631 	if (lut->reversed) {
   632 		// mBA are identical to mAB except that the transformation order
   633 		// is reversed
   634 		first_transform = reverse_transform(first_transform);
   635 	}
   637 	return first_transform;
   638 fail:
   639 	qcms_modular_transform_release(first_transform);
   640 	return NULL;
   641 }
   643 static struct qcms_modular_transform* qcms_modular_transform_create_lut(struct lutType *lut)
   644 {
   645 	struct qcms_modular_transform *first_transform = NULL;
   646 	struct qcms_modular_transform **next_transform = &first_transform;
   647 	struct qcms_modular_transform *transform = NULL;
   649 	size_t in_curve_len, clut_length, out_curve_len;
   650 	float *in_curves, *clut, *out_curves;
   652 	// Prepare Matrix
   653 	transform = qcms_modular_transform_alloc();
   654 	if (!transform) 
   655 		goto fail;
   656 	append_transform(transform, &next_transform);
   657 	transform->matrix = build_lut_matrix(lut);
   658 	if (transform->matrix.invalid)
   659 		goto fail;
   660 	transform->transform_module_fn = qcms_transform_module_matrix;
   662 	// Prepare input curves
   663 	transform = qcms_modular_transform_alloc();
   664 	if (!transform) 
   665 		goto fail;
   666 	append_transform(transform, &next_transform);
   667 	in_curve_len = sizeof(float)*lut->num_input_table_entries * 3;
   668 	in_curves = malloc(in_curve_len);
   669 	if (!in_curves) 
   670 		goto fail;
   671 	memcpy(in_curves, lut->input_table, in_curve_len);
   672 	transform->input_clut_table_r = in_curves + lut->num_input_table_entries * 0;
   673 	transform->input_clut_table_g = in_curves + lut->num_input_table_entries * 1;
   674 	transform->input_clut_table_b = in_curves + lut->num_input_table_entries * 2;
   675 	transform->input_clut_table_length = lut->num_input_table_entries;
   677 	// Prepare table
   678 	clut_length = sizeof(float)*pow(lut->num_clut_grid_points, 3)*3;
   679 	clut = malloc(clut_length);
   680 	if (!clut) 
   681 		goto fail;
   682 	memcpy(clut, lut->clut_table, clut_length);
   683 	transform->r_clut = clut + 0;
   684 	transform->g_clut = clut + 1;
   685 	transform->b_clut = clut + 2;
   686 	transform->grid_size = lut->num_clut_grid_points;
   688 	// Prepare output curves
   689 	out_curve_len = sizeof(float) * lut->num_output_table_entries * 3;
   690 	out_curves = malloc(out_curve_len);
   691 	if (!out_curves) 
   692 		goto fail;
   693 	memcpy(out_curves, lut->output_table, out_curve_len);
   694 	transform->output_clut_table_r = out_curves + lut->num_output_table_entries * 0;
   695 	transform->output_clut_table_g = out_curves + lut->num_output_table_entries * 1;
   696 	transform->output_clut_table_b = out_curves + lut->num_output_table_entries * 2;
   697 	transform->output_clut_table_length = lut->num_output_table_entries;
   698 	transform->transform_module_fn = qcms_transform_module_clut;
   700 	return first_transform;
   701 fail:
   702 	qcms_modular_transform_release(first_transform);
   703 	return NULL;
   704 }
   706 struct qcms_modular_transform* qcms_modular_transform_create_input(qcms_profile *in)
   707 {
   708 	struct qcms_modular_transform *first_transform = NULL;
   709 	struct qcms_modular_transform **next_transform = &first_transform;
   711 	if (in->A2B0) {
   712 		struct qcms_modular_transform *lut_transform;
   713 		lut_transform = qcms_modular_transform_create_lut(in->A2B0);
   714 		if (!lut_transform)
   715 			goto fail;
   716 		append_transform(lut_transform, &next_transform);
   717 	} else if (in->mAB && in->mAB->num_in_channels == 3 && in->mAB->num_out_channels == 3) {
   718 		struct qcms_modular_transform *mAB_transform;
   719 		mAB_transform = qcms_modular_transform_create_mAB(in->mAB);
   720 		if (!mAB_transform)
   721 			goto fail;
   722 		append_transform(mAB_transform, &next_transform);
   724 	} else {
   725 		struct qcms_modular_transform *transform;
   727 		transform = qcms_modular_transform_alloc();
   728 		if (!transform)
   729 			goto fail;
   730 		append_transform(transform, &next_transform);
   731 		transform->input_clut_table_r = build_input_gamma_table(in->redTRC);
   732 		transform->input_clut_table_g = build_input_gamma_table(in->greenTRC);
   733 		transform->input_clut_table_b = build_input_gamma_table(in->blueTRC);
   734 		transform->transform_module_fn = qcms_transform_module_gamma_table;
   735 		if (!transform->input_clut_table_r || !transform->input_clut_table_g ||
   736 				!transform->input_clut_table_b) {
   737 			goto fail;
   738 		}
   740 		transform = qcms_modular_transform_alloc();
   741 		if (!transform) 
   742 			goto fail;
   743 		append_transform(transform, &next_transform);
   744 		transform->matrix.m[0][0] = 1/1.999969482421875f;
   745 		transform->matrix.m[0][1] = 0.f;
   746 		transform->matrix.m[0][2] = 0.f;
   747 		transform->matrix.m[1][0] = 0.f;
   748 		transform->matrix.m[1][1] = 1/1.999969482421875f;
   749 		transform->matrix.m[1][2] = 0.f;
   750 		transform->matrix.m[2][0] = 0.f;
   751 		transform->matrix.m[2][1] = 0.f;
   752 		transform->matrix.m[2][2] = 1/1.999969482421875f;
   753 		transform->matrix.invalid = false;
   754 		transform->transform_module_fn = qcms_transform_module_matrix;
   756 		transform = qcms_modular_transform_alloc();
   757 		if (!transform) 
   758 			goto fail;
   759 		append_transform(transform, &next_transform);
   760 		transform->matrix = build_colorant_matrix(in);
   761 		transform->transform_module_fn = qcms_transform_module_matrix;
   762 	}
   764 	return first_transform;
   765 fail:
   766 	qcms_modular_transform_release(first_transform);
   767 	return EMPTY_TRANSFORM_LIST;
   768 }
   769 static struct qcms_modular_transform* qcms_modular_transform_create_output(qcms_profile *out)
   770 {
   771 	struct qcms_modular_transform *first_transform = NULL;
   772 	struct qcms_modular_transform **next_transform = &first_transform;
   774 	if (out->B2A0) {
   775 		struct qcms_modular_transform *lut_transform;
   776 		lut_transform = qcms_modular_transform_create_lut(out->B2A0);
   777 		if (!lut_transform) 
   778 			goto fail;
   779 		append_transform(lut_transform, &next_transform);
   780 	} else if (out->mBA && out->mBA->num_in_channels == 3 && out->mBA->num_out_channels == 3) {
   781 		struct qcms_modular_transform *lut_transform;
   782 		lut_transform = qcms_modular_transform_create_mAB(out->mBA);
   783 		if (!lut_transform) 
   784 			goto fail;
   785 		append_transform(lut_transform, &next_transform);
   786 	} else if (out->redTRC && out->greenTRC && out->blueTRC) {
   787 		struct qcms_modular_transform *transform;
   789 		transform = qcms_modular_transform_alloc();
   790 		if (!transform) 
   791 			goto fail;
   792 		append_transform(transform, &next_transform);
   793 		transform->matrix = matrix_invert(build_colorant_matrix(out));
   794 		transform->transform_module_fn = qcms_transform_module_matrix;
   796 		transform = qcms_modular_transform_alloc();
   797 		if (!transform) 
   798 			goto fail;
   799 		append_transform(transform, &next_transform);
   800 		transform->matrix.m[0][0] = 1.999969482421875f;
   801 		transform->matrix.m[0][1] = 0.f;
   802 		transform->matrix.m[0][2] = 0.f;
   803 		transform->matrix.m[1][0] = 0.f;
   804 		transform->matrix.m[1][1] = 1.999969482421875f;
   805 		transform->matrix.m[1][2] = 0.f;
   806 		transform->matrix.m[2][0] = 0.f;
   807 		transform->matrix.m[2][1] = 0.f;
   808 		transform->matrix.m[2][2] = 1.999969482421875f;
   809 		transform->matrix.invalid = false;
   810 		transform->transform_module_fn = qcms_transform_module_matrix;
   812 		transform = qcms_modular_transform_alloc();
   813 		if (!transform) 
   814 			goto fail;
   815 		append_transform(transform, &next_transform);
   816 		build_output_lut(out->redTRC, &transform->output_gamma_lut_r,
   817 			&transform->output_gamma_lut_r_length);
   818 		build_output_lut(out->greenTRC, &transform->output_gamma_lut_g,
   819 			&transform->output_gamma_lut_g_length);
   820 		build_output_lut(out->blueTRC, &transform->output_gamma_lut_b,
   821 			&transform->output_gamma_lut_b_length);
   822 		transform->transform_module_fn = qcms_transform_module_gamma_lut;
   824 		if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g ||
   825 				!transform->output_gamma_lut_b) {
   826 			goto fail;
   827 		}
   828 	} else {
   829 		assert(0 && "Unsupported output profile workflow.");
   830 		return NULL;
   831 	}
   833 	return first_transform;
   834 fail:
   835 	qcms_modular_transform_release(first_transform);
   836 	return EMPTY_TRANSFORM_LIST;
   837 }
   839 /* Not Completed
   840 // Simplify the transformation chain to an equivalent transformation chain
   841 static struct qcms_modular_transform* qcms_modular_transform_reduce(struct qcms_modular_transform *transform)
   842 {
   843 	struct qcms_modular_transform *first_transform = NULL;
   844 	struct qcms_modular_transform *curr_trans = transform;
   845 	struct qcms_modular_transform *prev_trans = NULL;
   846 	while (curr_trans) {
   847 		struct qcms_modular_transform *next_trans = curr_trans->next_transform;
   848 		if (curr_trans->transform_module_fn == qcms_transform_module_matrix) {
   849 			if (next_trans && next_trans->transform_module_fn == qcms_transform_module_matrix) {
   850 				curr_trans->matrix = matrix_multiply(curr_trans->matrix, next_trans->matrix);
   851 				goto remove_next;	
   852 			}
   853 		}
   854 		if (curr_trans->transform_module_fn == qcms_transform_module_gamma_table) {
   855 			bool isLinear = true;
   856 			uint16_t i;
   857 			for (i = 0; isLinear && i < 256; i++) {
   858 				isLinear &= (int)(curr_trans->input_clut_table_r[i] * 255) == i;
   859 				isLinear &= (int)(curr_trans->input_clut_table_g[i] * 255) == i;
   860 				isLinear &= (int)(curr_trans->input_clut_table_b[i] * 255) == i;
   861 			}
   862 			goto remove_current;
   863 		}
   865 next_transform:
   866 		if (!next_trans) break;
   867 		prev_trans = curr_trans;
   868 		curr_trans = next_trans;
   869 		continue;
   870 remove_current:
   871 		if (curr_trans == transform) {
   872 			//Update head
   873 			transform = next_trans;
   874 		} else {
   875 			prev_trans->next_transform = next_trans;
   876 		}
   877 		curr_trans->next_transform = NULL;
   878 		qcms_modular_transform_release(curr_trans);
   879 		//return transform;
   880 		return qcms_modular_transform_reduce(transform);
   881 remove_next:
   882 		curr_trans->next_transform = next_trans->next_transform;
   883 		next_trans->next_transform = NULL;
   884 		qcms_modular_transform_release(next_trans);
   885 		continue;
   886 	}
   887 	return transform;
   888 }
   889 */
   891 static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile *in, qcms_profile *out)
   892 {
   893 	struct qcms_modular_transform *first_transform = NULL;
   894 	struct qcms_modular_transform **next_transform = &first_transform;
   896 	if (in->color_space == RGB_SIGNATURE) {
   897 		struct qcms_modular_transform* rgb_to_pcs;
   898 		rgb_to_pcs = qcms_modular_transform_create_input(in);
   899 		if (!rgb_to_pcs) 
   900 			goto fail;
   901 		append_transform(rgb_to_pcs, &next_transform);
   902 	} else {
   903 		assert(0 && "input color space not supported");
   904 		goto fail;
   905 	}
   907 	if (in->pcs == LAB_SIGNATURE && out->pcs == XYZ_SIGNATURE) {
   908 		struct qcms_modular_transform* lab_to_pcs;
   909 		lab_to_pcs = qcms_modular_transform_alloc();
   910 		if (!lab_to_pcs) 
   911 			goto fail;
   912 		append_transform(lab_to_pcs, &next_transform);
   913 		lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_XYZ;
   914 	}
   916 	// This does not improve accuracy in practice, something is wrong here.
   917 	//if (in->chromaticAdaption.invalid == false) {
   918 	//	struct qcms_modular_transform* chromaticAdaption;
   919 	//	chromaticAdaption = qcms_modular_transform_alloc();
   920 	//	if (!chromaticAdaption) 
   921 	//		goto fail;
   922 	//	append_transform(chromaticAdaption, &next_transform);
   923 	//	chromaticAdaption->matrix = matrix_invert(in->chromaticAdaption);
   924 	//	chromaticAdaption->transform_module_fn = qcms_transform_module_matrix;
   925 	//}
   927         if (in->pcs == XYZ_SIGNATURE && out->pcs == LAB_SIGNATURE) {
   928 		struct qcms_modular_transform* pcs_to_lab;
   929 		pcs_to_lab = qcms_modular_transform_alloc();
   930 		if (!pcs_to_lab) 
   931 			goto fail;
   932 		append_transform(pcs_to_lab, &next_transform);
   933 		pcs_to_lab->transform_module_fn = qcms_transform_module_XYZ_to_LAB;
   934 	}
   936 	if (out->color_space == RGB_SIGNATURE) {
   937 		struct qcms_modular_transform* pcs_to_rgb;
   938 		pcs_to_rgb = qcms_modular_transform_create_output(out);
   939 		if (!pcs_to_rgb) 
   940 			goto fail;
   941 		append_transform(pcs_to_rgb, &next_transform);
   942 	} else {
   943 		assert(0 && "output color space not supported");
   944 		goto fail;
   945 	}
   946 	// Not Completed
   947 	//return qcms_modular_transform_reduce(first_transform);
   948 	return first_transform;
   949 fail:
   950 	qcms_modular_transform_release(first_transform);
   951 	return EMPTY_TRANSFORM_LIST;
   952 }
   954 static float* qcms_modular_transform_data(struct qcms_modular_transform *transform, float *src, float *dest, size_t len)
   955 {
   956         while (transform != NULL) {
   957                 // Keep swaping src/dest when performing a transform to use less memory.
   958                 float *new_src = dest;
   959 		const transform_module_fn_t transform_fn = transform->transform_module_fn;
   960 		if (transform_fn != qcms_transform_module_gamma_table &&
   961 		    transform_fn != qcms_transform_module_gamma_lut &&
   962 		    transform_fn != qcms_transform_module_clut &&
   963 		    transform_fn != qcms_transform_module_clut_only &&
   964 		    transform_fn != qcms_transform_module_matrix &&
   965 		    transform_fn != qcms_transform_module_matrix_translate &&
   966 		    transform_fn != qcms_transform_module_LAB_to_XYZ &&
   967 		    transform_fn != qcms_transform_module_XYZ_to_LAB) {
   968 			assert(0 && "Unsupported transform module");
   969 			return NULL;
   970 		}
   971                 transform->transform_module_fn(transform,src,dest,len);
   972                 dest = src;
   973                 src = new_src;
   974                 transform = transform->next_transform;
   975         }
   976         // The results end up in the src buffer because of the switching
   977         return src;
   978 }
   980 float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, float *dest, size_t lutSize)
   981 {
   982 	struct qcms_modular_transform *transform_list = qcms_modular_transform_create(in, out);
   983 	if (transform_list != NULL) {
   984 		float *lut = qcms_modular_transform_data(transform_list, src, dest, lutSize/3);
   985 		qcms_modular_transform_release(transform_list);
   986 		return lut;
   987 	}
   988 	return NULL;
   989 }

mercurial