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 
CPDF_ContentParser()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 
~CPDF_ContentParser()34 CPDF_ContentParser::~CPDF_ContentParser() {
35   if (!m_pSingleStream)
36     FX_Free(m_pData);
37 }
38 
Start(CPDF_Page * pPage)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 
Start(CPDF_Form * pForm,CPDF_AllStates * pGraphicStates,const CFX_Matrix * pParentMatrix,CPDF_Type3Char * pType3Char,int level)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 
Continue(IFX_Pause * pPause)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