blob: 57434703c9d3a992bfc1278412f545dae8a16beb [file] [log] [blame] [edit]
diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c
index 5ea1b4c85..8a1171820 100644
--- a/third_party/lcms/src/cmsopt.c
+++ b/third_party/lcms/src/cmsopt.c
@@ -104,6 +104,39 @@ typedef struct {
// Simple optimizations ----------------------------------------------------------------------------------------------------------
+// Clamp a fixed point integer to signed 28 bits to avoid overflow in
+// calculations. Clamp is intended for use with colorants, requiring one bit
+// for a colorant and another two bits to avoid overflow when combining the
+// colors.
+cmsINLINE cmsS1Fixed14Number _FixedClamp(cmsS1Fixed14Number n) {
+ const cmsS1Fixed14Number max_positive = 268435455; // 0x0FFFFFFF;
+ const cmsS1Fixed14Number max_negative = -268435456; // 0xF0000000;
+ // Normally expect the provided number to be in the range [0..1] (but in
+ // fixed 1.14 format), so can perform a quick check for this typical case
+ // to reduce number of compares.
+ const cmsS1Fixed14Number typical_range_mask = 0xFFFF8000;
+
+ if (!(n & typical_range_mask))
+ return n;
+ if (n < max_negative)
+ return max_negative;
+ if (n > max_positive)
+ return max_positive;
+ return n;
+}
+
+// Perform one row of matrix multiply with translation for MatShaperEval16().
+cmsINLINE cmsInt64Number _MatShaperEvaluateRow(cmsS1Fixed14Number* mat,
+ cmsS1Fixed14Number off,
+ cmsS1Fixed14Number r,
+ cmsS1Fixed14Number g,
+ cmsS1Fixed14Number b) {
+ return ((cmsInt64Number)mat[0] * r +
+ (cmsInt64Number)mat[1] * g +
+ (cmsInt64Number)mat[2] * b +
+ off + 0x2000) >> 14;
+}
+
// Remove an element in linked chain
static
void _RemoveElement(cmsStage** head)
@@ -1527,7 +1560,8 @@ void MatShaperEval16(register const cmsUInt16Number In[],
register const void* D)
{
MatShaper8Data* p = (MatShaper8Data*) D;
- cmsS1Fixed14Number l1, l2, l3, r, g, b;
+ cmsS1Fixed14Number r, g, b;
+ cmsInt64Number l1, l2, l3;
cmsUInt32Number ri, gi, bi;
// In this case (and only in this case!) we can use this simplification since
@@ -1537,14 +1571,14 @@ void MatShaperEval16(register const cmsUInt16Number In[],
bi = In[2] & 0xFFU;
// Across first shaper, which also converts to 1.14 fixed point
- r = p->Shaper1R[ri];
- g = p->Shaper1G[gi];
- b = p->Shaper1B[bi];
+ r = _FixedClamp(p->Shaper1R[ri]);
+ g = _FixedClamp(p->Shaper1G[gi]);
+ b = _FixedClamp(p->Shaper1B[bi]);
// Evaluate the matrix in 1.14 fixed point
- l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14;
- l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14;
- l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14;
+ l1 = _MatShaperEvaluateRow(p->Mat[0], p->Off[0], r, g, b);
+ l2 = _MatShaperEvaluateRow(p->Mat[1], p->Off[1], r, g, b);
+ l3 = _MatShaperEvaluateRow(p->Mat[2], p->Off[2], r, g, b);
// Now we have to clip to 0..1.0 range
ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384U : (cmsUInt32Number) l1);