xref: /aosp_15_r20/external/pdfium/core/fpdfapi/page/cpdf_shadingpattern.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2016 The PDFium Authors
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_shadingpattern.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fpdfapi/page/cpdf_docpagedata.h"
13 #include "core/fpdfapi/page/cpdf_function.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_document.h"
17 #include "core/fpdfapi/parser/cpdf_object.h"
18 #include "core/fpdfapi/parser/cpdf_stream.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "third_party/base/check.h"
21 #include "third_party/base/notreached.h"
22 
23 namespace {
24 
ToShadingType(int type)25 ShadingType ToShadingType(int type) {
26   return (type > kInvalidShading && type < kMaxShading)
27              ? static_cast<ShadingType>(type)
28              : kInvalidShading;
29 }
30 
31 }  // namespace
32 
CPDF_ShadingPattern(CPDF_Document * pDoc,RetainPtr<CPDF_Object> pPatternObj,bool bShading,const CFX_Matrix & parentMatrix)33 CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc,
34                                          RetainPtr<CPDF_Object> pPatternObj,
35                                          bool bShading,
36                                          const CFX_Matrix& parentMatrix)
37     : CPDF_Pattern(pDoc, std::move(pPatternObj), parentMatrix),
38       m_bShading(bShading) {
39   DCHECK(document());
40   if (!bShading)
41     SetPatternToFormMatrix();
42 }
43 
44 CPDF_ShadingPattern::~CPDF_ShadingPattern() = default;
45 
AsShadingPattern()46 CPDF_ShadingPattern* CPDF_ShadingPattern::AsShadingPattern() {
47   return this;
48 }
49 
Load()50 bool CPDF_ShadingPattern::Load() {
51   if (m_ShadingType != kInvalidShading)
52     return true;
53 
54   RetainPtr<const CPDF_Object> pShadingObj = GetShadingObject();
55   RetainPtr<const CPDF_Dictionary> pShadingDict =
56       pShadingObj ? pShadingObj->GetDict() : nullptr;
57   if (!pShadingDict)
58     return false;
59 
60   m_pFunctions.clear();
61   RetainPtr<const CPDF_Object> pFunc =
62       pShadingDict->GetDirectObjectFor("Function");
63   if (pFunc) {
64     if (const CPDF_Array* pArray = pFunc->AsArray()) {
65       m_pFunctions.resize(std::min<size_t>(pArray->size(), 4));
66       for (size_t i = 0; i < m_pFunctions.size(); ++i) {
67         m_pFunctions[i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
68       }
69     } else {
70       m_pFunctions.push_back(CPDF_Function::Load(std::move(pFunc)));
71     }
72   }
73   RetainPtr<const CPDF_Object> pCSObj =
74       pShadingDict->GetDirectObjectFor("ColorSpace");
75   if (!pCSObj)
76     return false;
77 
78   auto* pDocPageData = CPDF_DocPageData::FromDocument(document());
79   m_pCS = pDocPageData->GetColorSpace(pCSObj.Get(), nullptr);
80 
81   // The color space is required and cannot be a Pattern space, according to the
82   // PDF 1.7 spec, page 305.
83   if (!m_pCS || m_pCS->GetFamily() == CPDF_ColorSpace::Family::kPattern)
84     return false;
85 
86   m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType"));
87   return Validate();
88 }
89 
GetShadingObject() const90 RetainPtr<const CPDF_Object> CPDF_ShadingPattern::GetShadingObject() const {
91   return m_bShading ? pattern_obj()
92                     : pattern_obj()->GetDict()->GetDirectObjectFor("Shading");
93 }
94 
Validate() const95 bool CPDF_ShadingPattern::Validate() const {
96   if (m_ShadingType == kInvalidShading)
97     return false;
98 
99   // We expect to have a stream if our shading type is a mesh.
100   if (IsMeshShading() && !ToStream(GetShadingObject()))
101     return false;
102 
103   // Validate color space
104   switch (m_ShadingType) {
105     case kFunctionBasedShading:
106     case kAxialShading:
107     case kRadialShading: {
108       if (m_pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed)
109         return false;
110       break;
111     }
112     case kFreeFormGouraudTriangleMeshShading:
113     case kLatticeFormGouraudTriangleMeshShading:
114     case kCoonsPatchMeshShading:
115     case kTensorProductPatchMeshShading: {
116       if (!m_pFunctions.empty() &&
117           m_pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed) {
118         return false;
119       }
120       break;
121     }
122     default: {
123       NOTREACHED_NORETURN();
124     }
125   }
126 
127   uint32_t nNumColorSpaceComponents = m_pCS->CountComponents();
128   switch (m_ShadingType) {
129     case kFunctionBasedShading: {
130       // Either one 2-to-N function or N 2-to-1 functions.
131       return ValidateFunctions(1, 2, nNumColorSpaceComponents) ||
132              ValidateFunctions(nNumColorSpaceComponents, 2, 1);
133     }
134     case kAxialShading:
135     case kRadialShading: {
136       // Either one 1-to-N function or N 1-to-1 functions.
137       return ValidateFunctions(1, 1, nNumColorSpaceComponents) ||
138              ValidateFunctions(nNumColorSpaceComponents, 1, 1);
139     }
140     case kFreeFormGouraudTriangleMeshShading:
141     case kLatticeFormGouraudTriangleMeshShading:
142     case kCoonsPatchMeshShading:
143     case kTensorProductPatchMeshShading: {
144       // Either no function, one 1-to-N function, or N 1-to-1 functions.
145       return m_pFunctions.empty() ||
146              ValidateFunctions(1, 1, nNumColorSpaceComponents) ||
147              ValidateFunctions(nNumColorSpaceComponents, 1, 1);
148     }
149     default:
150       NOTREACHED_NORETURN();
151   }
152 }
153 
ValidateFunctions(uint32_t nExpectedNumFunctions,uint32_t nExpectedNumInputs,uint32_t nExpectedNumOutputs) const154 bool CPDF_ShadingPattern::ValidateFunctions(
155     uint32_t nExpectedNumFunctions,
156     uint32_t nExpectedNumInputs,
157     uint32_t nExpectedNumOutputs) const {
158   if (m_pFunctions.size() != nExpectedNumFunctions)
159     return false;
160 
161   FX_SAFE_UINT32 nTotalOutputs = 0;
162   for (const auto& function : m_pFunctions) {
163     if (!function)
164       return false;
165 
166     if (function->CountInputs() != nExpectedNumInputs ||
167         function->CountOutputs() != nExpectedNumOutputs) {
168       return false;
169     }
170 
171     nTotalOutputs += function->CountOutputs();
172   }
173 
174   return nTotalOutputs.IsValid();
175 }
176