| Index: third_party/qcms/src/transform.c
 | 
| diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
 | 
| index 9a6562bf2712db51bfdef01a6b3f751c31e54d39..8d49e5ce6dd96fbdd3ad01d591ad38e61c0edffa 100644
 | 
| --- a/third_party/qcms/src/transform.c
 | 
| +++ b/third_party/qcms/src/transform.c
 | 
| @@ -411,6 +411,41 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform,
 | 
|  	}
 | 
|  }
 | 
|  
 | 
| +static void qcms_transform_data_bgra_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
 | 
| +{
 | 
| +	unsigned int i;
 | 
| +	float (*mat)[4] = transform->matrix;
 | 
| +	for (i = 0; i < length; i++) {
 | 
| +		unsigned char device_b = *src++;
 | 
| +		unsigned char device_g = *src++;
 | 
| +		unsigned char device_r = *src++;
 | 
| +		unsigned char alpha = *src++;
 | 
| +		uint16_t r, g, b;
 | 
| +
 | 
| +		float linear_r = transform->input_gamma_table_r[device_r];
 | 
| +		float linear_g = transform->input_gamma_table_g[device_g];
 | 
| +		float linear_b = transform->input_gamma_table_b[device_b];
 | 
| +
 | 
| +		float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
 | 
| +		float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
 | 
| +		float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
 | 
| +
 | 
| +		out_linear_r = clamp_float(out_linear_r);
 | 
| +		out_linear_g = clamp_float(out_linear_g);
 | 
| +		out_linear_b = clamp_float(out_linear_b);
 | 
| +
 | 
| +		/* we could round here... */
 | 
| +		r = out_linear_r * PRECACHE_OUTPUT_MAX;
 | 
| +		g = out_linear_g * PRECACHE_OUTPUT_MAX;
 | 
| +		b = out_linear_b * PRECACHE_OUTPUT_MAX;
 | 
| +
 | 
| +		*dest++ = transform->output_table_b->data[b];
 | 
| +		*dest++ = transform->output_table_g->data[g];
 | 
| +		*dest++ = transform->output_table_r->data[r];
 | 
| +		*dest++ = alpha;
 | 
| +	}
 | 
| +}
 | 
| +
 | 
|  // Not used
 | 
|  /* 
 | 
|  static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
 | 
| @@ -584,6 +619,121 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsig
 | 
|  	}	
 | 
|  }
 | 
|  
 | 
| +// Using lcms' tetra interpolation algorithm.
 | 
| +static void qcms_transform_data_tetra_clut_bgra(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
 | 
| +	unsigned int i;
 | 
| +	int xy_len = 1;
 | 
| +	int x_len = transform->grid_size;
 | 
| +	int len = x_len * x_len;
 | 
| +	float* r_table = transform->r_clut;
 | 
| +	float* g_table = transform->g_clut;
 | 
| +	float* b_table = transform->b_clut;
 | 
| +	float c0_r, c1_r, c2_r, c3_r;
 | 
| +	float c0_g, c1_g, c2_g, c3_g;
 | 
| +	float c0_b, c1_b, c2_b, c3_b;
 | 
| +	float clut_r, clut_g, clut_b;
 | 
| +	for (i = 0; i < length; i++) {
 | 
| +		unsigned char in_b = *src++;
 | 
| +		unsigned char in_g = *src++;
 | 
| +		unsigned char in_r = *src++;
 | 
| +		unsigned char in_a = *src++;
 | 
| +		float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f;
 | 
| +
 | 
| +		int x = floor(linear_r * (transform->grid_size-1));
 | 
| +		int y = floor(linear_g * (transform->grid_size-1));
 | 
| +		int z = floor(linear_b * (transform->grid_size-1));
 | 
| +		int x_n = ceil(linear_r * (transform->grid_size-1));
 | 
| +		int y_n = ceil(linear_g * (transform->grid_size-1));
 | 
| +		int z_n = ceil(linear_b * (transform->grid_size-1));
 | 
| +		float rx = linear_r * (transform->grid_size-1) - x; 
 | 
| +		float ry = linear_g * (transform->grid_size-1) - y;
 | 
| +		float rz = linear_b * (transform->grid_size-1) - z; 
 | 
| +
 | 
| +		c0_r = CLU(r_table, x, y, z);
 | 
| +		c0_g = CLU(g_table, x, y, z);
 | 
| +		c0_b = CLU(b_table, x, y, z);
 | 
| +
 | 
| +		if( rx >= ry ) {
 | 
| +			if (ry >= rz) { //rx >= ry && ry >= rz
 | 
| +				c1_r = CLU(r_table, x_n, y, z) - c0_r;
 | 
| +				c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
 | 
| +				c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
 | 
| +				c1_g = CLU(g_table, x_n, y, z) - c0_g;
 | 
| +				c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
 | 
| +				c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
 | 
| +				c1_b = CLU(b_table, x_n, y, z) - c0_b;
 | 
| +				c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
 | 
| +				c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
 | 
| +			} else { 
 | 
| +				if (rx >= rz) { //rx >= rz && rz >= ry
 | 
| +					c1_r = CLU(r_table, x_n, y, z) - c0_r;
 | 
| +					c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
 | 
| +					c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z);
 | 
| +					c1_g = CLU(g_table, x_n, y, z) - c0_g;
 | 
| +					c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
 | 
| +					c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z);
 | 
| +					c1_b = CLU(b_table, x_n, y, z) - c0_b;
 | 
| +					c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
 | 
| +					c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z);
 | 
| +				} else { //rz > rx && rx >= ry
 | 
| +					c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n);
 | 
| +					c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
 | 
| +					c3_r = CLU(r_table, x, y, z_n) - c0_r;
 | 
| +					c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n);
 | 
| +					c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
 | 
| +					c3_g = CLU(g_table, x, y, z_n) - c0_g;
 | 
| +					c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n);
 | 
| +					c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
 | 
| +					c3_b = CLU(b_table, x, y, z_n) - c0_b;
 | 
| +				}
 | 
| +			}
 | 
| +		} else {
 | 
| +			if (rx >= rz) { //ry > rx && rx >= rz
 | 
| +				c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
 | 
| +				c2_r = CLU(r_table, x, y_n, z) - c0_r;
 | 
| +				c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
 | 
| +				c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
 | 
| +				c2_g = CLU(g_table, x, y_n, z) - c0_g;
 | 
| +				c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
 | 
| +				c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
 | 
| +				c2_b = CLU(b_table, x, y_n, z) - c0_b;
 | 
| +				c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
 | 
| +			} else {
 | 
| +				if (ry >= rz) { //ry >= rz && rz > rx 
 | 
| +					c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
 | 
| +					c2_r = CLU(r_table, x, y_n, z) - c0_r;
 | 
| +					c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z);
 | 
| +					c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
 | 
| +					c2_g = CLU(g_table, x, y_n, z) - c0_g;
 | 
| +					c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z);
 | 
| +					c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
 | 
| +					c2_b = CLU(b_table, x, y_n, z) - c0_b;
 | 
| +					c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z);
 | 
| +				} else { //rz > ry && ry > rx
 | 
| +					c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
 | 
| +					c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n);
 | 
| +					c3_r = CLU(r_table, x, y, z_n) - c0_r;
 | 
| +					c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
 | 
| +					c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n);
 | 
| +					c3_g = CLU(g_table, x, y, z_n) - c0_g;
 | 
| +					c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
 | 
| +					c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n);
 | 
| +					c3_b = CLU(b_table, x, y, z_n) - c0_b;
 | 
| +				}
 | 
| +			}
 | 
| +		}
 | 
| +				
 | 
| +		clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
 | 
| +		clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
 | 
| +		clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
 | 
| +
 | 
| +		*dest++ = clamp_u8(clut_b*255.0f);
 | 
| +		*dest++ = clamp_u8(clut_g*255.0f);
 | 
| +		*dest++ = clamp_u8(clut_r*255.0f);
 | 
| +		*dest++ = in_a;
 | 
| +	}	
 | 
| +}
 | 
| +
 | 
|  // Using lcms' tetra interpolation code.
 | 
|  static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
 | 
|  	unsigned int i;
 | 
| @@ -769,6 +919,43 @@ static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned
 | 
|  	}
 | 
|  }
 | 
|  
 | 
| +static void qcms_transform_data_bgra_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
 | 
| +{
 | 
| +	unsigned int i;
 | 
| +	float (*mat)[4] = transform->matrix;
 | 
| +	for (i = 0; i < length; i++) {
 | 
| +		unsigned char device_b = *src++;
 | 
| +		unsigned char device_g = *src++;
 | 
| +		unsigned char device_r = *src++;
 | 
| +		unsigned char alpha = *src++;
 | 
| +		float out_device_r, out_device_g, out_device_b;
 | 
| +
 | 
| +		float linear_r = transform->input_gamma_table_r[device_r];
 | 
| +		float linear_g = transform->input_gamma_table_g[device_g];
 | 
| +		float linear_b = transform->input_gamma_table_b[device_b];
 | 
| +
 | 
| +		float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
 | 
| +		float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
 | 
| +		float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
 | 
| +
 | 
| +		out_linear_r = clamp_float(out_linear_r);
 | 
| +		out_linear_g = clamp_float(out_linear_g);
 | 
| +		out_linear_b = clamp_float(out_linear_b);
 | 
| +
 | 
| +		out_device_r = lut_interp_linear(out_linear_r, 
 | 
| +				transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
 | 
| +		out_device_g = lut_interp_linear(out_linear_g, 
 | 
| +				transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
 | 
| +		out_device_b = lut_interp_linear(out_linear_b, 
 | 
| +				transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
 | 
| +
 | 
| +		*dest++ = clamp_u8(out_device_b*255);
 | 
| +		*dest++ = clamp_u8(out_device_g*255);
 | 
| +		*dest++ = clamp_u8(out_device_r*255);
 | 
| +		*dest++ = alpha;
 | 
| +	}
 | 
| +}
 | 
| +
 | 
|  #if 0
 | 
|  static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
 | 
|  {
 | 
| @@ -1068,6 +1255,8 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
 | 
|  			transform->grid_size = samples;
 | 
|  			if (in_type == QCMS_DATA_RGBA_8) {
 | 
|  				transform->transform_fn = qcms_transform_data_tetra_clut_rgba;
 | 
| +                        } else if (in_type == QCMS_DATA_BGRA_8) {
 | 
| +				transform->transform_fn = qcms_transform_data_tetra_clut_bgra;
 | 
|  			} else {
 | 
|  				transform->transform_fn = qcms_transform_data_tetra_clut;
 | 
|  			}
 | 
| @@ -1102,7 +1291,8 @@ qcms_transform* qcms_transform_create(
 | 
|  		return NULL;
 | 
|  	}
 | 
|  	if (out_type != QCMS_DATA_RGB_8 &&
 | 
| -                out_type != QCMS_DATA_RGBA_8) {
 | 
| +                out_type != QCMS_DATA_RGBA_8 &&
 | 
| +                out_type != QCMS_DATA_BGRA_8) {
 | 
|              assert(0 && "output type");
 | 
|  	    transform_free(transform);
 | 
|              return NULL;
 | 
| @@ -1151,7 +1341,8 @@ qcms_transform* qcms_transform_create(
 | 
|  		struct matrix in_matrix, out_matrix, result;
 | 
|  
 | 
|  		if (in_type != QCMS_DATA_RGB_8 &&
 | 
| -                    in_type != QCMS_DATA_RGBA_8){
 | 
| +                    in_type != QCMS_DATA_RGBA_8 &&
 | 
| +                    in_type != QCMS_DATA_BGRA_8){
 | 
|                  	assert(0 && "input type");
 | 
|  			transform_free(transform);
 | 
|                  	return NULL;
 | 
| @@ -1161,6 +1352,8 @@ qcms_transform* qcms_transform_create(
 | 
|  		    if (sse_version_available() >= 2) {
 | 
|  			    if (in_type == QCMS_DATA_RGB_8)
 | 
|  				    transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
 | 
| +                            else if (in_type == QCMS_DATA_BGRA_8)
 | 
| +				    transform->transform_fn = qcms_transform_data_bgra_out_lut_sse2;
 | 
|  			    else
 | 
|  				    transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
 | 
|  
 | 
| @@ -1171,6 +1364,8 @@ qcms_transform* qcms_transform_create(
 | 
|  		    if (sse_version_available() >= 1) {
 | 
|  			    if (in_type == QCMS_DATA_RGB_8)
 | 
|  				    transform->transform_fn = qcms_transform_data_rgb_out_lut_sse1;
 | 
| +                            else if (in_type == QCMS_DATA_BGRA_8)
 | 
| +                                    transform->transform_fn = qcms_transform_data_bgra_out_lut_sse1;
 | 
|  			    else
 | 
|  				    transform->transform_fn = qcms_transform_data_rgba_out_lut_sse1;
 | 
|  #endif
 | 
| @@ -1179,12 +1374,16 @@ qcms_transform* qcms_transform_create(
 | 
|  			{
 | 
|  				if (in_type == QCMS_DATA_RGB_8)
 | 
|  					transform->transform_fn = qcms_transform_data_rgb_out_lut_precache;
 | 
| +                                else if (in_type == QCMS_DATA_BGRA_8)
 | 
| +                                        transform->transform_fn = qcms_transform_data_bgra_out_lut_precache;
 | 
|  				else
 | 
|  					transform->transform_fn = qcms_transform_data_rgba_out_lut_precache;
 | 
|  			}
 | 
|  		} else {
 | 
|  			if (in_type == QCMS_DATA_RGB_8)
 | 
|  				transform->transform_fn = qcms_transform_data_rgb_out_lut;
 | 
| +                        else if (in_type == QCMS_DATA_BGRA_8)
 | 
| +                                transform->transform_fn = qcms_transform_data_bgra_out_lut;
 | 
|  			else
 | 
|  				transform->transform_fn = qcms_transform_data_rgba_out_lut;
 | 
|  		}
 | 
| 
 |