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_contentparser.h"
      8 
      9 #include "core/fpdfapi/font/cpdf_type3char.h"
     10 #include "core/fpdfapi/page/cpdf_allstates.h"
     11 #include "core/fpdfapi/page/cpdf_form.h"
     12 #include "core/fpdfapi/page/cpdf_page.h"
     13 #include "core/fpdfapi/page/cpdf_pageobject.h"
     14 #include "core/fpdfapi/page/cpdf_path.h"
     15 #include "core/fpdfapi/parser/cpdf_array.h"
     16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     17 #include "core/fpdfapi/parser/cpdf_stream.h"
     18 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
     19 #include "core/fxcrt/fx_safe_types.h"
     20 #include "core/fxcrt/ifx_pauseindicator.h"
     21 #include "third_party/base/ptr_util.h"
     22 
     23 #define PARSE_STEP_LIMIT 100
     24 
     25 CPDF_ContentParser::CPDF_ContentParser(CPDF_Page* pPage)
     26     : m_InternalStage(STAGE_GETCONTENT), m_pObjectHolder(pPage) {
     27   if (!pPage || !pPage->m_pDocument || !pPage->m_pFormDict) {
     28     m_bIsDone = true;
     29     return;
     30   }
     31 
     32   CPDF_Object* pContent = pPage->m_pFormDict->GetDirectObjectFor("Contents");
     33   if (!pContent) {
     34     m_bIsDone = true;
     35     return;
     36   }
     37   CPDF_Stream* pStream = pContent->AsStream();
     38   if (pStream) {
     39     m_pSingleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
     40     m_pSingleStream->LoadAllDataFiltered();
     41     return;
     42   }
     43   CPDF_Array* pArray = pContent->AsArray();
     44   if (!pArray) {
     45     m_bIsDone = true;
     46     return;
     47   }
     48   m_nStreams = pArray->GetCount();
     49   if (!m_nStreams) {
     50     m_bIsDone = true;
     51     return;
     52   }
     53   m_StreamArray.resize(m_nStreams);
     54 }
     55 
     56 CPDF_ContentParser::CPDF_ContentParser(CPDF_Form* pForm,
     57                                        CPDF_AllStates* pGraphicStates,
     58                                        const CFX_Matrix* pParentMatrix,
     59                                        CPDF_Type3Char* pType3Char,
     60                                        std::set<const uint8_t*>* parsedSet)
     61     : m_InternalStage(STAGE_PARSE),
     62       m_pObjectHolder(pForm),
     63       m_pType3Char(pType3Char) {
     64   CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrixFor("Matrix");
     65   if (pGraphicStates)
     66     form_matrix.Concat(pGraphicStates->m_CTM);
     67 
     68   CPDF_Array* pBBox = pForm->m_pFormDict->GetArrayFor("BBox");
     69   CFX_FloatRect form_bbox;
     70   CPDF_Path ClipPath;
     71   if (pBBox) {
     72     form_bbox = pBBox->GetRect();
     73     ClipPath.Emplace();
     74     ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right,
     75                         form_bbox.top);
     76     ClipPath.Transform(&form_matrix);
     77     if (pParentMatrix)
     78       ClipPath.Transform(pParentMatrix);
     79 
     80     form_bbox = form_matrix.TransformRect(form_bbox);
     81     if (pParentMatrix)
     82       form_bbox = pParentMatrix->TransformRect(form_bbox);
     83   }
     84 
     85   CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDictFor("Resources");
     86   m_pParser = pdfium::MakeUnique<CPDF_StreamContentParser>(
     87       pForm->m_pDocument.Get(), pForm->m_pPageResources.Get(),
     88       pForm->m_pResources.Get(), pParentMatrix, pForm, pResources, form_bbox,
     89       pGraphicStates, parsedSet);
     90   m_pParser->GetCurStates()->m_CTM = form_matrix;
     91   m_pParser->GetCurStates()->m_ParentMatrix = form_matrix;
     92   if (ClipPath.HasRef()) {
     93     m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING,
     94                                                      true);
     95   }
     96   if (pForm->m_iTransparency & PDFTRANS_GROUP) {
     97     CPDF_GeneralState* pState = &m_pParser->GetCurStates()->m_GeneralState;
     98     pState->SetBlendType(FXDIB_BLEND_NORMAL);
     99     pState->SetStrokeAlpha(1.0f);
    100     pState->SetFillAlpha(1.0f);
    101     pState->SetSoftMask(nullptr);
    102   }
    103   m_pSingleStream =
    104       pdfium::MakeRetain<CPDF_StreamAcc>(pForm->m_pFormStream.Get());
    105   m_pSingleStream->LoadAllDataFiltered();
    106   m_pData.Reset(m_pSingleStream->GetData());
    107   m_Size = m_pSingleStream->GetSize();
    108 }
    109 
    110 CPDF_ContentParser::~CPDF_ContentParser() {}
    111 
    112 bool CPDF_ContentParser::Continue(IFX_PauseIndicator* pPause) {
    113   if (m_bIsDone)
    114     return false;
    115 
    116   while (!m_bIsDone) {
    117     if (m_InternalStage == STAGE_GETCONTENT) {
    118       if (m_CurrentOffset == m_nStreams) {
    119         if (!m_StreamArray.empty()) {
    120           FX_SAFE_UINT32 safeSize = 0;
    121           for (const auto& stream : m_StreamArray) {
    122             safeSize += stream->GetSize();
    123             safeSize += 1;
    124           }
    125           if (!safeSize.IsValid()) {
    126             m_bIsDone = true;
    127             return false;
    128           }
    129           m_Size = safeSize.ValueOrDie();
    130           m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
    131               FX_Alloc(uint8_t, m_Size)));
    132           uint32_t pos = 0;
    133           for (const auto& stream : m_StreamArray) {
    134             memcpy(m_pData.Get() + pos, stream->GetData(), stream->GetSize());
    135             pos += stream->GetSize();
    136             m_pData.Get()[pos++] = ' ';
    137           }
    138           m_StreamArray.clear();
    139         } else {
    140           m_pData.Reset(m_pSingleStream->GetData());
    141           m_Size = m_pSingleStream->GetSize();
    142         }
    143         m_InternalStage = STAGE_PARSE;
    144         m_CurrentOffset = 0;
    145       } else {
    146         CPDF_Array* pContent =
    147             m_pObjectHolder->m_pFormDict->GetArrayFor("Contents");
    148         CPDF_Stream* pStreamObj = ToStream(
    149             pContent ? pContent->GetDirectObjectAt(m_CurrentOffset) : nullptr);
    150         m_StreamArray[m_CurrentOffset] =
    151             pdfium::MakeRetain<CPDF_StreamAcc>(pStreamObj);
    152         m_StreamArray[m_CurrentOffset]->LoadAllDataFiltered();
    153         m_CurrentOffset++;
    154       }
    155     }
    156     if (m_InternalStage == STAGE_PARSE) {
    157       if (!m_pParser) {
    158         m_parsedSet = pdfium::MakeUnique<std::set<const uint8_t*>>();
    159         m_pParser = pdfium::MakeUnique<CPDF_StreamContentParser>(
    160             m_pObjectHolder->m_pDocument.Get(),
    161             m_pObjectHolder->m_pPageResources.Get(), nullptr, nullptr,
    162             m_pObjectHolder.Get(), m_pObjectHolder->m_pResources.Get(),
    163             m_pObjectHolder->m_BBox, nullptr, m_parsedSet.get());
    164         m_pParser->GetCurStates()->m_ColorState.SetDefault();
    165       }
    166       if (m_CurrentOffset >= m_Size) {
    167         m_InternalStage = STAGE_CHECKCLIP;
    168       } else {
    169         m_CurrentOffset +=
    170             m_pParser->Parse(m_pData.Get() + m_CurrentOffset,
    171                              m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
    172       }
    173     }
    174     if (m_InternalStage == STAGE_CHECKCLIP) {
    175       if (m_pType3Char) {
    176         m_pType3Char->InitializeFromStreamData(m_pParser->IsColored(),
    177                                                m_pParser->GetType3Data());
    178       }
    179 
    180       for (auto& pObj : *m_pObjectHolder->GetPageObjectList()) {
    181         if (!pObj->m_ClipPath.HasRef())
    182           continue;
    183         if (pObj->m_ClipPath.GetPathCount() != 1)
    184           continue;
    185         if (pObj->m_ClipPath.GetTextCount() > 0)
    186           continue;
    187 
    188         CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
    189         if (!ClipPath.IsRect() || pObj->IsShading())
    190           continue;
    191 
    192         CFX_PointF point0 = ClipPath.GetPoint(0);
    193         CFX_PointF point2 = ClipPath.GetPoint(2);
    194         CFX_FloatRect old_rect(point0.x, point0.y, point2.x, point2.y);
    195         CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
    196                                pObj->m_Top);
    197         if (old_rect.Contains(obj_rect))
    198           pObj->m_ClipPath.SetNull();
    199       }
    200       m_bIsDone = true;
    201       return false;
    202     }
    203     if (pPause && pPause->NeedToPauseNow())
    204       break;
    205   }
    206   return true;
    207 }
    208