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