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_shadingpattern.h"
8
9 #include <algorithm>
10
11 #include "core/fpdfapi/page/cpdf_docpagedata.h"
12 #include "core/fpdfapi/page/cpdf_function.h"
13 #include "core/fpdfapi/parser/cpdf_array.h"
14 #include "core/fpdfapi/parser/cpdf_dictionary.h"
15 #include "core/fpdfapi/parser/cpdf_document.h"
16 #include "core/fpdfapi/parser/cpdf_object.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18
19 namespace {
20
ToShadingType(int type)21 ShadingType ToShadingType(int type) {
22 return (type > static_cast<int>(kInvalidShading) &&
23 type < static_cast<int>(kMaxShading))
24 ? static_cast<ShadingType>(type)
25 : kInvalidShading;
26 }
27
28 } // namespace
29
CPDF_ShadingPattern(CPDF_Document * pDoc,CPDF_Object * pPatternObj,bool bShading,const CFX_Matrix & parentMatrix)30 CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc,
31 CPDF_Object* pPatternObj,
32 bool bShading,
33 const CFX_Matrix& parentMatrix)
34 : CPDF_Pattern(pDoc, bShading ? nullptr : pPatternObj, parentMatrix),
35 m_ShadingType(kInvalidShading),
36 m_bShadingObj(bShading),
37 m_pShadingObj(pPatternObj),
38 m_pCS(nullptr),
39 m_pCountedCS(nullptr) {
40 assert(document());
41 if (!bShading) {
42 m_pShadingObj = pattern_obj()->GetDict()->GetDirectObjectFor("Shading");
43 SetPatternToFormMatrix();
44 }
45 }
46
~CPDF_ShadingPattern()47 CPDF_ShadingPattern::~CPDF_ShadingPattern() {
48 CPDF_ColorSpace* pCountedCS = m_pCountedCS ? m_pCountedCS->get() : nullptr;
49 if (pCountedCS) {
50 auto* pPageData = document()->GetPageData();
51 if (pPageData) {
52 m_pCS.Release(); // Give up unowned reference first.
53 pPageData->ReleaseColorSpace(pCountedCS->GetArray());
54 }
55 }
56 }
57
AsTilingPattern()58 CPDF_TilingPattern* CPDF_ShadingPattern::AsTilingPattern() {
59 return nullptr;
60 }
61
AsShadingPattern()62 CPDF_ShadingPattern* CPDF_ShadingPattern::AsShadingPattern() {
63 return this;
64 }
65
Load()66 bool CPDF_ShadingPattern::Load() {
67 if (m_ShadingType != kInvalidShading)
68 return true;
69
70 CPDF_Dictionary* pShadingDict =
71 m_pShadingObj ? m_pShadingObj->GetDict() : nullptr;
72 if (!pShadingDict)
73 return false;
74
75 m_pFunctions.clear();
76 CPDF_Object* pFunc = pShadingDict->GetDirectObjectFor("Function");
77 if (pFunc) {
78 if (CPDF_Array* pArray = pFunc->AsArray()) {
79 m_pFunctions.resize(std::min<size_t>(pArray->GetCount(), 4));
80 for (size_t i = 0; i < m_pFunctions.size(); ++i)
81 m_pFunctions[i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
82 } else {
83 m_pFunctions.push_back(CPDF_Function::Load(pFunc));
84 }
85 }
86 CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace");
87 if (!pCSObj)
88 return false;
89
90 CPDF_DocPageData* pDocPageData = document()->GetPageData();
91 m_pCS = pDocPageData->GetColorSpace(pCSObj, nullptr);
92
93 // The color space is required and cannot be a Pattern space, according to the
94 // PDF 1.7 spec, page 305.
95 if (!m_pCS || m_pCS->GetFamily() == PDFCS_PATTERN)
96 return false;
97
98 m_pCountedCS = pDocPageData->FindColorSpacePtr(m_pCS->GetArray());
99
100 m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType"));
101
102 return Validate();
103 }
104
Validate() const105 bool CPDF_ShadingPattern::Validate() const {
106 if (m_ShadingType == kInvalidShading)
107 return false;
108
109 // We expect to have a stream if our shading type is a mesh.
110 if (IsMeshShading() && !ToStream(m_pShadingObj.Get()))
111 return false;
112
113 // Validate color space
114 switch (m_ShadingType) {
115 case kFunctionBasedShading:
116 case kAxialShading:
117 case kRadialShading: {
118 if (m_pCS->GetFamily() == PDFCS_INDEXED)
119 return false;
120 break;
121 }
122 case kFreeFormGouraudTriangleMeshShading:
123 case kLatticeFormGouraudTriangleMeshShading:
124 case kCoonsPatchMeshShading:
125 case kTensorProductPatchMeshShading: {
126 if (!m_pFunctions.empty() && m_pCS->GetFamily() == PDFCS_INDEXED)
127 return false;
128 break;
129 }
130 default: {
131 NOTREACHED();
132 return false;
133 }
134 }
135
136 uint32_t nNumColorSpaceComponents = m_pCS->CountComponents();
137 switch (m_ShadingType) {
138 case kFunctionBasedShading: {
139 // Either one 2-to-N function or N 2-to-1 functions.
140 if (!ValidateFunctions(1, 2, nNumColorSpaceComponents) &&
141 !ValidateFunctions(nNumColorSpaceComponents, 2, 1)) {
142 return false;
143 }
144 break;
145 }
146 case kAxialShading:
147 case kRadialShading: {
148 // Either one 1-to-N function or N 1-to-1 functions.
149 if (!ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
150 !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
151 return false;
152 }
153 break;
154 }
155 case kFreeFormGouraudTriangleMeshShading:
156 case kLatticeFormGouraudTriangleMeshShading:
157 case kCoonsPatchMeshShading:
158 case kTensorProductPatchMeshShading: {
159 // Either no function, one 1-to-N function, or N 1-to-1 functions.
160 if (!m_pFunctions.empty() &&
161 !ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
162 !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
163 return false;
164 }
165 break;
166 }
167 default: {
168 NOTREACHED();
169 return false;
170 }
171 }
172 return true;
173 }
174
ValidateFunctions(uint32_t nExpectedNumFunctions,uint32_t nExpectedNumInputs,uint32_t nExpectedNumOutputs) const175 bool CPDF_ShadingPattern::ValidateFunctions(
176 uint32_t nExpectedNumFunctions,
177 uint32_t nExpectedNumInputs,
178 uint32_t nExpectedNumOutputs) const {
179 if (m_pFunctions.size() != nExpectedNumFunctions)
180 return false;
181
182 pdfium::base::CheckedNumeric<uint32_t> nTotalOutputs = 0;
183 for (const auto& function : m_pFunctions) {
184 if (!function)
185 return false;
186
187 if (function->CountInputs() != nExpectedNumInputs ||
188 function->CountOutputs() != nExpectedNumOutputs) {
189 return false;
190 }
191
192 nTotalOutputs += function->CountOutputs();
193 }
194
195 return nTotalOutputs.IsValid();
196 }
197