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