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