Home | History | Annotate | Download | only in page
      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