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_stitchfunc.h"
8
9 #include <utility>
10
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
14 #include "core/fxcrt/fx_safe_types.h"
15
16 namespace {
17
18 constexpr uint32_t kRequiredNumInputs = 1;
19
20 } // namespace
21
CPDF_StitchFunc()22 CPDF_StitchFunc::CPDF_StitchFunc() : CPDF_Function(Type::kType3Stitching) {}
23
~CPDF_StitchFunc()24 CPDF_StitchFunc::~CPDF_StitchFunc() {}
25
v_Init(const CPDF_Object * pObj,std::set<const CPDF_Object * > * pVisited)26 bool CPDF_StitchFunc::v_Init(const CPDF_Object* pObj,
27 std::set<const CPDF_Object*>* pVisited) {
28 if (m_nInputs != kRequiredNumInputs)
29 return false;
30
31 const CPDF_Dictionary* pDict = pObj->GetDict();
32 if (!pDict)
33 return false;
34
35 const CPDF_Array* pFunctionsArray = pDict->GetArrayFor("Functions");
36 if (!pFunctionsArray)
37 return false;
38
39 const CPDF_Array* pBoundsArray = pDict->GetArrayFor("Bounds");
40 if (!pBoundsArray)
41 return false;
42
43 const CPDF_Array* pEncodeArray = pDict->GetArrayFor("Encode");
44 if (!pEncodeArray)
45 return false;
46
47 const uint32_t nSubs = pFunctionsArray->size();
48 if (nSubs == 0)
49 return false;
50
51 // Check array sizes. The checks are slightly relaxed to allow the "Bounds"
52 // and "Encode" arrays to have more than the required number of elements.
53 {
54 if (pBoundsArray->size() < nSubs - 1)
55 return false;
56
57 FX_SAFE_UINT32 nExpectedEncodeSize = nSubs;
58 nExpectedEncodeSize *= 2;
59 if (!nExpectedEncodeSize.IsValid())
60 return false;
61
62 if (pEncodeArray->size() < nExpectedEncodeSize.ValueOrDie())
63 return false;
64 }
65
66 // Check sub-functions.
67 {
68 Optional<uint32_t> nOutputs;
69 for (uint32_t i = 0; i < nSubs; ++i) {
70 const CPDF_Object* pSub = pFunctionsArray->GetDirectObjectAt(i);
71 if (pSub == pObj)
72 return false;
73
74 std::unique_ptr<CPDF_Function> pFunc(CPDF_Function::Load(pSub, pVisited));
75 if (!pFunc)
76 return false;
77
78 // Check that the input dimensionality is 1, and that all output
79 // dimensionalities are the same.
80 if (pFunc->CountInputs() != kRequiredNumInputs)
81 return false;
82
83 uint32_t nFuncOutputs = pFunc->CountOutputs();
84 if (nFuncOutputs == 0)
85 return false;
86
87 if (nOutputs) {
88 if (nFuncOutputs != *nOutputs)
89 return false;
90 } else {
91 nOutputs = nFuncOutputs;
92 }
93
94 m_pSubFunctions.push_back(std::move(pFunc));
95 }
96 m_nOutputs = *nOutputs;
97 }
98
99 m_bounds.reserve(nSubs + 1);
100 m_bounds.push_back(m_Domains[0]);
101 for (uint32_t i = 0; i < nSubs - 1; i++)
102 m_bounds.push_back(pBoundsArray->GetNumberAt(i));
103 m_bounds.push_back(m_Domains[1]);
104
105 m_encode = ReadArrayElementsToVector(pEncodeArray, nSubs * 2);
106 return true;
107 }
108
v_Call(const float * inputs,float * results) const109 bool CPDF_StitchFunc::v_Call(const float* inputs, float* results) const {
110 float input = inputs[0];
111 size_t i;
112 for (i = 0; i < m_pSubFunctions.size() - 1; i++) {
113 if (input < m_bounds[i + 1])
114 break;
115 }
116 input = Interpolate(input, m_bounds[i], m_bounds[i + 1], m_encode[i * 2],
117 m_encode[i * 2 + 1]);
118 int nresults;
119 return m_pSubFunctions[i]->Call(&input, kRequiredNumInputs, results,
120 &nresults);
121 }
122