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 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 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 59 CPDF_Function::CPDF_Function(Type type) 60 : m_pDomains(nullptr), m_pRanges(nullptr), m_Type(type) {} 61 62 CPDF_Function::~CPDF_Function() { 63 FX_Free(m_pDomains); 64 FX_Free(m_pRanges); 65 } 66 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 104 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. 128 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 137 const CPDF_SampledFunc* CPDF_Function::ToSampledFunc() const { 138 return m_Type == Type::kType0Sampled 139 ? static_cast<const CPDF_SampledFunc*>(this) 140 : nullptr; 141 } 142 143 const CPDF_ExpIntFunc* CPDF_Function::ToExpIntFunc() const { 144 return m_Type == Type::kType2ExpotentialInterpolation 145 ? static_cast<const CPDF_ExpIntFunc*>(this) 146 : nullptr; 147 } 148 149 const CPDF_StitchFunc* CPDF_Function::ToStitchFunc() const { 150 return m_Type == Type::kType3Stitching 151 ? static_cast<const CPDF_StitchFunc*>(this) 152 : nullptr; 153 } 154