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