• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
~CPDF_CalGray()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);
~CPDF_CalRGB()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);
~CPDF_LabCS()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 
IsSRGB() const168   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:
Vector_3by1()251   Vector_3by1() : a(0.0f), b(0.0f), c(0.0f) {}
252 
Vector_3by1(float a1,float b1,float c1)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:
Matrix_3by3()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 
Matrix_3by3(float a1,float b1,float c1,float d1,float e1,float f1,float g1,float h1,float i1)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 
Inverse()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 
Multiply(const Matrix_3by3 & m)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 
TransformVector(const Vector_3by1 & v)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 
RGB_Conversion(float colorComponent)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 
XYZ_to_sRGB(float X,float Y,float Z,float * R,float * G,float * B)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 
XYZ_to_sRGB_WhitePoint(float X,float Y,float Z,float Xw,float Yw,float Zw,float * R,float * G,float * B)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
ColorspaceFromName(const ByteString & name)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
GetStockCS(int family)384 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
385   return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
386 }
387 
388 // static
Load(CPDF_Document * pDoc,CPDF_Object * pObj)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
Load(CPDF_Document * pDoc,CPDF_Object * pObj,std::set<CPDF_Object * > * pVisited)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 
Release()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 
GetBufSize() const483 int CPDF_ColorSpace::GetBufSize() const {
484   if (m_Family == PDFCS_PATTERN)
485     return sizeof(PatternValue);
486   return m_nComponents * sizeof(float);
487 }
488 
CreateBuf()489 float* CPDF_ColorSpace::CreateBuf() {
490   int size = GetBufSize();
491   return reinterpret_cast<float*>(FX_Alloc(uint8_t, size));
492 }
493 
GetDefaultColor(float * buf) const494 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 
CountComponents() const504 uint32_t CPDF_ColorSpace::CountComponents() const {
505   return m_nComponents;
506 }
507 
GetDefaultValue(int iComponent,float * value,float * min,float * max) const508 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 
TranslateImageLine(uint8_t * dest_buf,const uint8_t * src_buf,int pixels,int image_width,int image_height,bool bTransMask) const517 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 
EnableStdConversion(bool bEnabled)539 void CPDF_ColorSpace::EnableStdConversion(bool bEnabled) {
540   if (bEnabled)
541     m_dwStdConversion++;
542   else if (m_dwStdConversion)
543     m_dwStdConversion--;
544 }
545 
CPDF_ColorSpace(CPDF_Document * pDoc,int family)546 CPDF_ColorSpace::CPDF_ColorSpace(CPDF_Document* pDoc, int family)
547     : m_pDocument(pDoc), m_Family(family) {}
548 
~CPDF_ColorSpace()549 CPDF_ColorSpace::~CPDF_ColorSpace() {}
550 
SetComponentsForStockCS(uint32_t nComponents)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 
CPDF_CalGray(CPDF_Document * pDoc)556 CPDF_CalGray::CPDF_CalGray(CPDF_Document* pDoc)
557     : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY) {}
558 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const580 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 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const587 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 
CPDF_CalRGB(CPDF_Document * pDoc)600 CPDF_CalRGB::CPDF_CalRGB(CPDF_Document* pDoc)
601     : CPDF_ColorSpace(pDoc, PDFCS_CALRGB) {}
602 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const638 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 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const665 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 
CPDF_LabCS(CPDF_Document * pDoc)691 CPDF_LabCS::CPDF_LabCS(CPDF_Document* pDoc)
692     : CPDF_ColorSpace(pDoc, PDFCS_LAB) {}
693 
GetDefaultValue(int iComponent,float * value,float * min,float * max) const694 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 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const733 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 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const762 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 
CPDF_ICCBasedCS(CPDF_Document * pDoc)786 CPDF_ICCBasedCS::CPDF_ICCBasedCS(CPDF_Document* pDoc)
787     : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED) {}
788 
~CPDF_ICCBasedCS()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 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const841 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 
EnableStdConversion(bool bEnabled)869 void CPDF_ICCBasedCS::EnableStdConversion(bool bEnabled) {
870   CPDF_ColorSpace::EnableStdConversion(bEnabled);
871   if (m_pAlterCS)
872     m_pAlterCS->EnableStdConversion(bEnabled);
873 }
874 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const875 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 
FindAlternateProfile(CPDF_Document * pDoc,CPDF_Dictionary * pDict,std::set<CPDF_Object * > * pVisited,uint32_t nExpectedComponents)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
GetStockAlternateProfile(uint32_t nComponents)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
IsValidComponents(int32_t nComps)980 bool CPDF_ICCBasedCS::IsValidComponents(int32_t nComps) {
981   return nComps == 1 || nComps == 3 || nComps == 4;
982 }
983 
984 // static
GetRanges(CPDF_Dictionary * pDict,uint32_t nComponents)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 
CPDF_IndexedCS(CPDF_Document * pDoc)1005 CPDF_IndexedCS::CPDF_IndexedCS(CPDF_Document* pDoc)
1006     : CPDF_ColorSpace(pDoc, PDFCS_INDEXED) {}
1007 
~CPDF_IndexedCS()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 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const1064 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 
EnableStdConversion(bool bEnabled)1091 void CPDF_IndexedCS::EnableStdConversion(bool bEnabled) {
1092   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1093   if (m_pBaseCS)
1094     m_pBaseCS->EnableStdConversion(bEnabled);
1095 }
1096 
CPDF_SeparationCS(CPDF_Document * pDoc)1097 CPDF_SeparationCS::CPDF_SeparationCS(CPDF_Document* pDoc)
1098     : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION) {}
1099 
~CPDF_SeparationCS()1100 CPDF_SeparationCS::~CPDF_SeparationCS() {}
1101 
GetDefaultValue(int iComponent,float * value,float * min,float * max) const1102 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 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const1141 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 
EnableStdConversion(bool bEnabled)1174 void CPDF_SeparationCS::EnableStdConversion(bool bEnabled) {
1175   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1176   if (m_pAltCS)
1177     m_pAltCS->EnableStdConversion(bEnabled);
1178 }
1179 
CPDF_DeviceNCS(CPDF_Document * pDoc)1180 CPDF_DeviceNCS::CPDF_DeviceNCS(CPDF_Document* pDoc)
1181     : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN) {}
1182 
~CPDF_DeviceNCS()1183 CPDF_DeviceNCS::~CPDF_DeviceNCS() {}
1184 
GetDefaultValue(int iComponent,float * value,float * min,float * max) const1185 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 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray,std::set<CPDF_Object * > * pVisited)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 
GetRGB(float * pBuf,float * R,float * G,float * B) const1219 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 
EnableStdConversion(bool bEnabled)1232 void CPDF_DeviceNCS::EnableStdConversion(bool bEnabled) {
1233   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1234   if (m_pAltCS) {
1235     m_pAltCS->EnableStdConversion(bEnabled);
1236   }
1237 }
1238