Revert "Revert "Add type cast definitions for CPDF_Dictionary.""
[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   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
331   int i;
332   for (i = 0; i < 3; i++) {
333     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
334   }
335   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
336   for (i = 0; i < 3; i++) {
337     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
338   }
339   m_Gamma = pDict->GetNumber(FX_BSTRC("Gamma"));
340   if (m_Gamma == 0) {
341     m_Gamma = 1.0f;
342   }
343   return TRUE;
344 }
345 FX_BOOL CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
346                              FX_FLOAT& R,
347                              FX_FLOAT& G,
348                              FX_FLOAT& B) const {
349   R = G = B = *pBuf;
350   return TRUE;
351 }
352 FX_BOOL CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
353                              FX_FLOAT R,
354                              FX_FLOAT G,
355                              FX_FLOAT B) const {
356   if (R == G && R == B) {
357     *pBuf = R;
358     return TRUE;
359   }
360   return FALSE;
361 }
362 void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
363                                       const uint8_t* pSrcBuf,
364                                       int pixels,
365                                       int image_width,
366                                       int image_height,
367                                       FX_BOOL bTransMask) const {
368   for (int i = 0; i < pixels; i++) {
369     *pDestBuf++ = pSrcBuf[i];
370     *pDestBuf++ = pSrcBuf[i];
371     *pDestBuf++ = pSrcBuf[i];
372   }
373 }
374 class CPDF_CalRGB : public CPDF_ColorSpace {
375  public:
376   explicit CPDF_CalRGB(CPDF_Document* pDoc)
377       : CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
378   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
379   FX_BOOL GetRGB(FX_FLOAT* pBuf,
380                  FX_FLOAT& R,
381                  FX_FLOAT& G,
382                  FX_FLOAT& B) const override;
383   FX_BOOL SetRGB(FX_FLOAT* pBuf,
384                  FX_FLOAT R,
385                  FX_FLOAT G,
386                  FX_FLOAT B) const override;
387   void TranslateImageLine(uint8_t* pDestBuf,
388                           const uint8_t* pSrcBuf,
389                           int pixels,
390                           int image_width,
391                           int image_height,
392                           FX_BOOL bTransMask = FALSE) const override;
393
394   FX_FLOAT m_WhitePoint[3];
395   FX_FLOAT m_BlackPoint[3];
396   FX_FLOAT m_Gamma[3];
397   FX_FLOAT m_Matrix[9];
398   FX_BOOL m_bGamma;
399   FX_BOOL m_bMatrix;
400 };
401 FX_BOOL CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
402   CPDF_Dictionary* pDict = pArray->GetDict(1);
403   if (!pDict)
404     return FALSE;
405
406   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
407   int i;
408   for (i = 0; i < 3; i++) {
409     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
410   }
411   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
412   for (i = 0; i < 3; i++) {
413     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
414   }
415   pParam = pDict->GetArray(FX_BSTRC("Gamma"));
416   if (pParam) {
417     m_bGamma = TRUE;
418     for (i = 0; i < 3; i++) {
419       m_Gamma[i] = pParam->GetNumber(i);
420     }
421   } else {
422     m_bGamma = FALSE;
423   }
424   pParam = pDict->GetArray(FX_BSTRC("Matrix"));
425   if (pParam) {
426     m_bMatrix = TRUE;
427     for (i = 0; i < 9; i++) {
428       m_Matrix[i] = pParam->GetNumber(i);
429     }
430   } else {
431     m_bMatrix = FALSE;
432   }
433   return TRUE;
434 }
435 FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
436                             FX_FLOAT& R,
437                             FX_FLOAT& G,
438                             FX_FLOAT& B) const {
439   FX_FLOAT A_ = pBuf[0];
440   FX_FLOAT B_ = pBuf[1];
441   FX_FLOAT C_ = pBuf[2];
442   if (m_bGamma) {
443     A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
444     B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
445     C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
446   }
447   FX_FLOAT X, Y, Z;
448   if (m_bMatrix) {
449     X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
450     Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
451     Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
452   } else {
453     X = A_;
454     Y = B_;
455     Z = C_;
456   }
457   XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1],
458                          m_WhitePoint[2]);
459   return TRUE;
460 }
461 FX_BOOL CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf,
462                             FX_FLOAT R,
463                             FX_FLOAT G,
464                             FX_FLOAT B) const {
465   pBuf[0] = R;
466   pBuf[1] = G;
467   pBuf[2] = B;
468   return TRUE;
469 }
470 void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
471                                      const uint8_t* pSrcBuf,
472                                      int pixels,
473                                      int image_width,
474                                      int image_height,
475                                      FX_BOOL bTransMask) const {
476   if (bTransMask) {
477     FX_FLOAT Cal[3];
478     FX_FLOAT R, G, B;
479     for (int i = 0; i < pixels; i++) {
480       Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
481       Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
482       Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
483       GetRGB(Cal, R, G, B);
484       pDestBuf[0] = FXSYS_round(B * 255);
485       pDestBuf[1] = FXSYS_round(G * 255);
486       pDestBuf[2] = FXSYS_round(R * 255);
487       pSrcBuf += 3;
488       pDestBuf += 3;
489     }
490   }
491   ReverseRGB(pDestBuf, pSrcBuf, pixels);
492 }
493 class CPDF_LabCS : public CPDF_ColorSpace {
494  public:
495   explicit CPDF_LabCS(CPDF_Document* pDoc)
496       : CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
497   void GetDefaultValue(int iComponent,
498                        FX_FLOAT& value,
499                        FX_FLOAT& min,
500                        FX_FLOAT& max) const override;
501   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
502   FX_BOOL GetRGB(FX_FLOAT* pBuf,
503                  FX_FLOAT& R,
504                  FX_FLOAT& G,
505                  FX_FLOAT& B) const override;
506   FX_BOOL SetRGB(FX_FLOAT* pBuf,
507                  FX_FLOAT R,
508                  FX_FLOAT G,
509                  FX_FLOAT B) const override;
510   void TranslateImageLine(uint8_t* pDestBuf,
511                           const uint8_t* pSrcBuf,
512                           int pixels,
513                           int image_width,
514                           int image_height,
515                           FX_BOOL bTransMask = FALSE) const override;
516
517   FX_FLOAT m_WhitePoint[3];
518   FX_FLOAT m_BlackPoint[3];
519   FX_FLOAT m_Ranges[4];
520 };
521 FX_BOOL CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
522   CPDF_Dictionary* pDict = pArray->GetDict(1);
523   if (!pDict) {
524     return FALSE;
525   }
526   CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
527   int i;
528   for (i = 0; i < 3; i++) {
529     m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
530   }
531   pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
532   for (i = 0; i < 3; i++) {
533     m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
534   }
535   pParam = pDict->GetArray(FX_BSTRC("Range"));
536   const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
537                                   100 * 1.0f};
538   for (i = 0; i < 4; i++) {
539     m_Ranges[i] = pParam ? pParam->GetNumber(i) : def_ranges[i];
540   }
541   return TRUE;
542 }
543 void CPDF_LabCS::GetDefaultValue(int iComponent,
544                                  FX_FLOAT& value,
545                                  FX_FLOAT& min,
546                                  FX_FLOAT& max) const {
547   assert(iComponent < 3);
548   value = 0;
549   if (iComponent == 0) {
550     min = 0;
551     max = 100 * 1.0f;
552   } else {
553     min = m_Ranges[iComponent * 2 - 2];
554     max = m_Ranges[iComponent * 2 - 1];
555     if (value < min) {
556       value = min;
557     } else if (value > max) {
558       value = max;
559     }
560   }
561 }
562 FX_BOOL CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
563                            FX_FLOAT& R,
564                            FX_FLOAT& G,
565                            FX_FLOAT& B) const {
566   FX_FLOAT Lstar = pBuf[0];
567   FX_FLOAT astar = pBuf[1];
568   FX_FLOAT bstar = pBuf[2];
569   FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
570   FX_FLOAT L = M + astar / 500.0f;
571   FX_FLOAT N = M - bstar / 200.0f;
572   FX_FLOAT X, Y, Z;
573   if (L < 0.2069f) {
574     X = 0.957f * 0.12842f * (L - 0.1379f);
575   } else {
576     X = 0.957f * L * L * L;
577   }
578   if (M < 0.2069f) {
579     Y = 0.12842f * (M - 0.1379f);
580   } else {
581     Y = M * M * M;
582   }
583   if (N < 0.2069f) {
584     Z = 1.0889f * 0.12842f * (N - 0.1379f);
585   } else {
586     Z = 1.0889f * N * N * N;
587   }
588   XYZ_to_sRGB(X, Y, Z, R, G, B);
589   return TRUE;
590 }
591 FX_BOOL CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
592                            FX_FLOAT R,
593                            FX_FLOAT G,
594                            FX_FLOAT B) const {
595   return FALSE;
596 }
597 void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
598                                     const uint8_t* pSrcBuf,
599                                     int pixels,
600                                     int image_width,
601                                     int image_height,
602                                     FX_BOOL bTransMask) const {
603   for (int i = 0; i < pixels; i++) {
604     FX_FLOAT lab[3];
605     FX_FLOAT R, G, B;
606     lab[0] = (pSrcBuf[0] * 100 / 255.0f);
607     lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
608     lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
609     GetRGB(lab, R, G, B);
610     pDestBuf[0] = (int32_t)(B * 255);
611     pDestBuf[1] = (int32_t)(G * 255);
612     pDestBuf[2] = (int32_t)(R * 255);
613     pDestBuf += 3;
614     pSrcBuf += 3;
615   }
616 }
617 CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize)
618     : m_bsRGB(FALSE), m_pTransform(NULL), m_nSrcComponents(0) {
619   if (dwSize == 3144 &&
620       FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
621     m_bsRGB = TRUE;
622     m_nSrcComponents = 3;
623   } else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
624     m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
625         pData, dwSize, m_nSrcComponents);
626   }
627 }
628 CPDF_IccProfile::~CPDF_IccProfile() {
629   if (m_pTransform) {
630     CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
631   }
632 }
633 class CPDF_ICCBasedCS : public CPDF_ColorSpace {
634  public:
635   explicit CPDF_ICCBasedCS(CPDF_Document* pDoc)
636       : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
637         m_pAlterCS(nullptr),
638         m_pProfile(nullptr),
639         m_pCache(nullptr),
640         m_pRanges(nullptr),
641         m_bOwn(FALSE) {}
642   ~CPDF_ICCBasedCS() override;
643
644   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
645   FX_BOOL GetRGB(FX_FLOAT* pBuf,
646                  FX_FLOAT& R,
647                  FX_FLOAT& G,
648                  FX_FLOAT& B) const override;
649   FX_BOOL SetRGB(FX_FLOAT* pBuf,
650                  FX_FLOAT R,
651                  FX_FLOAT G,
652                  FX_FLOAT B) const override;
653   FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
654                     FX_FLOAT& c,
655                     FX_FLOAT& m,
656                     FX_FLOAT& y,
657                     FX_FLOAT& k) const override;
658   void EnableStdConversion(FX_BOOL bEnabled) override;
659   void TranslateImageLine(uint8_t* pDestBuf,
660                           const uint8_t* pSrcBuf,
661                           int pixels,
662                           int image_width,
663                           int image_height,
664                           FX_BOOL bTransMask = FALSE) const override;
665
666   CPDF_ColorSpace* m_pAlterCS;
667   CPDF_IccProfile* m_pProfile;
668   uint8_t* m_pCache;
669   FX_FLOAT* m_pRanges;
670   FX_BOOL m_bOwn;
671 };
672
673 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
674   FX_Free(m_pCache);
675   FX_Free(m_pRanges);
676   if (m_pAlterCS && m_bOwn) {
677     m_pAlterCS->ReleaseCS();
678   }
679   if (m_pProfile && m_pDocument) {
680     m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
681   }
682 }
683
684 FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
685   CPDF_Stream* pStream = pArray->GetStream(1);
686   if (pStream == NULL) {
687     return FALSE;
688   }
689   m_pProfile = pDoc->LoadIccProfile(pStream);
690   if (!m_pProfile) {
691     return FALSE;
692   }
693   m_nComponents =
694       m_pProfile
695           ->GetComponents();  // Try using the nComponents from ICC profile
696   CPDF_Dictionary* pDict = pStream->GetDict();
697   if (m_pProfile->m_pTransform == NULL) {  // No valid ICC profile or using sRGB
698     CPDF_Object* pAlterCSObj =
699         pDict ? pDict->GetElementValue(FX_BSTRC("Alternate")) : NULL;
700     if (pAlterCSObj) {
701       CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
702       if (pAlterCS) {
703         if (m_nComponents == 0) {                 // NO valid ICC profile
704           if (pAlterCS->CountComponents() > 0) {  // Use Alternative colorspace
705             m_nComponents = pAlterCS->CountComponents();
706             m_pAlterCS = pAlterCS;
707             m_bOwn = TRUE;
708           } else {  // No valid alternative colorspace
709             pAlterCS->ReleaseCS();
710             int32_t nDictComponents =
711                 pDict ? pDict->GetInteger(FX_BSTRC("N")) : 0;
712             if (nDictComponents != 1 && nDictComponents != 3 &&
713                 nDictComponents != 4) {
714               return FALSE;
715             }
716             m_nComponents = nDictComponents;
717           }
718
719         } else {  // Using sRGB
720           if (pAlterCS->CountComponents() != m_nComponents) {
721             pAlterCS->ReleaseCS();
722           } else {
723             m_pAlterCS = pAlterCS;
724             m_bOwn = TRUE;
725           }
726         }
727       }
728     }
729     if (!m_pAlterCS) {
730       if (m_nComponents == 1) {
731         m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
732       } else if (m_nComponents == 3) {
733         m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
734       } else if (m_nComponents == 4) {
735         m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
736       }
737     }
738   }
739   CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
740   m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
741   for (int i = 0; i < m_nComponents * 2; i++) {
742     if (pRanges) {
743       m_pRanges[i] = pRanges->GetNumber(i);
744     } else if (i % 2) {
745       m_pRanges[i] = 1.0f;
746     } else {
747       m_pRanges[i] = 0;
748     }
749   }
750   return TRUE;
751 }
752 FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
753                                 FX_FLOAT& R,
754                                 FX_FLOAT& G,
755                                 FX_FLOAT& B) const {
756   if (m_pProfile && m_pProfile->m_bsRGB) {
757     R = pBuf[0];
758     G = pBuf[1];
759     B = pBuf[2];
760     return TRUE;
761   }
762   ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
763   if (m_pProfile->m_pTransform == NULL || pIccModule == NULL) {
764     if (m_pAlterCS) {
765       return m_pAlterCS->GetRGB(pBuf, R, G, B);
766     }
767     R = G = B = 0.0f;
768     return TRUE;
769   }
770   FX_FLOAT rgb[3];
771   pIccModule->SetComponents(m_nComponents);
772   pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
773   R = rgb[0];
774   G = rgb[1];
775   B = rgb[2];
776   return TRUE;
777 }
778 FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
779                                    FX_FLOAT& c,
780                                    FX_FLOAT& m,
781                                    FX_FLOAT& y,
782                                    FX_FLOAT& k) const {
783   if (m_nComponents != 4) {
784     return FALSE;
785   }
786   c = pBuf[0];
787   m = pBuf[1];
788   y = pBuf[2];
789   k = pBuf[3];
790   return TRUE;
791 }
792 FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
793                                 FX_FLOAT R,
794                                 FX_FLOAT G,
795                                 FX_FLOAT B) const {
796   return FALSE;
797 }
798 void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
799   CPDF_ColorSpace::EnableStdConversion(bEnabled);
800   if (m_pAlterCS) {
801     m_pAlterCS->EnableStdConversion(bEnabled);
802   }
803 }
804 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
805                                          const uint8_t* pSrcBuf,
806                                          int pixels,
807                                          int image_width,
808                                          int image_height,
809                                          FX_BOOL bTransMask) const {
810   if (m_pProfile->m_bsRGB) {
811     ReverseRGB(pDestBuf, pSrcBuf, pixels);
812   } else if (m_pProfile->m_pTransform) {
813     int nMaxColors = 1;
814     for (int i = 0; i < m_nComponents; i++) {
815       nMaxColors *= 52;
816     }
817     if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
818       CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
819           m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
820     } else {
821       if (m_pCache == NULL) {
822         ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
823         uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
824         uint8_t* pSrc = temp_src;
825         for (int i = 0; i < nMaxColors; i++) {
826           FX_DWORD color = i;
827           FX_DWORD order = nMaxColors / 52;
828           for (int c = 0; c < m_nComponents; c++) {
829             *pSrc++ = (uint8_t)(color / order * 5);
830             color %= order;
831             order /= 52;
832           }
833         }
834         CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
835             m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
836         FX_Free(temp_src);
837       }
838       for (int i = 0; i < pixels; i++) {
839         int index = 0;
840         for (int c = 0; c < m_nComponents; c++) {
841           index = index * 52 + (*pSrcBuf) / 5;
842           pSrcBuf++;
843         }
844         index *= 3;
845         *pDestBuf++ = m_pCache[index];
846         *pDestBuf++ = m_pCache[index + 1];
847         *pDestBuf++ = m_pCache[index + 2];
848       }
849     }
850   } else if (m_pAlterCS) {
851     m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
852                                    image_height);
853   }
854 }
855 class CPDF_IndexedCS : public CPDF_ColorSpace {
856  public:
857   explicit CPDF_IndexedCS(CPDF_Document* pDoc)
858       : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
859         m_pBaseCS(nullptr),
860         m_pCountedBaseCS(nullptr),
861         m_pCompMinMax(nullptr) {}
862   ~CPDF_IndexedCS() override;
863
864   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
865   FX_BOOL GetRGB(FX_FLOAT* pBuf,
866                  FX_FLOAT& R,
867                  FX_FLOAT& G,
868                  FX_FLOAT& B) const override;
869   CPDF_ColorSpace* GetBaseCS() const override;
870   void EnableStdConversion(FX_BOOL bEnabled) override;
871
872   CPDF_ColorSpace* m_pBaseCS;
873   CPDF_CountedColorSpace* m_pCountedBaseCS;
874   int m_nBaseComponents;
875   int m_MaxIndex;
876   CFX_ByteString m_Table;
877   FX_FLOAT* m_pCompMinMax;
878 };
879 CPDF_IndexedCS::~CPDF_IndexedCS() {
880   FX_Free(m_pCompMinMax);
881   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
882   if (pCS && m_pDocument) {
883     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
884   }
885 }
886 FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
887   if (pArray->GetCount() < 4) {
888     return FALSE;
889   }
890   CPDF_Object* pBaseObj = pArray->GetElementValue(1);
891   if (pBaseObj == m_pArray) {
892     return FALSE;
893   }
894   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
895   m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
896   if (m_pBaseCS == NULL) {
897     return FALSE;
898   }
899   m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
900   m_nBaseComponents = m_pBaseCS->CountComponents();
901   m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
902   FX_FLOAT defvalue;
903   for (int i = 0; i < m_nBaseComponents; i++) {
904     m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
905                                m_pCompMinMax[i * 2 + 1]);
906     m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
907   }
908   m_MaxIndex = pArray->GetInteger(2);
909   CPDF_Object* pTableObj = pArray->GetElementValue(3);
910   if (pTableObj == NULL) {
911     return FALSE;
912   }
913   if (pTableObj->GetType() == PDFOBJ_STRING) {
914     m_Table = ((CPDF_String*)pTableObj)->GetString();
915   } else if (pTableObj->GetType() == PDFOBJ_STREAM) {
916     CPDF_StreamAcc acc;
917     acc.LoadAllData((CPDF_Stream*)pTableObj, FALSE);
918     m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
919   }
920   return TRUE;
921 }
922
923 FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
924                                FX_FLOAT& R,
925                                FX_FLOAT& G,
926                                FX_FLOAT& B) const {
927   int index = (int32_t)(*pBuf);
928   if (index < 0 || index > m_MaxIndex) {
929     return FALSE;
930   }
931   if (m_nBaseComponents) {
932     if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
933         (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
934       R = G = B = 0;
935       return FALSE;
936     }
937   }
938   CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
939   FX_FLOAT* comps = Comps;
940   const uint8_t* pTable = m_Table;
941   for (int i = 0; i < m_nBaseComponents; i++) {
942     comps[i] =
943         m_pCompMinMax[i * 2] +
944         m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
945   }
946   return m_pBaseCS->GetRGB(comps, R, G, B);
947 }
948 CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
949   return m_pBaseCS;
950 }
951 void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
952   CPDF_ColorSpace::EnableStdConversion(bEnabled);
953   if (m_pBaseCS) {
954     m_pBaseCS->EnableStdConversion(bEnabled);
955   }
956 }
957 #define MAX_PATTERN_COLORCOMPS 16
958 typedef struct _PatternValue {
959   CPDF_Pattern* m_pPattern;
960   CPDF_CountedPattern* m_pCountedPattern;
961   int m_nComps;
962   FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
963 } PatternValue;
964 CPDF_PatternCS::~CPDF_PatternCS() {
965   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
966   if (pCS && m_pDocument) {
967     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
968   }
969 }
970 FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
971   CPDF_Object* pBaseCS = pArray->GetElementValue(1);
972   if (pBaseCS == m_pArray) {
973     return FALSE;
974   }
975   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
976   m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
977   if (m_pBaseCS) {
978     if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
979       return FALSE;
980     }
981     m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
982     m_nComponents = m_pBaseCS->CountComponents() + 1;
983     if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
984       return FALSE;
985     }
986   } else {
987     m_nComponents = 1;
988   }
989   return TRUE;
990 }
991 FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
992                                FX_FLOAT& R,
993                                FX_FLOAT& G,
994                                FX_FLOAT& B) const {
995   if (m_pBaseCS) {
996     ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
997     PatternValue* pvalue = (PatternValue*)pBuf;
998     if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
999       return TRUE;
1000     }
1001   }
1002   R = G = B = 0.75f;
1003   return FALSE;
1004 }
1005 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
1006   return m_pBaseCS;
1007 }
1008 class CPDF_SeparationCS : public CPDF_ColorSpace {
1009  public:
1010   CPDF_SeparationCS(CPDF_Document* pDoc)
1011       : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
1012         m_pAltCS(nullptr),
1013         m_pFunc(nullptr) {}
1014   ~CPDF_SeparationCS() override;
1015   void GetDefaultValue(int iComponent,
1016                        FX_FLOAT& value,
1017                        FX_FLOAT& min,
1018                        FX_FLOAT& max) const override;
1019   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1020   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1021                  FX_FLOAT& R,
1022                  FX_FLOAT& G,
1023                  FX_FLOAT& B) const override;
1024   void EnableStdConversion(FX_BOOL bEnabled) override;
1025
1026   CPDF_ColorSpace* m_pAltCS;
1027   CPDF_Function* m_pFunc;
1028   enum { None, All, Colorant } m_Type;
1029 };
1030 CPDF_SeparationCS::~CPDF_SeparationCS() {
1031   if (m_pAltCS) {
1032     m_pAltCS->ReleaseCS();
1033   }
1034   delete m_pFunc;
1035 }
1036 void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1037                                         FX_FLOAT& value,
1038                                         FX_FLOAT& min,
1039                                         FX_FLOAT& max) const {
1040   value = 1.0f;
1041   min = 0;
1042   max = 1.0f;
1043 }
1044 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1045   CFX_ByteString name = pArray->GetString(1);
1046   if (name == FX_BSTRC("None")) {
1047     m_Type = None;
1048   } else {
1049     m_Type = Colorant;
1050     CPDF_Object* pAltCS = pArray->GetElementValue(2);
1051     if (pAltCS == m_pArray) {
1052       return FALSE;
1053     }
1054     m_pAltCS = Load(pDoc, pAltCS);
1055     if (!m_pAltCS) {
1056       return FALSE;
1057     }
1058     CPDF_Object* pFuncObj = pArray->GetElementValue(3);
1059     if (pFuncObj && pFuncObj->GetType() != PDFOBJ_NAME) {
1060       m_pFunc = CPDF_Function::Load(pFuncObj);
1061     }
1062     if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1063       delete m_pFunc;
1064       m_pFunc = NULL;
1065     }
1066   }
1067   return TRUE;
1068 }
1069 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
1070                                   FX_FLOAT& R,
1071                                   FX_FLOAT& G,
1072                                   FX_FLOAT& B) const {
1073   if (m_Type == None) {
1074     return FALSE;
1075   }
1076   if (m_pFunc == NULL) {
1077     if (m_pAltCS == NULL) {
1078       return FALSE;
1079     }
1080     int nComps = m_pAltCS->CountComponents();
1081     CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
1082     for (int i = 0; i < nComps; i++) {
1083       results[i] = *pBuf;
1084     }
1085     return m_pAltCS->GetRGB(results, R, G, B);
1086   }
1087   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1088   int nresults = 0;
1089   m_pFunc->Call(pBuf, 1, results, nresults);
1090   if (nresults == 0) {
1091     return FALSE;
1092   }
1093   if (m_pAltCS) {
1094     return m_pAltCS->GetRGB(results, R, G, B);
1095   }
1096   R = G = B = 0;
1097   return FALSE;
1098 }
1099 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
1100   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1101   if (m_pAltCS) {
1102     m_pAltCS->EnableStdConversion(bEnabled);
1103   }
1104 }
1105 class CPDF_DeviceNCS : public CPDF_ColorSpace {
1106  public:
1107   CPDF_DeviceNCS(CPDF_Document* pDoc)
1108       : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1109         m_pAltCS(nullptr),
1110         m_pFunc(nullptr) {}
1111   ~CPDF_DeviceNCS() override;
1112   void GetDefaultValue(int iComponent,
1113                        FX_FLOAT& value,
1114                        FX_FLOAT& min,
1115                        FX_FLOAT& max) const override;
1116   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1117   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1118                  FX_FLOAT& R,
1119                  FX_FLOAT& G,
1120                  FX_FLOAT& B) const override;
1121   void EnableStdConversion(FX_BOOL bEnabled) override;
1122
1123   CPDF_ColorSpace* m_pAltCS;
1124   CPDF_Function* m_pFunc;
1125 };
1126 CPDF_DeviceNCS::~CPDF_DeviceNCS() {
1127   delete m_pFunc;
1128   if (m_pAltCS) {
1129     m_pAltCS->ReleaseCS();
1130   }
1131 }
1132 void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1133                                      FX_FLOAT& value,
1134                                      FX_FLOAT& min,
1135                                      FX_FLOAT& max) const {
1136   value = 1.0f;
1137   min = 0;
1138   max = 1.0f;
1139 }
1140 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1141   CPDF_Object* pObj = pArray->GetElementValue(1);
1142   if (!pObj) {
1143     return FALSE;
1144   }
1145   if (pObj->GetType() != PDFOBJ_ARRAY) {
1146     return FALSE;
1147   }
1148   m_nComponents = ((CPDF_Array*)pObj)->GetCount();
1149   CPDF_Object* pAltCS = pArray->GetElementValue(2);
1150   if (!pAltCS || pAltCS == m_pArray) {
1151     return FALSE;
1152   }
1153   m_pAltCS = Load(pDoc, pAltCS);
1154   m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1155   if (m_pAltCS == NULL || m_pFunc == NULL) {
1156     return FALSE;
1157   }
1158   if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1159     return FALSE;
1160   }
1161   return TRUE;
1162 }
1163 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
1164                                FX_FLOAT& R,
1165                                FX_FLOAT& G,
1166                                FX_FLOAT& B) const {
1167   if (m_pFunc == NULL) {
1168     return FALSE;
1169   }
1170   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1171   int nresults = 0;
1172   m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1173   if (nresults == 0) {
1174     return FALSE;
1175   }
1176   return m_pAltCS->GetRGB(results, R, G, B);
1177 }
1178 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
1179   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1180   if (m_pAltCS) {
1181     m_pAltCS->EnableStdConversion(bEnabled);
1182   }
1183 }
1184 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
1185   return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
1186   ;
1187 }
1188 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
1189   if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
1190     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1191   }
1192   if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
1193     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1194   }
1195   if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
1196     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1197   }
1198   if (name == FX_BSTRC("Pattern")) {
1199     return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1200   }
1201   return NULL;
1202 }
1203 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
1204   if (pObj == NULL) {
1205     return NULL;
1206   }
1207   if (pObj->GetType() == PDFOBJ_NAME) {
1208     return _CSFromName(pObj->GetString());
1209   }
1210   if (pObj->GetType() == PDFOBJ_STREAM) {
1211     CPDF_Dictionary* pDict = ((CPDF_Stream*)pObj)->GetDict();
1212     if (!pDict) {
1213       return NULL;
1214     }
1215     CPDF_ColorSpace* pRet = NULL;
1216     FX_POSITION pos = pDict->GetStartPos();
1217     while (pos) {
1218       CFX_ByteString bsKey;
1219       CPDF_Object* pValue = pDict->GetNextElement(pos, bsKey);
1220       if (pValue && pValue->GetType() == PDFOBJ_NAME) {
1221         pRet = _CSFromName(pValue->GetString());
1222       }
1223       if (pRet) {
1224         return pRet;
1225       }
1226     }
1227     return NULL;
1228   }
1229   if (pObj->GetType() != PDFOBJ_ARRAY) {
1230     return NULL;
1231   }
1232   CPDF_Array* pArray = (CPDF_Array*)pObj;
1233   if (pArray->GetCount() == 0) {
1234     return NULL;
1235   }
1236   CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
1237   if (!pFamilyObj) {
1238     return NULL;
1239   }
1240   CFX_ByteString familyname = pFamilyObj->GetString();
1241   if (pArray->GetCount() == 1) {
1242     return _CSFromName(familyname);
1243   }
1244   CPDF_ColorSpace* pCS = NULL;
1245   FX_DWORD id = familyname.GetID();
1246   if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
1247     pCS = new CPDF_CalGray(pDoc);
1248   } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
1249     pCS = new CPDF_CalRGB(pDoc);
1250   } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
1251     pCS = new CPDF_LabCS(pDoc);
1252   } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
1253     pCS = new CPDF_ICCBasedCS(pDoc);
1254   } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
1255              id == FXBSTR_ID('I', 0, 0, 0)) {
1256     pCS = new CPDF_IndexedCS(pDoc);
1257   } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
1258     pCS = new CPDF_SeparationCS(pDoc);
1259   } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
1260     pCS = new CPDF_DeviceNCS(pDoc);
1261   } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
1262     pCS = new CPDF_PatternCS(pDoc);
1263   } else {
1264     return NULL;
1265   }
1266   pCS->m_pArray = pArray;
1267   if (!pCS->v_Load(pDoc, pArray)) {
1268     pCS->ReleaseCS();
1269     return NULL;
1270   }
1271   return pCS;
1272 }
1273 void CPDF_ColorSpace::ReleaseCS() {
1274   if (this == GetStockCS(PDFCS_DEVICERGB)) {
1275     return;
1276   }
1277   if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
1278     return;
1279   }
1280   if (this == GetStockCS(PDFCS_DEVICECMYK)) {
1281     return;
1282   }
1283   if (this == GetStockCS(PDFCS_PATTERN)) {
1284     return;
1285   }
1286   delete this;
1287 }
1288 int CPDF_ColorSpace::GetBufSize() const {
1289   if (m_Family == PDFCS_PATTERN) {
1290     return sizeof(PatternValue);
1291   }
1292   return m_nComponents * sizeof(FX_FLOAT);
1293 }
1294 FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
1295   int size = GetBufSize();
1296   uint8_t* pBuf = FX_Alloc(uint8_t, size);
1297   return (FX_FLOAT*)pBuf;
1298 }
1299 FX_BOOL CPDF_ColorSpace::sRGB() const {
1300   if (m_Family == PDFCS_DEVICERGB) {
1301     return TRUE;
1302   }
1303   if (m_Family != PDFCS_ICCBASED) {
1304     return FALSE;
1305   }
1306   CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
1307   return pCS->m_pProfile->m_bsRGB;
1308 }
1309 FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
1310                                  FX_FLOAT& c,
1311                                  FX_FLOAT& m,
1312                                  FX_FLOAT& y,
1313                                  FX_FLOAT& k) const {
1314   if (v_GetCMYK(pBuf, c, m, y, k)) {
1315     return TRUE;
1316   }
1317   FX_FLOAT R, G, B;
1318   if (!GetRGB(pBuf, R, G, B)) {
1319     return FALSE;
1320   }
1321   sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
1322   return TRUE;
1323 }
1324 FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
1325                                  FX_FLOAT c,
1326                                  FX_FLOAT m,
1327                                  FX_FLOAT y,
1328                                  FX_FLOAT k) const {
1329   if (v_SetCMYK(pBuf, c, m, y, k)) {
1330     return TRUE;
1331   }
1332   FX_FLOAT R, G, B;
1333   AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
1334   return SetRGB(pBuf, R, G, B);
1335 }
1336 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
1337   if (buf == NULL || m_Family == PDFCS_PATTERN) {
1338     return;
1339   }
1340   FX_FLOAT min, max;
1341   for (int i = 0; i < m_nComponents; i++) {
1342     GetDefaultValue(i, buf[i], min, max);
1343   }
1344 }
1345 int CPDF_ColorSpace::GetMaxIndex() const {
1346   if (m_Family != PDFCS_INDEXED) {
1347     return 0;
1348   }
1349   CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
1350   return pCS->m_MaxIndex;
1351 }
1352 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
1353                                          const uint8_t* src_buf,
1354                                          int pixels,
1355                                          int image_width,
1356                                          int image_height,
1357                                          FX_BOOL bTransMask) const {
1358   CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
1359   FX_FLOAT* src = srcbuf;
1360   FX_FLOAT R, G, B;
1361   for (int i = 0; i < pixels; i++) {
1362     for (int j = 0; j < m_nComponents; j++)
1363       if (m_Family == PDFCS_INDEXED) {
1364         src[j] = (FX_FLOAT)(*src_buf++);
1365       } else {
1366         src[j] = (FX_FLOAT)(*src_buf++) / 255;
1367       }
1368     GetRGB(src, R, G, B);
1369     *dest_buf++ = (int32_t)(B * 255);
1370     *dest_buf++ = (int32_t)(G * 255);
1371     *dest_buf++ = (int32_t)(R * 255);
1372   }
1373 }
1374 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
1375   if (bEnabled) {
1376     m_dwStdConversion++;
1377   } else if (m_dwStdConversion) {
1378     m_dwStdConversion--;
1379   }
1380 }
1381 CPDF_Color::CPDF_Color(int family) {
1382   m_pCS = CPDF_ColorSpace::GetStockCS(family);
1383   int nComps = 3;
1384   if (family == PDFCS_DEVICEGRAY) {
1385     nComps = 1;
1386   } else if (family == PDFCS_DEVICECMYK) {
1387     nComps = 4;
1388   }
1389   m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
1390   for (int i = 0; i < nComps; i++) {
1391     m_pBuffer[i] = 0;
1392   }
1393 }
1394 CPDF_Color::~CPDF_Color() {
1395   ReleaseBuffer();
1396   ReleaseColorSpace();
1397 }
1398 void CPDF_Color::ReleaseBuffer() {
1399   if (!m_pBuffer) {
1400     return;
1401   }
1402   if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1403     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1404     CPDF_Pattern* pPattern =
1405         pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
1406     if (pPattern && pPattern->m_pDocument) {
1407       CPDF_DocPageData* pPageData = pPattern->m_pDocument->GetPageData();
1408       if (pPageData) {
1409         pPageData->ReleasePattern(pPattern->m_pPatternObj);
1410       }
1411     }
1412   }
1413   FX_Free(m_pBuffer);
1414   m_pBuffer = NULL;
1415 }
1416 void CPDF_Color::ReleaseColorSpace() {
1417   if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
1418     m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
1419     m_pCS = NULL;
1420   }
1421 }
1422 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
1423   if (m_pCS == pCS) {
1424     if (m_pBuffer == NULL) {
1425       m_pBuffer = pCS->CreateBuf();
1426     }
1427     ReleaseColorSpace();
1428     m_pCS = pCS;
1429     return;
1430   }
1431   ReleaseBuffer();
1432   ReleaseColorSpace();
1433   m_pCS = pCS;
1434   if (m_pCS) {
1435     m_pBuffer = pCS->CreateBuf();
1436     pCS->GetDefaultColor(m_pBuffer);
1437   }
1438 }
1439 void CPDF_Color::SetValue(FX_FLOAT* comps) {
1440   if (m_pBuffer == NULL) {
1441     return;
1442   }
1443   if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1444     FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1445   }
1446 }
1447 void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps) {
1448   if (ncomps > MAX_PATTERN_COLORCOMPS) {
1449     return;
1450   }
1451   if (m_pCS == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1452     FX_Free(m_pBuffer);
1453     m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1454     m_pBuffer = m_pCS->CreateBuf();
1455   }
1456   CPDF_DocPageData* pDocPageData = NULL;
1457   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1458   if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1459     pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
1460     if (pDocPageData) {
1461       pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
1462     }
1463   }
1464   pvalue->m_nComps = ncomps;
1465   pvalue->m_pPattern = pPattern;
1466   if (ncomps) {
1467     FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
1468   }
1469   pvalue->m_pCountedPattern = NULL;
1470   if (pPattern && pPattern->m_pDocument) {
1471     if (!pDocPageData) {
1472       pDocPageData = pPattern->m_pDocument->GetPageData();
1473     }
1474     pvalue->m_pCountedPattern =
1475         pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
1476   }
1477 }
1478 void CPDF_Color::Copy(const CPDF_Color* pSrc) {
1479   ReleaseBuffer();
1480   ReleaseColorSpace();
1481   m_pCS = pSrc->m_pCS;
1482   if (m_pCS && m_pCS->m_pDocument) {
1483     CPDF_Array* pArray = m_pCS->GetArray();
1484     if (pArray) {
1485       m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
1486     }
1487   }
1488   if (m_pCS == NULL) {
1489     return;
1490   }
1491   m_pBuffer = m_pCS->CreateBuf();
1492   FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
1493   if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1494     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1495     if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1496       pvalue->m_pPattern =
1497           pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(
1498               pvalue->m_pPattern->m_pPatternObj, FALSE,
1499               &pvalue->m_pPattern->m_ParentMatrix);
1500     }
1501   }
1502 }
1503 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
1504   if (m_pCS == NULL || m_pBuffer == NULL) {
1505     return FALSE;
1506   }
1507   FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
1508   if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
1509     return FALSE;
1510   }
1511   R = (int32_t)(r * 255 + 0.5f);
1512   G = (int32_t)(g * 255 + 0.5f);
1513   B = (int32_t)(b * 255 + 0.5f);
1514   return TRUE;
1515 }
1516 CPDF_Pattern* CPDF_Color::GetPattern() const {
1517   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1518     return NULL;
1519   }
1520   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1521   return pvalue->m_pPattern;
1522 }
1523 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
1524   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1525     return NULL;
1526   }
1527   return m_pCS->GetBaseCS();
1528 }
1529 FX_FLOAT* CPDF_Color::GetPatternColor() const {
1530   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1531     return NULL;
1532   }
1533   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1534   return pvalue->m_nComps ? pvalue->m_Comps : NULL;
1535 }
1536 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
1537   if (m_pCS != other.m_pCS || m_pCS == NULL) {
1538     return FALSE;
1539   }
1540   return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1541 }