• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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_function.h"
8 
9 #include <vector>
10 
11 #include "core/fpdfapi/page/cpdf_expintfunc.h"
12 #include "core/fpdfapi/page/cpdf_psfunc.h"
13 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
14 #include "core/fpdfapi/page/cpdf_stitchfunc.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "third_party/base/ptr_util.h"
21 #include "third_party/base/stl_util.h"
22 
23 // static
Load(const CPDF_Object * pFuncObj)24 std::unique_ptr<CPDF_Function> CPDF_Function::Load(
25     const CPDF_Object* pFuncObj) {
26   std::set<const CPDF_Object*> visited;
27   return Load(pFuncObj, &visited);
28 }
29 
30 // static
Load(const CPDF_Object * pFuncObj,std::set<const CPDF_Object * > * pVisited)31 std::unique_ptr<CPDF_Function> CPDF_Function::Load(
32     const CPDF_Object* pFuncObj,
33     std::set<const CPDF_Object*>* pVisited) {
34   if (!pFuncObj)
35     return nullptr;
36 
37   if (pdfium::ContainsKey(*pVisited, pFuncObj))
38     return nullptr;
39   pdfium::ScopedSetInsertion<const CPDF_Object*> insertion(pVisited, pFuncObj);
40 
41   int iType = -1;
42   if (const CPDF_Stream* pStream = pFuncObj->AsStream())
43     iType = pStream->GetDict()->GetIntegerFor("FunctionType");
44   else if (const CPDF_Dictionary* pDict = pFuncObj->AsDictionary())
45     iType = pDict->GetIntegerFor("FunctionType");
46 
47   std::unique_ptr<CPDF_Function> pFunc;
48   Type type = IntegerToFunctionType(iType);
49   if (type == Type::kType0Sampled)
50     pFunc = pdfium::MakeUnique<CPDF_SampledFunc>();
51   else if (type == Type::kType2ExpotentialInterpolation)
52     pFunc = pdfium::MakeUnique<CPDF_ExpIntFunc>();
53   else if (type == Type::kType3Stitching)
54     pFunc = pdfium::MakeUnique<CPDF_StitchFunc>();
55   else if (type == Type::kType4PostScript)
56     pFunc = pdfium::MakeUnique<CPDF_PSFunc>();
57 
58   if (!pFunc || !pFunc->Init(pFuncObj, pVisited))
59     return nullptr;
60 
61   return pFunc;
62 }
63 
64 // static
IntegerToFunctionType(int iType)65 CPDF_Function::Type CPDF_Function::IntegerToFunctionType(int iType) {
66   switch (iType) {
67     case 0:
68     case 2:
69     case 3:
70     case 4:
71       return static_cast<Type>(iType);
72     default:
73       return Type::kTypeInvalid;
74   }
75 }
76 
CPDF_Function(Type type)77 CPDF_Function::CPDF_Function(Type type) : m_Type(type) {}
78 
79 CPDF_Function::~CPDF_Function() = default;
80 
Init(const CPDF_Object * pObj,std::set<const CPDF_Object * > * pVisited)81 bool CPDF_Function::Init(const CPDF_Object* pObj,
82                          std::set<const CPDF_Object*>* pVisited) {
83   const CPDF_Stream* pStream = pObj->AsStream();
84   const CPDF_Dictionary* pDict =
85       pStream ? pStream->GetDict() : pObj->AsDictionary();
86 
87   const CPDF_Array* pDomains = pDict->GetArrayFor("Domain");
88   if (!pDomains)
89     return false;
90 
91   m_nInputs = pDomains->size() / 2;
92   if (m_nInputs == 0)
93     return false;
94 
95   size_t nInputs = m_nInputs * 2;
96   m_Domains = ReadArrayElementsToVector(pDomains, nInputs);
97 
98   const CPDF_Array* pRanges = pDict->GetArrayFor("Range");
99   m_nOutputs = pRanges ? pRanges->size() / 2 : 0;
100 
101   // Ranges are required for type 0 and type 4 functions. A non-zero
102   // |m_nOutputs| here implied Ranges meets the requirements.
103   bool bRangeRequired =
104       m_Type == Type::kType0Sampled || m_Type == Type::kType4PostScript;
105   if (bRangeRequired && m_nOutputs == 0)
106     return false;
107 
108   if (m_nOutputs > 0) {
109     size_t nOutputs = m_nOutputs * 2;
110     m_Ranges = ReadArrayElementsToVector(pRanges, nOutputs);
111   }
112 
113   uint32_t old_outputs = m_nOutputs;
114   if (!v_Init(pObj, pVisited))
115     return false;
116 
117   if (!m_Ranges.empty() && m_nOutputs > old_outputs) {
118     FX_SAFE_SIZE_T nOutputs = m_nOutputs;
119     nOutputs *= 2;
120     m_Ranges.resize(nOutputs.ValueOrDie());
121   }
122   return true;
123 }
124 
Call(const float * inputs,uint32_t ninputs,float * results,int * nresults) const125 bool CPDF_Function::Call(const float* inputs,
126                          uint32_t ninputs,
127                          float* results,
128                          int* nresults) const {
129   if (m_nInputs != ninputs)
130     return false;
131 
132   *nresults = m_nOutputs;
133   std::vector<float> clamped_inputs(m_nInputs);
134   for (uint32_t i = 0; i < m_nInputs; i++) {
135     clamped_inputs[i] =
136         pdfium::clamp(inputs[i], m_Domains[i * 2], m_Domains[i * 2 + 1]);
137   }
138   if (!v_Call(clamped_inputs.data(), results))
139     return false;
140 
141   if (m_Ranges.empty())
142     return true;
143 
144   for (uint32_t i = 0; i < m_nOutputs; i++) {
145     results[i] =
146         pdfium::clamp(results[i], m_Ranges[i * 2], m_Ranges[i * 2 + 1]);
147   }
148   return true;
149 }
150 
151 // See PDF Reference 1.7, page 170.
Interpolate(float x,float xmin,float xmax,float ymin,float ymax) const152 float CPDF_Function::Interpolate(float x,
153                                  float xmin,
154                                  float xmax,
155                                  float ymin,
156                                  float ymax) const {
157   float divisor = xmax - xmin;
158   return ymin + (divisor ? (x - xmin) * (ymax - ymin) / divisor : 0);
159 }
160 
ToSampledFunc() const161 const CPDF_SampledFunc* CPDF_Function::ToSampledFunc() const {
162   return m_Type == Type::kType0Sampled
163              ? static_cast<const CPDF_SampledFunc*>(this)
164              : nullptr;
165 }
166 
ToExpIntFunc() const167 const CPDF_ExpIntFunc* CPDF_Function::ToExpIntFunc() const {
168   return m_Type == Type::kType2ExpotentialInterpolation
169              ? static_cast<const CPDF_ExpIntFunc*>(this)
170              : nullptr;
171 }
172 
ToStitchFunc() const173 const CPDF_StitchFunc* CPDF_Function::ToStitchFunc() const {
174   return m_Type == Type::kType3Stitching
175              ? static_cast<const CPDF_StitchFunc*>(this)
176              : nullptr;
177 }
178