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_meshstream.h"
      8 
      9 #include "core/fpdfapi/page/cpdf_colorspace.h"
     10 #include "core/fpdfapi/page/cpdf_function.h"
     11 #include "core/fpdfapi/parser/cpdf_array.h"
     12 
     13 namespace {
     14 
     15 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.33 and 4.34)
     16 bool ShouldCheckBPC(ShadingType type) {
     17   switch (type) {
     18     case kFreeFormGouraudTriangleMeshShading:
     19     case kLatticeFormGouraudTriangleMeshShading:
     20     case kCoonsPatchMeshShading:
     21     case kTensorProductPatchMeshShading:
     22       return true;
     23     default:
     24       return false;
     25   }
     26 }
     27 
     28 // Same references as ShouldCheckBPC() above.
     29 bool IsValidBitsPerComponent(uint32_t x) {
     30   switch (x) {
     31     case 1:
     32     case 2:
     33     case 4:
     34     case 8:
     35     case 12:
     36     case 16:
     37       return true;
     38     default:
     39       return false;
     40   }
     41 }
     42 
     43 // Same references as ShouldCheckBPC() above.
     44 bool IsValidBitsPerCoordinate(uint32_t x) {
     45   switch (x) {
     46     case 1:
     47     case 2:
     48     case 4:
     49     case 8:
     50     case 12:
     51     case 16:
     52     case 24:
     53     case 32:
     54       return true;
     55     default:
     56       return false;
     57   }
     58 }
     59 
     60 // See PDF Reference 1.7, page 315, table 4.32. (Also table 4.34)
     61 bool ShouldCheckBitsPerFlag(ShadingType type) {
     62   switch (type) {
     63     case kFreeFormGouraudTriangleMeshShading:
     64     case kCoonsPatchMeshShading:
     65     case kTensorProductPatchMeshShading:
     66       return true;
     67     default:
     68       return false;
     69   }
     70 }
     71 
     72 // Same references as ShouldCheckBitsPerFlag() above.
     73 bool IsValidBitsPerFlag(uint32_t x) {
     74   switch (x) {
     75     case 2:
     76     case 4:
     77     case 8:
     78       return true;
     79     default:
     80       return false;
     81   }
     82 }
     83 
     84 }  // namespace
     85 
     86 CPDF_MeshVertex::CPDF_MeshVertex() = default;
     87 
     88 CPDF_MeshVertex::CPDF_MeshVertex(const CPDF_MeshVertex&) = default;
     89 
     90 CPDF_MeshVertex::~CPDF_MeshVertex() = default;
     91 
     92 CPDF_MeshStream::CPDF_MeshStream(
     93     ShadingType type,
     94     const std::vector<std::unique_ptr<CPDF_Function>>& funcs,
     95     CPDF_Stream* pShadingStream,
     96     CPDF_ColorSpace* pCS)
     97     : m_type(type),
     98       m_funcs(funcs),
     99       m_pShadingStream(pShadingStream),
    100       m_pCS(pCS),
    101       m_nCoordBits(0),
    102       m_nComponentBits(0),
    103       m_nFlagBits(0),
    104       m_nComponents(0),
    105       m_CoordMax(0),
    106       m_ComponentMax(0),
    107       m_xmin(0),
    108       m_xmax(0),
    109       m_ymin(0),
    110       m_ymax(0),
    111       m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(pShadingStream)) {
    112   memset(&m_ColorMin, 0, sizeof(m_ColorMin));
    113   memset(&m_ColorMax, 0, sizeof(m_ColorMax));
    114 }
    115 
    116 CPDF_MeshStream::~CPDF_MeshStream() {}
    117 
    118 bool CPDF_MeshStream::Load() {
    119   m_pStream->LoadAllDataFiltered();
    120   m_BitStream = pdfium::MakeUnique<CFX_BitStream>(m_pStream->GetData(),
    121                                                   m_pStream->GetSize());
    122   CPDF_Dictionary* pDict = m_pShadingStream->GetDict();
    123   m_nCoordBits = pDict->GetIntegerFor("BitsPerCoordinate");
    124   m_nComponentBits = pDict->GetIntegerFor("BitsPerComponent");
    125   if (ShouldCheckBPC(m_type)) {
    126     if (!IsValidBitsPerCoordinate(m_nCoordBits))
    127       return false;
    128     if (!IsValidBitsPerComponent(m_nComponentBits))
    129       return false;
    130   }
    131 
    132   m_nFlagBits = pDict->GetIntegerFor("BitsPerFlag");
    133   if (ShouldCheckBitsPerFlag(m_type) && !IsValidBitsPerFlag(m_nFlagBits))
    134     return false;
    135 
    136   uint32_t nComponents = m_pCS->CountComponents();
    137   if (nComponents > kMaxComponents)
    138     return false;
    139 
    140   m_nComponents = m_funcs.empty() ? nComponents : 1;
    141   CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
    142   if (!pDecode || pDecode->GetCount() != 4 + m_nComponents * 2)
    143     return false;
    144 
    145   m_xmin = pDecode->GetNumberAt(0);
    146   m_xmax = pDecode->GetNumberAt(1);
    147   m_ymin = pDecode->GetNumberAt(2);
    148   m_ymax = pDecode->GetNumberAt(3);
    149   for (uint32_t i = 0; i < m_nComponents; ++i) {
    150     m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4);
    151     m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5);
    152   }
    153 
    154   if (ShouldCheckBPC(m_type)) {
    155     m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1;
    156     m_ComponentMax = (1 << m_nComponentBits) - 1;
    157   }
    158   return true;
    159 }
    160 
    161 bool CPDF_MeshStream::CanReadFlag() const {
    162   return m_BitStream->BitsRemaining() >= m_nFlagBits;
    163 }
    164 
    165 bool CPDF_MeshStream::CanReadCoords() const {
    166   return m_BitStream->BitsRemaining() / 2 >= m_nCoordBits;
    167 }
    168 
    169 bool CPDF_MeshStream::CanReadColor() const {
    170   return m_BitStream->BitsRemaining() / m_nComponentBits >= m_nComponents;
    171 }
    172 
    173 uint32_t CPDF_MeshStream::ReadFlag() {
    174   ASSERT(ShouldCheckBitsPerFlag(m_type));
    175   return m_BitStream->GetBits(m_nFlagBits) & 0x03;
    176 }
    177 
    178 CFX_PointF CPDF_MeshStream::ReadCoords() {
    179   ASSERT(ShouldCheckBPC(m_type));
    180 
    181   CFX_PointF pos;
    182   if (m_nCoordBits == 32) {
    183     pos.x = m_xmin + m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) /
    184                          static_cast<double>(m_CoordMax);
    185     pos.y = m_ymin + m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) /
    186                          static_cast<double>(m_CoordMax);
    187   } else {
    188     pos.x = m_xmin +
    189             m_BitStream->GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
    190     pos.y = m_ymin +
    191             m_BitStream->GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
    192   }
    193   return pos;
    194 }
    195 
    196 std::tuple<float, float, float> CPDF_MeshStream::ReadColor() {
    197   ASSERT(ShouldCheckBPC(m_type));
    198 
    199   float color_value[kMaxComponents];
    200   for (uint32_t i = 0; i < m_nComponents; ++i) {
    201     color_value[i] = m_ColorMin[i] + m_BitStream->GetBits(m_nComponentBits) *
    202                                          (m_ColorMax[i] - m_ColorMin[i]) /
    203                                          m_ComponentMax;
    204   }
    205 
    206   float r = 0.0;
    207   float g = 0.0;
    208   float b = 0.0;
    209   if (m_funcs.empty()) {
    210     m_pCS->GetRGB(color_value, &r, &g, &b);
    211     return std::tuple<float, float, float>(r, g, b);
    212   }
    213 
    214   float result[kMaxComponents];
    215   memset(result, 0, sizeof(result));
    216   int nResults;
    217   for (const auto& func : m_funcs) {
    218     if (func && func->CountOutputs() <= kMaxComponents)
    219       func->Call(color_value, 1, result, &nResults);
    220   }
    221 
    222   m_pCS->GetRGB(result, &r, &g, &b);
    223   return std::tuple<float, float, float>(r, g, b);
    224 }
    225 
    226 bool CPDF_MeshStream::ReadVertex(const CFX_Matrix& pObject2Bitmap,
    227                                  CPDF_MeshVertex* vertex,
    228                                  uint32_t* flag) {
    229   if (!CanReadFlag())
    230     return false;
    231   *flag = ReadFlag();
    232 
    233   if (!CanReadCoords())
    234     return false;
    235   vertex->position = pObject2Bitmap.Transform(ReadCoords());
    236 
    237   if (!CanReadColor())
    238     return false;
    239   std::tie(vertex->r, vertex->g, vertex->b) = ReadColor();
    240   m_BitStream->ByteAlign();
    241   return true;
    242 }
    243 
    244 std::vector<CPDF_MeshVertex> CPDF_MeshStream::ReadVertexRow(
    245     const CFX_Matrix& pObject2Bitmap,
    246     int count) {
    247   std::vector<CPDF_MeshVertex> vertices;
    248   for (int i = 0; i < count; ++i) {
    249     if (m_BitStream->IsEOF() || !CanReadCoords())
    250       return std::vector<CPDF_MeshVertex>();
    251 
    252     vertices.push_back(CPDF_MeshVertex());
    253     CPDF_MeshVertex& vertex = vertices.back();
    254     vertex.position = pObject2Bitmap.Transform(ReadCoords());
    255     if (!CanReadColor())
    256       return std::vector<CPDF_MeshVertex>();
    257 
    258     std::tie(vertex.r, vertex.g, vertex.b) = ReadColor();
    259     m_BitStream->ByteAlign();
    260   }
    261   return vertices;
    262 }
    263