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 "core/fpdfapi/page/cpdf_expintfunc.h"
10 #include "core/fpdfapi/page/cpdf_psfunc.h"
11 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
12 #include "core/fpdfapi/page/cpdf_stitchfunc.h"
13 #include "core/fpdfapi/parser/cpdf_array.h"
14 #include "core/fpdfapi/parser/cpdf_dictionary.h"
15 #include "core/fpdfapi/parser/cpdf_stream.h"
16 #include "third_party/base/ptr_util.h"
17
18 // static
Load(CPDF_Object * pFuncObj)19 std::unique_ptr<CPDF_Function> CPDF_Function::Load(CPDF_Object* pFuncObj) {
20 std::unique_ptr<CPDF_Function> pFunc;
21 if (!pFuncObj)
22 return pFunc;
23
24 int iType = -1;
25 if (CPDF_Stream* pStream = pFuncObj->AsStream())
26 iType = pStream->GetDict()->GetIntegerFor("FunctionType");
27 else if (CPDF_Dictionary* pDict = pFuncObj->AsDictionary())
28 iType = pDict->GetIntegerFor("FunctionType");
29
30 Type type = IntegerToFunctionType(iType);
31 if (type == Type::kType0Sampled)
32 pFunc = pdfium::MakeUnique<CPDF_SampledFunc>();
33 else if (type == Type::kType2ExpotentialInterpolation)
34 pFunc = pdfium::MakeUnique<CPDF_ExpIntFunc>();
35 else if (type == Type::kType3Stitching)
36 pFunc = pdfium::MakeUnique<CPDF_StitchFunc>();
37 else if (type == Type::kType4PostScript)
38 pFunc = pdfium::MakeUnique<CPDF_PSFunc>();
39
40 if (!pFunc || !pFunc->Init(pFuncObj))
41 return nullptr;
42
43 return pFunc;
44 }
45
46 // static
IntegerToFunctionType(int iType)47 CPDF_Function::Type CPDF_Function::IntegerToFunctionType(int iType) {
48 switch (iType) {
49 case 0:
50 case 2:
51 case 3:
52 case 4:
53 return static_cast<Type>(iType);
54 default:
55 return Type::kTypeInvalid;
56 }
57 }
58
CPDF_Function(Type type)59 CPDF_Function::CPDF_Function(Type type)
60 : m_pDomains(nullptr), m_pRanges(nullptr), m_Type(type) {}
61
~CPDF_Function()62 CPDF_Function::~CPDF_Function() {
63 FX_Free(m_pDomains);
64 FX_Free(m_pRanges);
65 }
66
Init(CPDF_Object * pObj)67 bool CPDF_Function::Init(CPDF_Object* pObj) {
68 CPDF_Stream* pStream = pObj->AsStream();
69 CPDF_Dictionary* pDict = pStream ? pStream->GetDict() : pObj->AsDictionary();
70
71 CPDF_Array* pDomains = pDict->GetArrayFor("Domain");
72 if (!pDomains)
73 return false;
74
75 m_nInputs = pDomains->GetCount() / 2;
76 if (m_nInputs == 0)
77 return false;
78
79 m_pDomains = FX_Alloc2D(float, m_nInputs, 2);
80 for (uint32_t i = 0; i < m_nInputs * 2; i++) {
81 m_pDomains[i] = pDomains->GetFloatAt(i);
82 }
83 CPDF_Array* pRanges = pDict->GetArrayFor("Range");
84 m_nOutputs = 0;
85 if (pRanges) {
86 m_nOutputs = pRanges->GetCount() / 2;
87 m_pRanges = FX_Alloc2D(float, m_nOutputs, 2);
88 for (uint32_t i = 0; i < m_nOutputs * 2; i++)
89 m_pRanges[i] = pRanges->GetFloatAt(i);
90 }
91 uint32_t old_outputs = m_nOutputs;
92 if (!v_Init(pObj))
93 return false;
94 if (m_pRanges && m_nOutputs > old_outputs) {
95 m_pRanges = FX_Realloc(float, m_pRanges, m_nOutputs * 2);
96 if (m_pRanges) {
97 memset(m_pRanges + (old_outputs * 2), 0,
98 sizeof(float) * (m_nOutputs - old_outputs) * 2);
99 }
100 }
101 return true;
102 }
103
Call(float * inputs,uint32_t ninputs,float * results,int * nresults) const104 bool CPDF_Function::Call(float* inputs,
105 uint32_t ninputs,
106 float* results,
107 int* nresults) const {
108 if (m_nInputs != ninputs)
109 return false;
110
111 *nresults = m_nOutputs;
112 for (uint32_t i = 0; i < m_nInputs; i++) {
113 inputs[i] =
114 pdfium::clamp(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1]);
115 }
116 v_Call(inputs, results);
117 if (!m_pRanges)
118 return true;
119
120 for (uint32_t i = 0; i < m_nOutputs; i++) {
121 results[i] =
122 pdfium::clamp(results[i], m_pRanges[i * 2], m_pRanges[i * 2 + 1]);
123 }
124 return true;
125 }
126
127 // See PDF Reference 1.7, page 170.
Interpolate(float x,float xmin,float xmax,float ymin,float ymax) const128 float CPDF_Function::Interpolate(float x,
129 float xmin,
130 float xmax,
131 float ymin,
132 float ymax) const {
133 float divisor = xmax - xmin;
134 return ymin + (divisor ? (x - xmin) * (ymax - ymin) / divisor : 0);
135 }
136
ToSampledFunc() const137 const CPDF_SampledFunc* CPDF_Function::ToSampledFunc() const {
138 return m_Type == Type::kType0Sampled
139 ? static_cast<const CPDF_SampledFunc*>(this)
140 : nullptr;
141 }
142
ToExpIntFunc() const143 const CPDF_ExpIntFunc* CPDF_Function::ToExpIntFunc() const {
144 return m_Type == Type::kType2ExpotentialInterpolation
145 ? static_cast<const CPDF_ExpIntFunc*>(this)
146 : nullptr;
147 }
148
ToStitchFunc() const149 const CPDF_StitchFunc* CPDF_Function::ToStitchFunc() const {
150 return m_Type == Type::kType3Stitching
151 ? static_cast<const CPDF_StitchFunc*>(this)
152 : nullptr;
153 }
154