Home | History | Annotate | Download | only in page
      1 // Copyright 2016 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_shadingpattern.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fpdfapi/page/cpdf_docpagedata.h"
     12 #include "core/fpdfapi/page/cpdf_function.h"
     13 #include "core/fpdfapi/parser/cpdf_array.h"
     14 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     15 #include "core/fpdfapi/parser/cpdf_document.h"
     16 #include "core/fpdfapi/parser/cpdf_object.h"
     17 #include "core/fpdfapi/parser/cpdf_stream.h"
     18 
     19 namespace {
     20 
     21 ShadingType ToShadingType(int type) {
     22   return (type > static_cast<int>(kInvalidShading) &&
     23           type < static_cast<int>(kMaxShading))
     24              ? static_cast<ShadingType>(type)
     25              : kInvalidShading;
     26 }
     27 
     28 }  // namespace
     29 
     30 CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc,
     31                                          CPDF_Object* pPatternObj,
     32                                          bool bShading,
     33                                          const CFX_Matrix& parentMatrix)
     34     : CPDF_Pattern(pDoc, bShading ? nullptr : pPatternObj, parentMatrix),
     35       m_ShadingType(kInvalidShading),
     36       m_bShadingObj(bShading),
     37       m_pShadingObj(pPatternObj),
     38       m_pCS(nullptr),
     39       m_pCountedCS(nullptr) {
     40   assert(document());
     41   if (!bShading) {
     42     m_pShadingObj = pattern_obj()->GetDict()->GetDirectObjectFor("Shading");
     43     SetPatternToFormMatrix();
     44   }
     45 }
     46 
     47 CPDF_ShadingPattern::~CPDF_ShadingPattern() {
     48   CPDF_ColorSpace* pCountedCS = m_pCountedCS ? m_pCountedCS->get() : nullptr;
     49   if (pCountedCS) {
     50     auto* pPageData = document()->GetPageData();
     51     if (pPageData) {
     52       m_pCS.Release();  // Give up unowned reference first.
     53       pPageData->ReleaseColorSpace(pCountedCS->GetArray());
     54     }
     55   }
     56 }
     57 
     58 CPDF_TilingPattern* CPDF_ShadingPattern::AsTilingPattern() {
     59   return nullptr;
     60 }
     61 
     62 CPDF_ShadingPattern* CPDF_ShadingPattern::AsShadingPattern() {
     63   return this;
     64 }
     65 
     66 bool CPDF_ShadingPattern::Load() {
     67   if (m_ShadingType != kInvalidShading)
     68     return true;
     69 
     70   CPDF_Dictionary* pShadingDict =
     71       m_pShadingObj ? m_pShadingObj->GetDict() : nullptr;
     72   if (!pShadingDict)
     73     return false;
     74 
     75   m_pFunctions.clear();
     76   CPDF_Object* pFunc = pShadingDict->GetDirectObjectFor("Function");
     77   if (pFunc) {
     78     if (CPDF_Array* pArray = pFunc->AsArray()) {
     79       m_pFunctions.resize(std::min<size_t>(pArray->GetCount(), 4));
     80       for (size_t i = 0; i < m_pFunctions.size(); ++i)
     81         m_pFunctions[i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
     82     } else {
     83       m_pFunctions.push_back(CPDF_Function::Load(pFunc));
     84     }
     85   }
     86   CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace");
     87   if (!pCSObj)
     88     return false;
     89 
     90   CPDF_DocPageData* pDocPageData = document()->GetPageData();
     91   m_pCS = pDocPageData->GetColorSpace(pCSObj, nullptr);
     92 
     93   // The color space is required and cannot be a Pattern space, according to the
     94   // PDF 1.7 spec, page 305.
     95   if (!m_pCS || m_pCS->GetFamily() == PDFCS_PATTERN)
     96     return false;
     97 
     98   m_pCountedCS = pDocPageData->FindColorSpacePtr(m_pCS->GetArray());
     99 
    100   m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType"));
    101 
    102   return Validate();
    103 }
    104 
    105 bool CPDF_ShadingPattern::Validate() const {
    106   if (m_ShadingType == kInvalidShading)
    107     return false;
    108 
    109   // We expect to have a stream if our shading type is a mesh.
    110   if (IsMeshShading() && !ToStream(m_pShadingObj.Get()))
    111     return false;
    112 
    113   // Validate color space
    114   switch (m_ShadingType) {
    115     case kFunctionBasedShading:
    116     case kAxialShading:
    117     case kRadialShading: {
    118       if (m_pCS->GetFamily() == PDFCS_INDEXED)
    119         return false;
    120       break;
    121     }
    122     case kFreeFormGouraudTriangleMeshShading:
    123     case kLatticeFormGouraudTriangleMeshShading:
    124     case kCoonsPatchMeshShading:
    125     case kTensorProductPatchMeshShading: {
    126       if (!m_pFunctions.empty() && m_pCS->GetFamily() == PDFCS_INDEXED)
    127         return false;
    128       break;
    129     }
    130     default: {
    131       NOTREACHED();
    132       return false;
    133     }
    134   }
    135 
    136   uint32_t nNumColorSpaceComponents = m_pCS->CountComponents();
    137   switch (m_ShadingType) {
    138     case kFunctionBasedShading: {
    139       // Either one 2-to-N function or N 2-to-1 functions.
    140       if (!ValidateFunctions(1, 2, nNumColorSpaceComponents) &&
    141           !ValidateFunctions(nNumColorSpaceComponents, 2, 1)) {
    142         return false;
    143       }
    144       break;
    145     }
    146     case kAxialShading:
    147     case kRadialShading: {
    148       // Either one 1-to-N function or N 1-to-1 functions.
    149       if (!ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
    150           !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
    151         return false;
    152       }
    153       break;
    154     }
    155     case kFreeFormGouraudTriangleMeshShading:
    156     case kLatticeFormGouraudTriangleMeshShading:
    157     case kCoonsPatchMeshShading:
    158     case kTensorProductPatchMeshShading: {
    159       // Either no function, one 1-to-N function, or N 1-to-1 functions.
    160       if (!m_pFunctions.empty() &&
    161           !ValidateFunctions(1, 1, nNumColorSpaceComponents) &&
    162           !ValidateFunctions(nNumColorSpaceComponents, 1, 1)) {
    163         return false;
    164       }
    165       break;
    166     }
    167     default: {
    168       NOTREACHED();
    169       return false;
    170     }
    171   }
    172   return true;
    173 }
    174 
    175 bool CPDF_ShadingPattern::ValidateFunctions(
    176     uint32_t nExpectedNumFunctions,
    177     uint32_t nExpectedNumInputs,
    178     uint32_t nExpectedNumOutputs) const {
    179   if (m_pFunctions.size() != nExpectedNumFunctions)
    180     return false;
    181 
    182   pdfium::base::CheckedNumeric<uint32_t> nTotalOutputs = 0;
    183   for (const auto& function : m_pFunctions) {
    184     if (!function)
    185       return false;
    186 
    187     if (function->CountInputs() != nExpectedNumInputs ||
    188         function->CountOutputs() != nExpectedNumOutputs) {
    189       return false;
    190     }
    191 
    192     nTotalOutputs += function->CountOutputs();
    193   }
    194 
    195   return nTotalOutputs.IsValid();
    196 }
    197