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