Add a NULL check in pdf_page_colors.cpp
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_colors.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fpdfapi/fpdf_page.h"
8 #include "../../../include/fpdfapi/fpdf_module.h"
9 #include "../../../include/fxcodec/fx_codec.h"
10 #include "pageint.h"
11 #include <limits.h>
12
13 namespace {
14
15 void sRGB_to_AdobeCMYK(FX_FLOAT R,
16                        FX_FLOAT G,
17                        FX_FLOAT B,
18                        FX_FLOAT& c,
19                        FX_FLOAT& m,
20                        FX_FLOAT& y,
21                        FX_FLOAT& k) {
22   c = 1.0f - R;
23   m = 1.0f - G;
24   y = 1.0f - B;
25   k = c;
26   if (m < k) {
27     k = m;
28   }
29   if (y < k) {
30     k = y;
31   }
32 }
33
34 int ComponentsForFamily(int family) {
35   if (family == PDFCS_DEVICERGB)
36     return 3;
37   if (family == PDFCS_DEVICEGRAY)
38     return 1;
39   return 4;
40 }
41
42 }  // namespace
43
44 CPDF_DeviceCS::CPDF_DeviceCS(CPDF_Document* pDoc, int family)
45     : CPDF_ColorSpace(pDoc, family, ComponentsForFamily(family)) {}
46
47 FX_BOOL CPDF_DeviceCS::GetRGB(FX_FLOAT* pBuf,
48                               FX_FLOAT& R,
49                               FX_FLOAT& G,
50                               FX_FLOAT& B) const {
51   if (m_Family == PDFCS_DEVICERGB) {
52     R = pBuf[0];
53     if (R < 0) {
54       R = 0;
55     } else if (R > 1) {
56       R = 1;
57     }
58     G = pBuf[1];
59     if (G < 0) {
60       G = 0;
61     } else if (G > 1) {
62       G = 1;
63     }
64     B = pBuf[2];
65     if (B < 0) {
66       B = 0;
67     } else if (B > 1) {
68       B = 1;
69     }
70   } else if (m_Family == PDFCS_DEVICEGRAY) {
71     R = *pBuf;
72     if (R < 0) {
73       R = 0;
74     } else if (R > 1) {
75       R = 1;
76     }
77     G = B = R;
78   } else if (m_Family == PDFCS_DEVICECMYK) {
79     if (!m_dwStdConversion) {
80       AdobeCMYK_to_sRGB(pBuf[0], pBuf[1], pBuf[2], pBuf[3], R, G, B);
81     } else {
82       FX_FLOAT k = pBuf[3];
83       R = 1.0f - FX_MIN(1.0f, pBuf[0] + k);
84       G = 1.0f - FX_MIN(1.0f, pBuf[1] + k);
85       B = 1.0f - FX_MIN(1.0f, pBuf[2] + k);
86     }
87   } else {
88     ASSERT(m_Family == PDFCS_PATTERN);
89     R = G = B = 0;
90     return FALSE;
91   }
92   return TRUE;
93 }
94 FX_BOOL CPDF_DeviceCS::v_GetCMYK(FX_FLOAT* pBuf,
95                                  FX_FLOAT& c,
96                                  FX_FLOAT& m,
97                                  FX_FLOAT& y,
98                                  FX_FLOAT& k) const {
99   if (m_Family != PDFCS_DEVICECMYK) {
100     return FALSE;
101   }
102   c = pBuf[0];
103   m = pBuf[1];
104   y = pBuf[2];
105   k = pBuf[3];
106   return TRUE;
107 }
108 FX_BOOL CPDF_DeviceCS::SetRGB(FX_FLOAT* pBuf,
109                               FX_FLOAT R,
110                               FX_FLOAT G,
111                               FX_FLOAT B) const {
112   if (m_Family == PDFCS_DEVICERGB) {
113     pBuf[0] = R;
114     pBuf[1] = G;
115     pBuf[2] = B;
116     return TRUE;
117   }
118   if (m_Family == PDFCS_DEVICEGRAY) {
119     if (R == G && R == B) {
120       *pBuf = R;
121       return TRUE;
122     }
123     return FALSE;
124   }
125   if (m_Family == PDFCS_DEVICECMYK) {
126     sRGB_to_AdobeCMYK(R, G, B, pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
127     return TRUE;
128   }
129   return FALSE;
130 }
131 FX_BOOL CPDF_DeviceCS::v_SetCMYK(FX_FLOAT* pBuf,
132                                  FX_FLOAT c,
133                                  FX_FLOAT m,
134                                  FX_FLOAT y,
135                                  FX_FLOAT k) const {
136   if (m_Family == PDFCS_DEVICERGB) {
137     AdobeCMYK_to_sRGB(c, m, y, k, pBuf[0], pBuf[1], pBuf[2]);
138     return TRUE;
139   }
140   if (m_Family == PDFCS_DEVICECMYK) {
141     pBuf[0] = c;
142     pBuf[1] = m;
143     pBuf[2] = y;
144     pBuf[3] = k;
145     return TRUE;
146   }
147   return FALSE;
148 }
149 static void ReverseRGB(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels) {
150   if (pDestBuf == pSrcBuf)
151     for (int i = 0; i < pixels; i++) {
152       uint8_t temp = pDestBuf[2];
153       pDestBuf[2] = pDestBuf[0];
154       pDestBuf[0] = temp;
155       pDestBuf += 3;
156     }
157   else
158     for (int i = 0; i < pixels; i++) {
159       *pDestBuf++ = pSrcBuf[2];
160       *pDestBuf++ = pSrcBuf[1];
161       *pDestBuf++ = pSrcBuf[0];
162       pSrcBuf += 3;
163     }
164 }
165 void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf,
166                                        const uint8_t* pSrcBuf,
167                                        int pixels,
168                                        int image_width,
169                                        int image_height,
170                                        FX_BOOL bTransMask) const {
171   if (bTransMask && m_Family == PDFCS_DEVICECMYK) {
172     for (int i = 0; i < pixels; i++) {
173       int k = 255 - pSrcBuf[3];
174       pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255;
175       pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255;
176       pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255;
177       pDestBuf += 3;
178       pSrcBuf += 4;
179     }
180     return;
181   }
182   if (m_Family == PDFCS_DEVICERGB) {
183     ReverseRGB(pDestBuf, pSrcBuf, pixels);
184   } else if (m_Family == PDFCS_DEVICEGRAY) {
185     for (int i = 0; i < pixels; i++) {
186       *pDestBuf++ = pSrcBuf[i];
187       *pDestBuf++ = pSrcBuf[i];
188       *pDestBuf++ = pSrcBuf[i];
189     }
190   } else {
191     for (int i = 0; i < pixels; i++) {
192       if (!m_dwStdConversion) {
193         AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3],
194                            pDestBuf[2], pDestBuf[1], pDestBuf[0]);
195       } else {
196         uint8_t k = pSrcBuf[3];
197         pDestBuf[2] = 255 - FX_MIN(255, pSrcBuf[0] + k);
198         pDestBuf[1] = 255 - FX_MIN(255, pSrcBuf[1] + k);
199         pDestBuf[0] = 255 - FX_MIN(255, pSrcBuf[2] + k);
200       }
201       pSrcBuf += 4;
202       pDestBuf += 3;
203     }
204   }
205 }
206 const uint8_t g_sRGBSamples1[] = {
207     0,   3,   6,   10,  13,  15,  18,  20,  22,  23,  25,  27,  28,  30,  31,
208     32,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
209     48,  49,  49,  50,  51,  52,  53,  53,  54,  55,  56,  56,  57,  58,  58,
210     59,  60,  61,  61,  62,  62,  63,  64,  64,  65,  66,  66,  67,  67,  68,
211     68,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  76,  76,
212     77,  77,  78,  78,  79,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,
213     84,  84,  85,  85,  85,  86,  86,  87,  87,  88,  88,  88,  89,  89,  90,
214     90,  91,  91,  91,  92,  92,  93,  93,  93,  94,  94,  95,  95,  95,  96,
215     96,  97,  97,  97,  98,  98,  98,  99,  99,  99,  100, 100, 101, 101, 101,
216     102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
217     107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
218     112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
219     116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
220 };
221 const uint8_t g_sRGBSamples2[] = {
222     120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
223     136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
224     150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
225     163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
226     174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
227     185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
228     194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
229     203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
230     212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
231     220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
232     228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
233     236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
234     243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249,
235     250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
236 };
237
238 static FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) {
239   if (colorComponent > 1) {
240     colorComponent = 1;
241   }
242   if (colorComponent < 0) {
243     colorComponent = 0;
244   }
245   int scale = (int)(colorComponent * 1023);
246   if (scale < 0) {
247     scale = 0;
248   }
249   if (scale < 192) {
250     colorComponent = (g_sRGBSamples1[scale] / 255.0f);
251   } else {
252     colorComponent = (g_sRGBSamples2[scale / 4 - 48] / 255.0f);
253   }
254   return colorComponent;
255 }
256
257 static void XYZ_to_sRGB(FX_FLOAT X,
258                         FX_FLOAT Y,
259                         FX_FLOAT Z,
260                         FX_FLOAT& R,
261                         FX_FLOAT& G,
262                         FX_FLOAT& B) {
263   FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z;
264   FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z;
265   FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z;
266
267   R = RGB_Conversion(R1);
268   G = RGB_Conversion(G1);
269   B = RGB_Conversion(B1);
270 }
271
272 static void XYZ_to_sRGB_WhitePoint(FX_FLOAT X,
273                                    FX_FLOAT Y,
274                                    FX_FLOAT Z,
275                                    FX_FLOAT& R,
276                                    FX_FLOAT& G,
277                                    FX_FLOAT& B,
278                                    FX_FLOAT Xw,
279                                    FX_FLOAT Yw,
280                                    FX_FLOAT Zw) {
281   // The following RGB_xyz is based on
282   // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06}
283
284   FX_FLOAT Rx = 0.64f, Ry = 0.33f;
285   FX_FLOAT Gx = 0.30f, Gy = 0.60f;
286   FX_FLOAT Bx = 0.15f, By = 0.06f;
287   CFX_Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy,
288                           1 - Bx - By);
289   CFX_Vector_3by1 whitePoint(Xw, Yw, Zw);
290   CFX_Vector_3by1 XYZ(X, Y, Z);
291
292   CFX_Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint);
293   CFX_Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0,
294                                    0, RGB_Sum_XYZ.c);
295   CFX_Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG);
296   CFX_Vector_3by1 RGB = M.Inverse().TransformVector(XYZ);
297
298   R = RGB_Conversion(RGB.a);
299   G = RGB_Conversion(RGB.b);
300   B = RGB_Conversion(RGB.c);
301 }
302 class CPDF_CalGray : public CPDF_ColorSpace {
303  public:
304   explicit CPDF_CalGray(CPDF_Document* pDoc)
305       : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY, 1) {}
306   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
307   FX_BOOL GetRGB(FX_FLOAT* pBuf,
308                  FX_FLOAT& R,
309                  FX_FLOAT& G,
310                  FX_FLOAT& B) const override;
311   FX_BOOL SetRGB(FX_FLOAT* pBuf,
312                  FX_FLOAT R,
313                  FX_FLOAT G,
314                  FX_FLOAT B) const override;
315   void TranslateImageLine(uint8_t* pDestBuf,
316                           const uint8_t* pSrcBuf,
317                           int pixels,
318                           int image_width,
319                           int image_height,
320                           FX_BOOL bTransMask = FALSE) const override;
321
322  private:
323   FX_FLOAT m_WhitePoint[3];
324   FX_FLOAT m_BlackPoint[3];
325   FX_FLOAT m_Gamma;
326 };
327
328 FX_BOOL CPDF_CalGray::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
329   CPDF_Dictionary* pDict = pArray->GetDict(1);
330   if (!pDict)
331     return FALSE;
332
333   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
334   int i;
335   for (i = 0; i < 3; i++) {
336     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
337   }
338   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
339   for (i = 0; i < 3; i++) {
340     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
341   }
342   m_Gamma = pDict->GetNumber(FX_BSTRC("Gamma"));
343   if (m_Gamma == 0) {
344     m_Gamma = 1.0f;
345   }
346   return TRUE;
347 }
348 FX_BOOL CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
349                              FX_FLOAT& R,
350                              FX_FLOAT& G,
351                              FX_FLOAT& B) const {
352   R = G = B = *pBuf;
353   return TRUE;
354 }
355 FX_BOOL CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
356                              FX_FLOAT R,
357                              FX_FLOAT G,
358                              FX_FLOAT B) const {
359   if (R == G && R == B) {
360     *pBuf = R;
361     return TRUE;
362   }
363   return FALSE;
364 }
365 void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
366                                       const uint8_t* pSrcBuf,
367                                       int pixels,
368                                       int image_width,
369                                       int image_height,
370                                       FX_BOOL bTransMask) const {
371   for (int i = 0; i < pixels; i++) {
372     *pDestBuf++ = pSrcBuf[i];
373     *pDestBuf++ = pSrcBuf[i];
374     *pDestBuf++ = pSrcBuf[i];
375   }
376 }
377 class CPDF_CalRGB : public CPDF_ColorSpace {
378  public:
379   explicit CPDF_CalRGB(CPDF_Document* pDoc)
380       : CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
381   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
382   FX_BOOL GetRGB(FX_FLOAT* pBuf,
383                  FX_FLOAT& R,
384                  FX_FLOAT& G,
385                  FX_FLOAT& B) const override;
386   FX_BOOL SetRGB(FX_FLOAT* pBuf,
387                  FX_FLOAT R,
388                  FX_FLOAT G,
389                  FX_FLOAT B) const override;
390   void TranslateImageLine(uint8_t* pDestBuf,
391                           const uint8_t* pSrcBuf,
392                           int pixels,
393                           int image_width,
394                           int image_height,
395                           FX_BOOL bTransMask = FALSE) const override;
396
397   FX_FLOAT m_WhitePoint[3];
398   FX_FLOAT m_BlackPoint[3];
399   FX_FLOAT m_Gamma[3];
400   FX_FLOAT m_Matrix[9];
401   FX_BOOL m_bGamma;
402   FX_BOOL m_bMatrix;
403 };
404 FX_BOOL CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
405   CPDF_Dictionary* pDict = pArray->GetDict(1);
406   if (!pDict)
407     return FALSE;
408
409   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
410   int i;
411   for (i = 0; i < 3; i++) {
412     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
413   }
414   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
415   for (i = 0; i < 3; i++) {
416     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
417   }
418   pParam = pDict->GetArray(FX_BSTRC("Gamma"));
419   if (pParam) {
420     m_bGamma = TRUE;
421     for (i = 0; i < 3; i++) {
422       m_Gamma[i] = pParam->GetNumber(i);
423     }
424   } else {
425     m_bGamma = FALSE;
426   }
427   pParam = pDict->GetArray(FX_BSTRC("Matrix"));
428   if (pParam) {
429     m_bMatrix = TRUE;
430     for (i = 0; i < 9; i++) {
431       m_Matrix[i] = pParam->GetNumber(i);
432     }
433   } else {
434     m_bMatrix = FALSE;
435   }
436   return TRUE;
437 }
438 FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
439                             FX_FLOAT& R,
440                             FX_FLOAT& G,
441                             FX_FLOAT& B) const {
442   FX_FLOAT A_ = pBuf[0];
443   FX_FLOAT B_ = pBuf[1];
444   FX_FLOAT C_ = pBuf[2];
445   if (m_bGamma) {
446     A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
447     B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
448     C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
449   }
450   FX_FLOAT X, Y, Z;
451   if (m_bMatrix) {
452     X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
453     Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
454     Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
455   } else {
456     X = A_;
457     Y = B_;
458     Z = C_;
459   }
460   XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1],
461                          m_WhitePoint[2]);
462   return TRUE;
463 }
464 FX_BOOL CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf,
465                             FX_FLOAT R,
466                             FX_FLOAT G,
467                             FX_FLOAT B) const {
468   pBuf[0] = R;
469   pBuf[1] = G;
470   pBuf[2] = B;
471   return TRUE;
472 }
473 void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
474                                      const uint8_t* pSrcBuf,
475                                      int pixels,
476                                      int image_width,
477                                      int image_height,
478                                      FX_BOOL bTransMask) const {
479   if (bTransMask) {
480     FX_FLOAT Cal[3];
481     FX_FLOAT R, G, B;
482     for (int i = 0; i < pixels; i++) {
483       Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
484       Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
485       Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
486       GetRGB(Cal, R, G, B);
487       pDestBuf[0] = FXSYS_round(B * 255);
488       pDestBuf[1] = FXSYS_round(G * 255);
489       pDestBuf[2] = FXSYS_round(R * 255);
490       pSrcBuf += 3;
491       pDestBuf += 3;
492     }
493   }
494   ReverseRGB(pDestBuf, pSrcBuf, pixels);
495 }
496 class CPDF_LabCS : public CPDF_ColorSpace {
497  public:
498   explicit CPDF_LabCS(CPDF_Document* pDoc)
499       : CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
500   void GetDefaultValue(int iComponent,
501                        FX_FLOAT& value,
502                        FX_FLOAT& min,
503                        FX_FLOAT& max) const override;
504   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
505   FX_BOOL GetRGB(FX_FLOAT* pBuf,
506                  FX_FLOAT& R,
507                  FX_FLOAT& G,
508                  FX_FLOAT& B) const override;
509   FX_BOOL SetRGB(FX_FLOAT* pBuf,
510                  FX_FLOAT R,
511                  FX_FLOAT G,
512                  FX_FLOAT B) const override;
513   void TranslateImageLine(uint8_t* pDestBuf,
514                           const uint8_t* pSrcBuf,
515                           int pixels,
516                           int image_width,
517                           int image_height,
518                           FX_BOOL bTransMask = FALSE) const override;
519
520   FX_FLOAT m_WhitePoint[3];
521   FX_FLOAT m_BlackPoint[3];
522   FX_FLOAT m_Ranges[4];
523 };
524 FX_BOOL CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
525   CPDF_Dictionary* pDict = pArray->GetDict(1);
526   if (!pDict) {
527     return FALSE;
528   }
529   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
530   int i;
531   for (i = 0; i < 3; i++) {
532     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
533   }
534   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
535   for (i = 0; i < 3; i++) {
536     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
537   }
538   pParam = pDict->GetArray(FX_BSTRC("Range"));
539   const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
540                                   100 * 1.0f};
541   for (i = 0; i < 4; i++) {
542     m_Ranges[i] = pParam ? pParam->GetNumber(i) : def_ranges[i];
543   }
544   return TRUE;
545 }
546 void CPDF_LabCS::GetDefaultValue(int iComponent,
547                                  FX_FLOAT& value,
548                                  FX_FLOAT& min,
549                                  FX_FLOAT& max) const {
550   assert(iComponent < 3);
551   value = 0;
552   if (iComponent == 0) {
553     min = 0;
554     max = 100 * 1.0f;
555   } else {
556     min = m_Ranges[iComponent * 2 - 2];
557     max = m_Ranges[iComponent * 2 - 1];
558     if (value < min) {
559       value = min;
560     } else if (value > max) {
561       value = max;
562     }
563   }
564 }
565 FX_BOOL CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
566                            FX_FLOAT& R,
567                            FX_FLOAT& G,
568                            FX_FLOAT& B) const {
569   FX_FLOAT Lstar = pBuf[0];
570   FX_FLOAT astar = pBuf[1];
571   FX_FLOAT bstar = pBuf[2];
572   FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
573   FX_FLOAT L = M + astar / 500.0f;
574   FX_FLOAT N = M - bstar / 200.0f;
575   FX_FLOAT X, Y, Z;
576   if (L < 0.2069f) {
577     X = 0.957f * 0.12842f * (L - 0.1379f);
578   } else {
579     X = 0.957f * L * L * L;
580   }
581   if (M < 0.2069f) {
582     Y = 0.12842f * (M - 0.1379f);
583   } else {
584     Y = M * M * M;
585   }
586   if (N < 0.2069f) {
587     Z = 1.0889f * 0.12842f * (N - 0.1379f);
588   } else {
589     Z = 1.0889f * N * N * N;
590   }
591   XYZ_to_sRGB(X, Y, Z, R, G, B);
592   return TRUE;
593 }
594 FX_BOOL CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
595                            FX_FLOAT R,
596                            FX_FLOAT G,
597                            FX_FLOAT B) const {
598   return FALSE;
599 }
600 void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
601                                     const uint8_t* pSrcBuf,
602                                     int pixels,
603                                     int image_width,
604                                     int image_height,
605                                     FX_BOOL bTransMask) const {
606   for (int i = 0; i < pixels; i++) {
607     FX_FLOAT lab[3];
608     FX_FLOAT R, G, B;
609     lab[0] = (pSrcBuf[0] * 100 / 255.0f);
610     lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
611     lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
612     GetRGB(lab, R, G, B);
613     pDestBuf[0] = (int32_t)(B * 255);
614     pDestBuf[1] = (int32_t)(G * 255);
615     pDestBuf[2] = (int32_t)(R * 255);
616     pDestBuf += 3;
617     pSrcBuf += 3;
618   }
619 }
620 CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize)
621     : m_bsRGB(FALSE), m_pTransform(NULL), m_nSrcComponents(0) {
622   if (dwSize == 3144 &&
623       FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
624     m_bsRGB = TRUE;
625     m_nSrcComponents = 3;
626   } else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
627     m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
628         pData, dwSize, m_nSrcComponents);
629   }
630 }
631 CPDF_IccProfile::~CPDF_IccProfile() {
632   if (m_pTransform) {
633     CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
634   }
635 }
636 class CPDF_ICCBasedCS : public CPDF_ColorSpace {
637  public:
638   explicit CPDF_ICCBasedCS(CPDF_Document* pDoc)
639       : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
640         m_pAlterCS(nullptr),
641         m_pProfile(nullptr),
642         m_pCache(nullptr),
643         m_pRanges(nullptr),
644         m_bOwn(FALSE) {}
645   ~CPDF_ICCBasedCS() override;
646
647   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
648   FX_BOOL GetRGB(FX_FLOAT* pBuf,
649                  FX_FLOAT& R,
650                  FX_FLOAT& G,
651                  FX_FLOAT& B) const override;
652   FX_BOOL SetRGB(FX_FLOAT* pBuf,
653                  FX_FLOAT R,
654                  FX_FLOAT G,
655                  FX_FLOAT B) const override;
656   FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
657                     FX_FLOAT& c,
658                     FX_FLOAT& m,
659                     FX_FLOAT& y,
660                     FX_FLOAT& k) const override;
661   void EnableStdConversion(FX_BOOL bEnabled) override;
662   void TranslateImageLine(uint8_t* pDestBuf,
663                           const uint8_t* pSrcBuf,
664                           int pixels,
665                           int image_width,
666                           int image_height,
667                           FX_BOOL bTransMask = FALSE) const override;
668
669   CPDF_ColorSpace* m_pAlterCS;
670   CPDF_IccProfile* m_pProfile;
671   uint8_t* m_pCache;
672   FX_FLOAT* m_pRanges;
673   FX_BOOL m_bOwn;
674 };
675
676 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
677   FX_Free(m_pCache);
678   FX_Free(m_pRanges);
679   if (m_pAlterCS && m_bOwn) {
680     m_pAlterCS->ReleaseCS();
681   }
682   if (m_pProfile && m_pDocument) {
683     m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
684   }
685 }
686
687 FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
688   CPDF_Stream* pStream = pArray->GetStream(1);
689   if (pStream == NULL) {
690     return FALSE;
691   }
692   m_pProfile = pDoc->LoadIccProfile(pStream);
693   if (!m_pProfile) {
694     return FALSE;
695   }
696   m_nComponents =
697       m_pProfile
698           ->GetComponents();  // Try using the nComponents from ICC profile
699   CPDF_Dictionary* pDict = pStream->GetDict();
700   if (m_pProfile->m_pTransform == NULL) {  // No valid ICC profile or using sRGB
701     CPDF_Object* pAlterCSObj =
702         pDict ? pDict->GetElementValue(FX_BSTRC("Alternate")) : NULL;
703     if (pAlterCSObj) {
704       CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
705       if (pAlterCS) {
706         if (m_nComponents == 0) {                 // NO valid ICC profile
707           if (pAlterCS->CountComponents() > 0) {  // Use Alternative colorspace
708             m_nComponents = pAlterCS->CountComponents();
709             m_pAlterCS = pAlterCS;
710             m_bOwn = TRUE;
711           } else {  // No valid alternative colorspace
712             pAlterCS->ReleaseCS();
713             int32_t nDictComponents =
714                 pDict ? pDict->GetInteger(FX_BSTRC("N")) : 0;
715             if (nDictComponents != 1 && nDictComponents != 3 &&
716                 nDictComponents != 4) {
717               return FALSE;
718             }
719             m_nComponents = nDictComponents;
720           }
721
722         } else {  // Using sRGB
723           if (pAlterCS->CountComponents() != m_nComponents) {
724             pAlterCS->ReleaseCS();
725           } else {
726             m_pAlterCS = pAlterCS;
727             m_bOwn = TRUE;
728           }
729         }
730       }
731     }
732     if (!m_pAlterCS) {
733       if (m_nComponents == 1) {
734         m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
735       } else if (m_nComponents == 3) {
736         m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
737       } else if (m_nComponents == 4) {
738         m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
739       }
740     }
741   }
742   CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
743   m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
744   for (int i = 0; i < m_nComponents * 2; i++) {
745     if (pRanges) {
746       m_pRanges[i] = pRanges->GetNumber(i);
747     } else if (i % 2) {
748       m_pRanges[i] = 1.0f;
749     } else {
750       m_pRanges[i] = 0;
751     }
752   }
753   return TRUE;
754 }
755 FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
756                                 FX_FLOAT& R,
757                                 FX_FLOAT& G,
758                                 FX_FLOAT& B) const {
759   if (m_pProfile && m_pProfile->m_bsRGB) {
760     R = pBuf[0];
761     G = pBuf[1];
762     B = pBuf[2];
763     return TRUE;
764   }
765   ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
766   if (m_pProfile->m_pTransform == NULL || pIccModule == NULL) {
767     if (m_pAlterCS) {
768       return m_pAlterCS->GetRGB(pBuf, R, G, B);
769     }
770     R = G = B = 0.0f;
771     return TRUE;
772   }
773   FX_FLOAT rgb[3];
774   pIccModule->SetComponents(m_nComponents);
775   pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
776   R = rgb[0];
777   G = rgb[1];
778   B = rgb[2];
779   return TRUE;
780 }
781 FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
782                                    FX_FLOAT& c,
783                                    FX_FLOAT& m,
784                                    FX_FLOAT& y,
785                                    FX_FLOAT& k) const {
786   if (m_nComponents != 4) {
787     return FALSE;
788   }
789   c = pBuf[0];
790   m = pBuf[1];
791   y = pBuf[2];
792   k = pBuf[3];
793   return TRUE;
794 }
795 FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
796                                 FX_FLOAT R,
797                                 FX_FLOAT G,
798                                 FX_FLOAT B) const {
799   return FALSE;
800 }
801 void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
802   CPDF_ColorSpace::EnableStdConversion(bEnabled);
803   if (m_pAlterCS) {
804     m_pAlterCS->EnableStdConversion(bEnabled);
805   }
806 }
807 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
808                                          const uint8_t* pSrcBuf,
809                                          int pixels,
810                                          int image_width,
811                                          int image_height,
812                                          FX_BOOL bTransMask) const {
813   if (m_pProfile->m_bsRGB) {
814     ReverseRGB(pDestBuf, pSrcBuf, pixels);
815   } else if (m_pProfile->m_pTransform) {
816     int nMaxColors = 1;
817     for (int i = 0; i < m_nComponents; i++) {
818       nMaxColors *= 52;
819     }
820     if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
821       CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
822           m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
823     } else {
824       if (m_pCache == NULL) {
825         ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
826         uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
827         uint8_t* pSrc = temp_src;
828         for (int i = 0; i < nMaxColors; i++) {
829           FX_DWORD color = i;
830           FX_DWORD order = nMaxColors / 52;
831           for (int c = 0; c < m_nComponents; c++) {
832             *pSrc++ = (uint8_t)(color / order * 5);
833             color %= order;
834             order /= 52;
835           }
836         }
837         CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
838             m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
839         FX_Free(temp_src);
840       }
841       for (int i = 0; i < pixels; i++) {
842         int index = 0;
843         for (int c = 0; c < m_nComponents; c++) {
844           index = index * 52 + (*pSrcBuf) / 5;
845           pSrcBuf++;
846         }
847         index *= 3;
848         *pDestBuf++ = m_pCache[index];
849         *pDestBuf++ = m_pCache[index + 1];
850         *pDestBuf++ = m_pCache[index + 2];
851       }
852     }
853   } else if (m_pAlterCS) {
854     m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
855                                    image_height);
856   }
857 }
858 class CPDF_IndexedCS : public CPDF_ColorSpace {
859  public:
860   explicit CPDF_IndexedCS(CPDF_Document* pDoc)
861       : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
862         m_pBaseCS(nullptr),
863         m_pCountedBaseCS(nullptr),
864         m_pCompMinMax(nullptr) {}
865   ~CPDF_IndexedCS() override;
866
867   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
868   FX_BOOL GetRGB(FX_FLOAT* pBuf,
869                  FX_FLOAT& R,
870                  FX_FLOAT& G,
871                  FX_FLOAT& B) const override;
872   CPDF_ColorSpace* GetBaseCS() const override;
873   void EnableStdConversion(FX_BOOL bEnabled) override;
874
875   CPDF_ColorSpace* m_pBaseCS;
876   CPDF_CountedColorSpace* m_pCountedBaseCS;
877   int m_nBaseComponents;
878   int m_MaxIndex;
879   CFX_ByteString m_Table;
880   FX_FLOAT* m_pCompMinMax;
881 };
882 CPDF_IndexedCS::~CPDF_IndexedCS() {
883   FX_Free(m_pCompMinMax);
884   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
885   if (pCS && m_pDocument) {
886     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
887   }
888 }
889 FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
890   if (pArray->GetCount() < 4) {
891     return FALSE;
892   }
893   CPDF_Object* pBaseObj = pArray->GetElementValue(1);
894   if (pBaseObj == m_pArray) {
895     return FALSE;
896   }
897   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
898   m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
899   if (m_pBaseCS == NULL) {
900     return FALSE;
901   }
902   m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
903   m_nBaseComponents = m_pBaseCS->CountComponents();
904   m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
905   FX_FLOAT defvalue;
906   for (int i = 0; i < m_nBaseComponents; i++) {
907     m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
908                                m_pCompMinMax[i * 2 + 1]);
909     m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
910   }
911   m_MaxIndex = pArray->GetInteger(2);
912
913   CPDF_Object* pTableObj = pArray->GetElementValue(3);
914   if (!pTableObj)
915     return FALSE;
916
917   if (CPDF_String* pString = pTableObj->AsString()) {
918     m_Table = pString->GetString();
919   } else if (CPDF_Stream* pStream = pTableObj->AsStream()) {
920     CPDF_StreamAcc acc;
921     acc.LoadAllData(pStream, FALSE);
922     m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
923   }
924   return TRUE;
925 }
926
927 FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
928                                FX_FLOAT& R,
929                                FX_FLOAT& G,
930                                FX_FLOAT& B) const {
931   int index = (int32_t)(*pBuf);
932   if (index < 0 || index > m_MaxIndex) {
933     return FALSE;
934   }
935   if (m_nBaseComponents) {
936     if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
937         (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
938       R = G = B = 0;
939       return FALSE;
940     }
941   }
942   CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
943   FX_FLOAT* comps = Comps;
944   const uint8_t* pTable = m_Table;
945   for (int i = 0; i < m_nBaseComponents; i++) {
946     comps[i] =
947         m_pCompMinMax[i * 2] +
948         m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
949   }
950   return m_pBaseCS->GetRGB(comps, R, G, B);
951 }
952 CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
953   return m_pBaseCS;
954 }
955 void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
956   CPDF_ColorSpace::EnableStdConversion(bEnabled);
957   if (m_pBaseCS) {
958     m_pBaseCS->EnableStdConversion(bEnabled);
959   }
960 }
961 #define MAX_PATTERN_COLORCOMPS 16
962 typedef struct _PatternValue {
963   CPDF_Pattern* m_pPattern;
964   CPDF_CountedPattern* m_pCountedPattern;
965   int m_nComps;
966   FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
967 } PatternValue;
968 CPDF_PatternCS::~CPDF_PatternCS() {
969   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
970   if (pCS && m_pDocument) {
971     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
972   }
973 }
974 FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
975   CPDF_Object* pBaseCS = pArray->GetElementValue(1);
976   if (pBaseCS == m_pArray) {
977     return FALSE;
978   }
979   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
980   m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
981   if (m_pBaseCS) {
982     if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
983       return FALSE;
984     }
985     m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
986     m_nComponents = m_pBaseCS->CountComponents() + 1;
987     if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
988       return FALSE;
989     }
990   } else {
991     m_nComponents = 1;
992   }
993   return TRUE;
994 }
995 FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
996                                FX_FLOAT& R,
997                                FX_FLOAT& G,
998                                FX_FLOAT& B) const {
999   if (m_pBaseCS) {
1000     ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
1001     PatternValue* pvalue = (PatternValue*)pBuf;
1002     if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
1003       return TRUE;
1004     }
1005   }
1006   R = G = B = 0.75f;
1007   return FALSE;
1008 }
1009 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
1010   return m_pBaseCS;
1011 }
1012 class CPDF_SeparationCS : public CPDF_ColorSpace {
1013  public:
1014   CPDF_SeparationCS(CPDF_Document* pDoc)
1015       : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
1016         m_pAltCS(nullptr),
1017         m_pFunc(nullptr) {}
1018   ~CPDF_SeparationCS() override;
1019   void GetDefaultValue(int iComponent,
1020                        FX_FLOAT& value,
1021                        FX_FLOAT& min,
1022                        FX_FLOAT& max) const override;
1023   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1024   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1025                  FX_FLOAT& R,
1026                  FX_FLOAT& G,
1027                  FX_FLOAT& B) const override;
1028   void EnableStdConversion(FX_BOOL bEnabled) override;
1029
1030   CPDF_ColorSpace* m_pAltCS;
1031   CPDF_Function* m_pFunc;
1032   enum { None, All, Colorant } m_Type;
1033 };
1034 CPDF_SeparationCS::~CPDF_SeparationCS() {
1035   if (m_pAltCS) {
1036     m_pAltCS->ReleaseCS();
1037   }
1038   delete m_pFunc;
1039 }
1040 void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1041                                         FX_FLOAT& value,
1042                                         FX_FLOAT& min,
1043                                         FX_FLOAT& max) const {
1044   value = 1.0f;
1045   min = 0;
1046   max = 1.0f;
1047 }
1048 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1049   CFX_ByteString name = pArray->GetString(1);
1050   if (name == FX_BSTRC("None")) {
1051     m_Type = None;
1052   } else {
1053     m_Type = Colorant;
1054     CPDF_Object* pAltCS = pArray->GetElementValue(2);
1055     if (pAltCS == m_pArray) {
1056       return FALSE;
1057     }
1058     m_pAltCS = Load(pDoc, pAltCS);
1059     if (!m_pAltCS) {
1060       return FALSE;
1061     }
1062     CPDF_Object* pFuncObj = pArray->GetElementValue(3);
1063     if (pFuncObj && !pFuncObj->IsName())
1064       m_pFunc = CPDF_Function::Load(pFuncObj);
1065
1066     if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1067       delete m_pFunc;
1068       m_pFunc = NULL;
1069     }
1070   }
1071   return TRUE;
1072 }
1073 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
1074                                   FX_FLOAT& R,
1075                                   FX_FLOAT& G,
1076                                   FX_FLOAT& B) const {
1077   if (m_Type == None) {
1078     return FALSE;
1079   }
1080   if (m_pFunc == NULL) {
1081     if (m_pAltCS == NULL) {
1082       return FALSE;
1083     }
1084     int nComps = m_pAltCS->CountComponents();
1085     CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
1086     for (int i = 0; i < nComps; i++) {
1087       results[i] = *pBuf;
1088     }
1089     return m_pAltCS->GetRGB(results, R, G, B);
1090   }
1091   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1092   int nresults = 0;
1093   m_pFunc->Call(pBuf, 1, results, nresults);
1094   if (nresults == 0) {
1095     return FALSE;
1096   }
1097   if (m_pAltCS) {
1098     return m_pAltCS->GetRGB(results, R, G, B);
1099   }
1100   R = G = B = 0;
1101   return FALSE;
1102 }
1103 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
1104   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1105   if (m_pAltCS) {
1106     m_pAltCS->EnableStdConversion(bEnabled);
1107   }
1108 }
1109 class CPDF_DeviceNCS : public CPDF_ColorSpace {
1110  public:
1111   CPDF_DeviceNCS(CPDF_Document* pDoc)
1112       : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1113         m_pAltCS(nullptr),
1114         m_pFunc(nullptr) {}
1115   ~CPDF_DeviceNCS() override;
1116   void GetDefaultValue(int iComponent,
1117                        FX_FLOAT& value,
1118                        FX_FLOAT& min,
1119                        FX_FLOAT& max) const override;
1120   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1121   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1122                  FX_FLOAT& R,
1123                  FX_FLOAT& G,
1124                  FX_FLOAT& B) const override;
1125   void EnableStdConversion(FX_BOOL bEnabled) override;
1126
1127   CPDF_ColorSpace* m_pAltCS;
1128   CPDF_Function* m_pFunc;
1129 };
1130 CPDF_DeviceNCS::~CPDF_DeviceNCS() {
1131   delete m_pFunc;
1132   if (m_pAltCS) {
1133     m_pAltCS->ReleaseCS();
1134   }
1135 }
1136 void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1137                                      FX_FLOAT& value,
1138                                      FX_FLOAT& min,
1139                                      FX_FLOAT& max) const {
1140   value = 1.0f;
1141   min = 0;
1142   max = 1.0f;
1143 }
1144 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1145   CPDF_Array* pObj = ToArray(pArray->GetElementValue(1));
1146   if (!pObj)
1147     return FALSE;
1148
1149   m_nComponents = pObj->GetCount();
1150   CPDF_Object* pAltCS = pArray->GetElementValue(2);
1151   if (!pAltCS || pAltCS == m_pArray) {
1152     return FALSE;
1153   }
1154   m_pAltCS = Load(pDoc, pAltCS);
1155   m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1156   if (m_pAltCS == NULL || m_pFunc == NULL) {
1157     return FALSE;
1158   }
1159   if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1160     return FALSE;
1161   }
1162   return TRUE;
1163 }
1164 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
1165                                FX_FLOAT& R,
1166                                FX_FLOAT& G,
1167                                FX_FLOAT& B) const {
1168   if (m_pFunc == NULL) {
1169     return FALSE;
1170   }
1171   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1172   int nresults = 0;
1173   m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1174   if (nresults == 0) {
1175     return FALSE;
1176   }
1177   return m_pAltCS->GetRGB(results, R, G, B);
1178 }
1179 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
1180   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1181   if (m_pAltCS) {
1182     m_pAltCS->EnableStdConversion(bEnabled);
1183   }
1184 }
1185 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
1186   return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
1187   ;
1188 }
1189 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
1190   if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
1191     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1192   }
1193   if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
1194     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1195   }
1196   if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
1197     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1198   }
1199   if (name == FX_BSTRC("Pattern")) {
1200     return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1201   }
1202   return NULL;
1203 }
1204 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
1205   if (!pObj)
1206     return nullptr;
1207   if (pObj->IsName())
1208     return _CSFromName(pObj->GetString());
1209
1210   if (CPDF_Stream* pStream = pObj->AsStream()) {
1211     CPDF_Dictionary* pDict = pStream->GetDict();
1212     if (!pDict)
1213       return nullptr;
1214
1215     CPDF_ColorSpace* pRet = nullptr;
1216     FX_POSITION pos = pDict->GetStartPos();
1217     while (pos) {
1218       CFX_ByteString bsKey;
1219       CPDF_Object* pValue = pDict->GetNextElement(pos, bsKey);
1220       if (ToName(pValue))
1221         pRet = _CSFromName(pValue->GetString());
1222       if (pRet)
1223         return pRet;
1224     }
1225     return nullptr;
1226   }
1227
1228   CPDF_Array* pArray = pObj->AsArray();
1229   if (!pArray || pArray->GetCount() == 0)
1230     return nullptr;
1231
1232   CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
1233   if (!pFamilyObj)
1234     return nullptr;
1235
1236   CFX_ByteString familyname = pFamilyObj->GetString();
1237   if (pArray->GetCount() == 1)
1238     return _CSFromName(familyname);
1239
1240   CPDF_ColorSpace* pCS = NULL;
1241   FX_DWORD id = familyname.GetID();
1242   if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
1243     pCS = new CPDF_CalGray(pDoc);
1244   } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
1245     pCS = new CPDF_CalRGB(pDoc);
1246   } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
1247     pCS = new CPDF_LabCS(pDoc);
1248   } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
1249     pCS = new CPDF_ICCBasedCS(pDoc);
1250   } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
1251              id == FXBSTR_ID('I', 0, 0, 0)) {
1252     pCS = new CPDF_IndexedCS(pDoc);
1253   } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
1254     pCS = new CPDF_SeparationCS(pDoc);
1255   } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
1256     pCS = new CPDF_DeviceNCS(pDoc);
1257   } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
1258     pCS = new CPDF_PatternCS(pDoc);
1259   } else {
1260     return NULL;
1261   }
1262   pCS->m_pArray = pArray;
1263   if (!pCS->v_Load(pDoc, pArray)) {
1264     pCS->ReleaseCS();
1265     return NULL;
1266   }
1267   return pCS;
1268 }
1269 void CPDF_ColorSpace::ReleaseCS() {
1270   if (this == GetStockCS(PDFCS_DEVICERGB)) {
1271     return;
1272   }
1273   if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
1274     return;
1275   }
1276   if (this == GetStockCS(PDFCS_DEVICECMYK)) {
1277     return;
1278   }
1279   if (this == GetStockCS(PDFCS_PATTERN)) {
1280     return;
1281   }
1282   delete this;
1283 }
1284 int CPDF_ColorSpace::GetBufSize() const {
1285   if (m_Family == PDFCS_PATTERN) {
1286     return sizeof(PatternValue);
1287   }
1288   return m_nComponents * sizeof(FX_FLOAT);
1289 }
1290 FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
1291   int size = GetBufSize();
1292   uint8_t* pBuf = FX_Alloc(uint8_t, size);
1293   return (FX_FLOAT*)pBuf;
1294 }
1295 FX_BOOL CPDF_ColorSpace::sRGB() const {
1296   if (m_Family == PDFCS_DEVICERGB) {
1297     return TRUE;
1298   }
1299   if (m_Family != PDFCS_ICCBASED) {
1300     return FALSE;
1301   }
1302   CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
1303   return pCS->m_pProfile->m_bsRGB;
1304 }
1305 FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
1306                                  FX_FLOAT& c,
1307                                  FX_FLOAT& m,
1308                                  FX_FLOAT& y,
1309                                  FX_FLOAT& k) const {
1310   if (v_GetCMYK(pBuf, c, m, y, k)) {
1311     return TRUE;
1312   }
1313   FX_FLOAT R, G, B;
1314   if (!GetRGB(pBuf, R, G, B)) {
1315     return FALSE;
1316   }
1317   sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
1318   return TRUE;
1319 }
1320 FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
1321                                  FX_FLOAT c,
1322                                  FX_FLOAT m,
1323                                  FX_FLOAT y,
1324                                  FX_FLOAT k) const {
1325   if (v_SetCMYK(pBuf, c, m, y, k)) {
1326     return TRUE;
1327   }
1328   FX_FLOAT R, G, B;
1329   AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
1330   return SetRGB(pBuf, R, G, B);
1331 }
1332 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
1333   if (buf == NULL || m_Family == PDFCS_PATTERN) {
1334     return;
1335   }
1336   FX_FLOAT min, max;
1337   for (int i = 0; i < m_nComponents; i++) {
1338     GetDefaultValue(i, buf[i], min, max);
1339   }
1340 }
1341 int CPDF_ColorSpace::GetMaxIndex() const {
1342   if (m_Family != PDFCS_INDEXED) {
1343     return 0;
1344   }
1345   CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
1346   return pCS->m_MaxIndex;
1347 }
1348 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
1349                                          const uint8_t* src_buf,
1350                                          int pixels,
1351                                          int image_width,
1352                                          int image_height,
1353                                          FX_BOOL bTransMask) const {
1354   CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
1355   FX_FLOAT* src = srcbuf;
1356   FX_FLOAT R, G, B;
1357   for (int i = 0; i < pixels; i++) {
1358     for (int j = 0; j < m_nComponents; j++)
1359       if (m_Family == PDFCS_INDEXED) {
1360         src[j] = (FX_FLOAT)(*src_buf++);
1361       } else {
1362         src[j] = (FX_FLOAT)(*src_buf++) / 255;
1363       }
1364     GetRGB(src, R, G, B);
1365     *dest_buf++ = (int32_t)(B * 255);
1366     *dest_buf++ = (int32_t)(G * 255);
1367     *dest_buf++ = (int32_t)(R * 255);
1368   }
1369 }
1370 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
1371   if (bEnabled) {
1372     m_dwStdConversion++;
1373   } else if (m_dwStdConversion) {
1374     m_dwStdConversion--;
1375   }
1376 }
1377 CPDF_Color::CPDF_Color(int family) {
1378   m_pCS = CPDF_ColorSpace::GetStockCS(family);
1379   int nComps = 3;
1380   if (family == PDFCS_DEVICEGRAY) {
1381     nComps = 1;
1382   } else if (family == PDFCS_DEVICECMYK) {
1383     nComps = 4;
1384   }
1385   m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
1386   for (int i = 0; i < nComps; i++) {
1387     m_pBuffer[i] = 0;
1388   }
1389 }
1390 CPDF_Color::~CPDF_Color() {
1391   ReleaseBuffer();
1392   ReleaseColorSpace();
1393 }
1394 void CPDF_Color::ReleaseBuffer() {
1395   if (!m_pBuffer) {
1396     return;
1397   }
1398   if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1399     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1400     CPDF_Pattern* pPattern =
1401         pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
1402     if (pPattern && pPattern->m_pDocument) {
1403       CPDF_DocPageData* pPageData = pPattern->m_pDocument->GetPageData();
1404       if (pPageData) {
1405         pPageData->ReleasePattern(pPattern->m_pPatternObj);
1406       }
1407     }
1408   }
1409   FX_Free(m_pBuffer);
1410   m_pBuffer = NULL;
1411 }
1412 void CPDF_Color::ReleaseColorSpace() {
1413   if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
1414     m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
1415     m_pCS = NULL;
1416   }
1417 }
1418 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
1419   if (m_pCS == pCS) {
1420     if (m_pBuffer == NULL) {
1421       m_pBuffer = pCS->CreateBuf();
1422     }
1423     ReleaseColorSpace();
1424     m_pCS = pCS;
1425     return;
1426   }
1427   ReleaseBuffer();
1428   ReleaseColorSpace();
1429   m_pCS = pCS;
1430   if (m_pCS) {
1431     m_pBuffer = pCS->CreateBuf();
1432     pCS->GetDefaultColor(m_pBuffer);
1433   }
1434 }
1435 void CPDF_Color::SetValue(FX_FLOAT* comps) {
1436   if (m_pBuffer == NULL) {
1437     return;
1438   }
1439   if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1440     FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1441   }
1442 }
1443 void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps) {
1444   if (ncomps > MAX_PATTERN_COLORCOMPS) {
1445     return;
1446   }
1447   if (m_pCS == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1448     FX_Free(m_pBuffer);
1449     m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1450     m_pBuffer = m_pCS->CreateBuf();
1451   }
1452   CPDF_DocPageData* pDocPageData = NULL;
1453   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1454   if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1455     pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
1456     if (pDocPageData) {
1457       pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
1458     }
1459   }
1460   pvalue->m_nComps = ncomps;
1461   pvalue->m_pPattern = pPattern;
1462   if (ncomps) {
1463     FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
1464   }
1465   pvalue->m_pCountedPattern = NULL;
1466   if (pPattern && pPattern->m_pDocument) {
1467     if (!pDocPageData) {
1468       pDocPageData = pPattern->m_pDocument->GetPageData();
1469     }
1470     pvalue->m_pCountedPattern =
1471         pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
1472   }
1473 }
1474 void CPDF_Color::Copy(const CPDF_Color* pSrc) {
1475   ReleaseBuffer();
1476   ReleaseColorSpace();
1477   m_pCS = pSrc->m_pCS;
1478   if (m_pCS && m_pCS->m_pDocument) {
1479     CPDF_Array* pArray = m_pCS->GetArray();
1480     if (pArray) {
1481       m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
1482     }
1483   }
1484   if (m_pCS == NULL) {
1485     return;
1486   }
1487   m_pBuffer = m_pCS->CreateBuf();
1488   FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
1489   if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1490     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1491     if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1492       pvalue->m_pPattern =
1493           pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(
1494               pvalue->m_pPattern->m_pPatternObj, FALSE,
1495               &pvalue->m_pPattern->m_ParentMatrix);
1496     }
1497   }
1498 }
1499 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
1500   if (m_pCS == NULL || m_pBuffer == NULL) {
1501     return FALSE;
1502   }
1503   FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
1504   if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
1505     return FALSE;
1506   }
1507   R = (int32_t)(r * 255 + 0.5f);
1508   G = (int32_t)(g * 255 + 0.5f);
1509   B = (int32_t)(b * 255 + 0.5f);
1510   return TRUE;
1511 }
1512 CPDF_Pattern* CPDF_Color::GetPattern() const {
1513   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1514     return NULL;
1515   }
1516   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1517   return pvalue->m_pPattern;
1518 }
1519 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
1520   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1521     return NULL;
1522   }
1523   return m_pCS->GetBaseCS();
1524 }
1525 FX_FLOAT* CPDF_Color::GetPatternColor() const {
1526   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1527     return NULL;
1528   }
1529   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1530   return pvalue->m_nComps ? pvalue->m_Comps : NULL;
1531 }
1532 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
1533   if (m_pCS != other.m_pCS || m_pCS == NULL) {
1534     return FALSE;
1535   }
1536   return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1537 }