• 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 "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