1 // Copyright 2016 The PDFium Authors
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_streamcontentparser.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "core/fpdfapi/font/cpdf_font.h"
15 #include "core/fpdfapi/font/cpdf_type3font.h"
16 #include "core/fpdfapi/page/cpdf_allstates.h"
17 #include "core/fpdfapi/page/cpdf_docpagedata.h"
18 #include "core/fpdfapi/page/cpdf_form.h"
19 #include "core/fpdfapi/page/cpdf_formobject.h"
20 #include "core/fpdfapi/page/cpdf_image.h"
21 #include "core/fpdfapi/page/cpdf_imageobject.h"
22 #include "core/fpdfapi/page/cpdf_meshstream.h"
23 #include "core/fpdfapi/page/cpdf_pageobject.h"
24 #include "core/fpdfapi/page/cpdf_pathobject.h"
25 #include "core/fpdfapi/page/cpdf_shadingobject.h"
26 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
27 #include "core/fpdfapi/page/cpdf_streamparser.h"
28 #include "core/fpdfapi/page/cpdf_textobject.h"
29 #include "core/fpdfapi/parser/cpdf_array.h"
30 #include "core/fpdfapi/parser/cpdf_dictionary.h"
31 #include "core/fpdfapi/parser/cpdf_document.h"
32 #include "core/fpdfapi/parser/cpdf_name.h"
33 #include "core/fpdfapi/parser/cpdf_number.h"
34 #include "core/fpdfapi/parser/cpdf_reference.h"
35 #include "core/fpdfapi/parser/cpdf_stream.h"
36 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
37 #include "core/fxcrt/autonuller.h"
38 #include "core/fxcrt/bytestring.h"
39 #include "core/fxcrt/fx_safe_types.h"
40 #include "core/fxcrt/scoped_set_insertion.h"
41 #include "core/fxcrt/stl_util.h"
42 #include "core/fxge/cfx_graphstate.h"
43 #include "core/fxge/cfx_graphstatedata.h"
44 #include "third_party/base/check.h"
45 #include "third_party/base/containers/contains.h"
46 #include "third_party/base/no_destructor.h"
47 #include "third_party/base/notreached.h"
48 #include "third_party/base/span.h"
49
50 namespace {
51
52 const int kMaxFormLevel = 40;
53
54 const int kSingleCoordinatePair = 1;
55 const int kTensorCoordinatePairs = 16;
56 const int kCoonsCoordinatePairs = 12;
57 const int kSingleColorPerPatch = 1;
58 const int kQuadColorsPerPatch = 4;
59
60 const char kPathOperatorSubpath = 'm';
61 const char kPathOperatorLine = 'l';
62 const char kPathOperatorCubicBezier1 = 'c';
63 const char kPathOperatorCubicBezier2 = 'v';
64 const char kPathOperatorCubicBezier3 = 'y';
65 const char kPathOperatorClosePath = 'h';
66 const char kPathOperatorRectangle[] = "re";
67
GetShadingBBox(CPDF_ShadingPattern * pShading,const CFX_Matrix & matrix)68 CFX_FloatRect GetShadingBBox(CPDF_ShadingPattern* pShading,
69 const CFX_Matrix& matrix) {
70 ShadingType type = pShading->GetShadingType();
71 RetainPtr<const CPDF_Stream> pStream = ToStream(pShading->GetShadingObject());
72 RetainPtr<CPDF_ColorSpace> pCS = pShading->GetCS();
73 if (!pStream || !pCS)
74 return CFX_FloatRect();
75
76 CPDF_MeshStream stream(type, pShading->GetFuncs(), std::move(pStream),
77 std::move(pCS));
78 if (!stream.Load())
79 return CFX_FloatRect();
80
81 CFX_FloatRect rect;
82 bool update_rect = false;
83 bool bGouraud = type == kFreeFormGouraudTriangleMeshShading ||
84 type == kLatticeFormGouraudTriangleMeshShading;
85
86 int point_count;
87 if (type == kTensorProductPatchMeshShading)
88 point_count = kTensorCoordinatePairs;
89 else if (type == kCoonsPatchMeshShading)
90 point_count = kCoonsCoordinatePairs;
91 else
92 point_count = kSingleCoordinatePair;
93
94 int color_count;
95 if (type == kCoonsPatchMeshShading || type == kTensorProductPatchMeshShading)
96 color_count = kQuadColorsPerPatch;
97 else
98 color_count = kSingleColorPerPatch;
99
100 while (!stream.IsEOF()) {
101 uint32_t flag = 0;
102 if (type != kLatticeFormGouraudTriangleMeshShading) {
103 if (!stream.CanReadFlag())
104 break;
105 flag = stream.ReadFlag();
106 }
107
108 if (!bGouraud && flag) {
109 point_count -= 4;
110 color_count -= 2;
111 }
112
113 for (int i = 0; i < point_count; ++i) {
114 if (!stream.CanReadCoords())
115 break;
116
117 CFX_PointF origin = stream.ReadCoords();
118 if (update_rect) {
119 rect.UpdateRect(origin);
120 } else {
121 rect = CFX_FloatRect(origin);
122 update_rect = true;
123 }
124 }
125 FX_SAFE_UINT32 nBits = stream.Components();
126 nBits *= stream.ComponentBits();
127 nBits *= color_count;
128 if (!nBits.IsValid())
129 break;
130
131 stream.SkipBits(nBits.ValueOrDie());
132 if (bGouraud)
133 stream.ByteAlign();
134 }
135 return matrix.TransformRect(rect);
136 }
137
138 struct AbbrPair {
139 const char* abbr;
140 const char* full_name;
141 };
142
143 const AbbrPair kInlineKeyAbbr[] = {
144 {"BPC", "BitsPerComponent"}, {"CS", "ColorSpace"}, {"D", "Decode"},
145 {"DP", "DecodeParms"}, {"F", "Filter"}, {"H", "Height"},
146 {"IM", "ImageMask"}, {"I", "Interpolate"}, {"W", "Width"},
147 };
148
149 const AbbrPair kInlineValueAbbr[] = {
150 {"G", "DeviceGray"}, {"RGB", "DeviceRGB"},
151 {"CMYK", "DeviceCMYK"}, {"I", "Indexed"},
152 {"AHx", "ASCIIHexDecode"}, {"A85", "ASCII85Decode"},
153 {"LZW", "LZWDecode"}, {"Fl", "FlateDecode"},
154 {"RL", "RunLengthDecode"}, {"CCF", "CCITTFaxDecode"},
155 {"DCT", "DCTDecode"},
156 };
157
158 struct AbbrReplacementOp {
159 bool is_replace_key;
160 ByteString key;
161 ByteStringView replacement;
162 };
163
FindFullName(pdfium::span<const AbbrPair> table,ByteStringView abbr)164 ByteStringView FindFullName(pdfium::span<const AbbrPair> table,
165 ByteStringView abbr) {
166 for (const auto& pair : table) {
167 if (pair.abbr == abbr)
168 return ByteStringView(pair.full_name);
169 }
170 return ByteStringView();
171 }
172
173 void ReplaceAbbr(RetainPtr<CPDF_Object> pObj);
174
ReplaceAbbrInDictionary(CPDF_Dictionary * pDict)175 void ReplaceAbbrInDictionary(CPDF_Dictionary* pDict) {
176 std::vector<AbbrReplacementOp> replacements;
177 {
178 CPDF_DictionaryLocker locker(pDict);
179 for (const auto& it : locker) {
180 ByteString key = it.first;
181 ByteStringView fullname =
182 FindFullName(kInlineKeyAbbr, key.AsStringView());
183 if (!fullname.IsEmpty()) {
184 AbbrReplacementOp op;
185 op.is_replace_key = true;
186 op.key = std::move(key);
187 op.replacement = fullname;
188 replacements.push_back(op);
189 key = fullname;
190 }
191 RetainPtr<CPDF_Object> value = it.second;
192 if (value->IsName()) {
193 ByteString name = value->GetString();
194 fullname = FindFullName(kInlineValueAbbr, name.AsStringView());
195 if (!fullname.IsEmpty()) {
196 AbbrReplacementOp op;
197 op.is_replace_key = false;
198 op.key = key;
199 op.replacement = fullname;
200 replacements.push_back(op);
201 }
202 } else {
203 ReplaceAbbr(std::move(value));
204 }
205 }
206 }
207 for (const auto& op : replacements) {
208 if (op.is_replace_key)
209 pDict->ReplaceKey(op.key, ByteString(op.replacement));
210 else
211 pDict->SetNewFor<CPDF_Name>(op.key, ByteString(op.replacement));
212 }
213 }
214
ReplaceAbbrInArray(CPDF_Array * pArray)215 void ReplaceAbbrInArray(CPDF_Array* pArray) {
216 for (size_t i = 0; i < pArray->size(); ++i) {
217 RetainPtr<CPDF_Object> pElement = pArray->GetMutableObjectAt(i);
218 if (pElement->IsName()) {
219 ByteString name = pElement->GetString();
220 ByteStringView fullname =
221 FindFullName(kInlineValueAbbr, name.AsStringView());
222 if (!fullname.IsEmpty())
223 pArray->SetNewAt<CPDF_Name>(i, ByteString(fullname));
224 } else {
225 ReplaceAbbr(std::move(pElement));
226 }
227 }
228 }
229
ReplaceAbbr(RetainPtr<CPDF_Object> pObj)230 void ReplaceAbbr(RetainPtr<CPDF_Object> pObj) {
231 CPDF_Dictionary* pDict = pObj->AsMutableDictionary();
232 if (pDict) {
233 ReplaceAbbrInDictionary(pDict);
234 return;
235 }
236
237 CPDF_Array* pArray = pObj->AsMutableArray();
238 if (pArray)
239 ReplaceAbbrInArray(pArray);
240 }
241
242 } // namespace
243
CPDF_StreamContentParser(CPDF_Document * pDocument,RetainPtr<CPDF_Dictionary> pPageResources,RetainPtr<CPDF_Dictionary> pParentResources,const CFX_Matrix * pmtContentToUser,CPDF_PageObjectHolder * pObjHolder,RetainPtr<CPDF_Dictionary> pResources,const CFX_FloatRect & rcBBox,const CPDF_AllStates * pStates,std::set<const uint8_t * > * pParsedSet)244 CPDF_StreamContentParser::CPDF_StreamContentParser(
245 CPDF_Document* pDocument,
246 RetainPtr<CPDF_Dictionary> pPageResources,
247 RetainPtr<CPDF_Dictionary> pParentResources,
248 const CFX_Matrix* pmtContentToUser,
249 CPDF_PageObjectHolder* pObjHolder,
250 RetainPtr<CPDF_Dictionary> pResources,
251 const CFX_FloatRect& rcBBox,
252 const CPDF_AllStates* pStates,
253 std::set<const uint8_t*>* pParsedSet)
254 : m_pDocument(pDocument),
255 m_pPageResources(pPageResources),
256 m_pParentResources(pParentResources),
257 m_pResources(CPDF_Form::ChooseResourcesDict(pResources.Get(),
258 pParentResources.Get(),
259 pPageResources.Get())),
260 m_pObjectHolder(pObjHolder),
261 m_ParsedSet(pParsedSet),
262 m_BBox(rcBBox),
263 m_pCurStates(std::make_unique<CPDF_AllStates>()) {
264 if (pmtContentToUser)
265 m_mtContentToUser = *pmtContentToUser;
266 if (pStates) {
267 m_pCurStates->Copy(*pStates);
268 } else {
269 m_pCurStates->m_GeneralState.Emplace();
270 m_pCurStates->m_GraphState.Emplace();
271 m_pCurStates->m_TextState.Emplace();
272 m_pCurStates->m_ColorState.Emplace();
273 }
274
275 // Add the sentinel.
276 m_ContentMarksStack.push(std::make_unique<CPDF_ContentMarks>());
277 }
278
~CPDF_StreamContentParser()279 CPDF_StreamContentParser::~CPDF_StreamContentParser() {
280 ClearAllParams();
281 }
282
GetNextParamPos()283 int CPDF_StreamContentParser::GetNextParamPos() {
284 if (m_ParamCount == kParamBufSize) {
285 m_ParamStartPos++;
286 if (m_ParamStartPos == kParamBufSize) {
287 m_ParamStartPos = 0;
288 }
289 if (m_ParamBuf[m_ParamStartPos].m_Type == ContentParam::Type::kObject)
290 m_ParamBuf[m_ParamStartPos].m_pObject.Reset();
291
292 return m_ParamStartPos;
293 }
294 int index = m_ParamStartPos + m_ParamCount;
295 if (index >= kParamBufSize) {
296 index -= kParamBufSize;
297 }
298 m_ParamCount++;
299 return index;
300 }
301
AddNameParam(ByteStringView bsName)302 void CPDF_StreamContentParser::AddNameParam(ByteStringView bsName) {
303 ContentParam& param = m_ParamBuf[GetNextParamPos()];
304 param.m_Type = ContentParam::Type::kName;
305 param.m_Name = PDF_NameDecode(bsName);
306 }
307
AddNumberParam(ByteStringView str)308 void CPDF_StreamContentParser::AddNumberParam(ByteStringView str) {
309 ContentParam& param = m_ParamBuf[GetNextParamPos()];
310 param.m_Type = ContentParam::Type::kNumber;
311 param.m_Number = FX_Number(str);
312 }
313
AddObjectParam(RetainPtr<CPDF_Object> pObj)314 void CPDF_StreamContentParser::AddObjectParam(RetainPtr<CPDF_Object> pObj) {
315 ContentParam& param = m_ParamBuf[GetNextParamPos()];
316 param.m_Type = ContentParam::Type::kObject;
317 param.m_pObject = std::move(pObj);
318 }
319
ClearAllParams()320 void CPDF_StreamContentParser::ClearAllParams() {
321 uint32_t index = m_ParamStartPos;
322 for (uint32_t i = 0; i < m_ParamCount; i++) {
323 if (m_ParamBuf[index].m_Type == ContentParam::Type::kObject)
324 m_ParamBuf[index].m_pObject.Reset();
325 index++;
326 if (index == kParamBufSize)
327 index = 0;
328 }
329 m_ParamStartPos = 0;
330 m_ParamCount = 0;
331 }
332
GetObject(uint32_t index)333 RetainPtr<CPDF_Object> CPDF_StreamContentParser::GetObject(uint32_t index) {
334 if (index >= m_ParamCount) {
335 return nullptr;
336 }
337 int real_index = m_ParamStartPos + m_ParamCount - index - 1;
338 if (real_index >= kParamBufSize) {
339 real_index -= kParamBufSize;
340 }
341 ContentParam& param = m_ParamBuf[real_index];
342 if (param.m_Type == ContentParam::Type::kNumber) {
343 param.m_Type = ContentParam::Type::kObject;
344 param.m_pObject =
345 param.m_Number.IsInteger()
346 ? pdfium::MakeRetain<CPDF_Number>(param.m_Number.GetSigned())
347 : pdfium::MakeRetain<CPDF_Number>(param.m_Number.GetFloat());
348 return param.m_pObject;
349 }
350 if (param.m_Type == ContentParam::Type::kName) {
351 param.m_Type = ContentParam::Type::kObject;
352 param.m_pObject = m_pDocument->New<CPDF_Name>(param.m_Name);
353 return param.m_pObject;
354 }
355 if (param.m_Type == ContentParam::Type::kObject)
356 return param.m_pObject;
357
358 NOTREACHED_NORETURN();
359 }
360
GetString(uint32_t index) const361 ByteString CPDF_StreamContentParser::GetString(uint32_t index) const {
362 if (index >= m_ParamCount)
363 return ByteString();
364
365 int real_index = m_ParamStartPos + m_ParamCount - index - 1;
366 if (real_index >= kParamBufSize)
367 real_index -= kParamBufSize;
368
369 const ContentParam& param = m_ParamBuf[real_index];
370 if (param.m_Type == ContentParam::Type::kName)
371 return param.m_Name;
372
373 if (param.m_Type == ContentParam::Type::kObject && param.m_pObject)
374 return param.m_pObject->GetString();
375
376 return ByteString();
377 }
378
GetNumber(uint32_t index) const379 float CPDF_StreamContentParser::GetNumber(uint32_t index) const {
380 if (index >= m_ParamCount)
381 return 0;
382
383 int real_index = m_ParamStartPos + m_ParamCount - index - 1;
384 if (real_index >= kParamBufSize)
385 real_index -= kParamBufSize;
386
387 const ContentParam& param = m_ParamBuf[real_index];
388 if (param.m_Type == ContentParam::Type::kNumber)
389 return param.m_Number.GetFloat();
390
391 if (param.m_Type == ContentParam::Type::kObject && param.m_pObject)
392 return param.m_pObject->GetNumber();
393
394 return 0;
395 }
396
GetNumbers(size_t count) const397 std::vector<float> CPDF_StreamContentParser::GetNumbers(size_t count) const {
398 std::vector<float> values(count);
399 for (size_t i = 0; i < count; ++i)
400 values[i] = GetNumber(count - i - 1);
401 return values;
402 }
403
GetPoint(uint32_t index) const404 CFX_PointF CPDF_StreamContentParser::GetPoint(uint32_t index) const {
405 return CFX_PointF(GetNumber(index + 1), GetNumber(index));
406 }
407
GetMatrix() const408 CFX_Matrix CPDF_StreamContentParser::GetMatrix() const {
409 return CFX_Matrix(GetNumber(5), GetNumber(4), GetNumber(3), GetNumber(2),
410 GetNumber(1), GetNumber(0));
411 }
412
SetGraphicStates(CPDF_PageObject * pObj,bool bColor,bool bText,bool bGraph)413 void CPDF_StreamContentParser::SetGraphicStates(CPDF_PageObject* pObj,
414 bool bColor,
415 bool bText,
416 bool bGraph) {
417 pObj->m_GeneralState = m_pCurStates->m_GeneralState;
418 pObj->m_ClipPath = m_pCurStates->m_ClipPath;
419 pObj->SetContentMarks(*m_ContentMarksStack.top());
420 if (bColor) {
421 pObj->m_ColorState = m_pCurStates->m_ColorState;
422 }
423 if (bGraph) {
424 pObj->m_GraphState = m_pCurStates->m_GraphState;
425 }
426 if (bText) {
427 pObj->m_TextState = m_pCurStates->m_TextState;
428 }
429 pObj->SetGraphicsResourceName(m_pCurStates->m_GraphicsResourceName);
430 }
431
432 // static
433 CPDF_StreamContentParser::OpCodes
InitializeOpCodes()434 CPDF_StreamContentParser::InitializeOpCodes() {
435 return OpCodes({
436 {FXBSTR_ID('"', 0, 0, 0),
437 &CPDF_StreamContentParser::Handle_NextLineShowText_Space},
438 {FXBSTR_ID('\'', 0, 0, 0),
439 &CPDF_StreamContentParser::Handle_NextLineShowText},
440 {FXBSTR_ID('B', 0, 0, 0),
441 &CPDF_StreamContentParser::Handle_FillStrokePath},
442 {FXBSTR_ID('B', '*', 0, 0),
443 &CPDF_StreamContentParser::Handle_EOFillStrokePath},
444 {FXBSTR_ID('B', 'D', 'C', 0),
445 &CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary},
446 {FXBSTR_ID('B', 'I', 0, 0), &CPDF_StreamContentParser::Handle_BeginImage},
447 {FXBSTR_ID('B', 'M', 'C', 0),
448 &CPDF_StreamContentParser::Handle_BeginMarkedContent},
449 {FXBSTR_ID('B', 'T', 0, 0), &CPDF_StreamContentParser::Handle_BeginText},
450 {FXBSTR_ID('C', 'S', 0, 0),
451 &CPDF_StreamContentParser::Handle_SetColorSpace_Stroke},
452 {FXBSTR_ID('D', 'P', 0, 0),
453 &CPDF_StreamContentParser::Handle_MarkPlace_Dictionary},
454 {FXBSTR_ID('D', 'o', 0, 0),
455 &CPDF_StreamContentParser::Handle_ExecuteXObject},
456 {FXBSTR_ID('E', 'I', 0, 0), &CPDF_StreamContentParser::Handle_EndImage},
457 {FXBSTR_ID('E', 'M', 'C', 0),
458 &CPDF_StreamContentParser::Handle_EndMarkedContent},
459 {FXBSTR_ID('E', 'T', 0, 0), &CPDF_StreamContentParser::Handle_EndText},
460 {FXBSTR_ID('F', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPathOld},
461 {FXBSTR_ID('G', 0, 0, 0),
462 &CPDF_StreamContentParser::Handle_SetGray_Stroke},
463 {FXBSTR_ID('I', 'D', 0, 0),
464 &CPDF_StreamContentParser::Handle_BeginImageData},
465 {FXBSTR_ID('J', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineCap},
466 {FXBSTR_ID('K', 0, 0, 0),
467 &CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke},
468 {FXBSTR_ID('M', 0, 0, 0),
469 &CPDF_StreamContentParser::Handle_SetMiterLimit},
470 {FXBSTR_ID('M', 'P', 0, 0), &CPDF_StreamContentParser::Handle_MarkPlace},
471 {FXBSTR_ID('Q', 0, 0, 0),
472 &CPDF_StreamContentParser::Handle_RestoreGraphState},
473 {FXBSTR_ID('R', 'G', 0, 0),
474 &CPDF_StreamContentParser::Handle_SetRGBColor_Stroke},
475 {FXBSTR_ID('S', 0, 0, 0), &CPDF_StreamContentParser::Handle_StrokePath},
476 {FXBSTR_ID('S', 'C', 0, 0),
477 &CPDF_StreamContentParser::Handle_SetColor_Stroke},
478 {FXBSTR_ID('S', 'C', 'N', 0),
479 &CPDF_StreamContentParser::Handle_SetColorPS_Stroke},
480 {FXBSTR_ID('T', '*', 0, 0),
481 &CPDF_StreamContentParser::Handle_MoveToNextLine},
482 {FXBSTR_ID('T', 'D', 0, 0),
483 &CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading},
484 {FXBSTR_ID('T', 'J', 0, 0),
485 &CPDF_StreamContentParser::Handle_ShowText_Positioning},
486 {FXBSTR_ID('T', 'L', 0, 0),
487 &CPDF_StreamContentParser::Handle_SetTextLeading},
488 {FXBSTR_ID('T', 'c', 0, 0),
489 &CPDF_StreamContentParser::Handle_SetCharSpace},
490 {FXBSTR_ID('T', 'd', 0, 0),
491 &CPDF_StreamContentParser::Handle_MoveTextPoint},
492 {FXBSTR_ID('T', 'f', 0, 0), &CPDF_StreamContentParser::Handle_SetFont},
493 {FXBSTR_ID('T', 'j', 0, 0), &CPDF_StreamContentParser::Handle_ShowText},
494 {FXBSTR_ID('T', 'm', 0, 0),
495 &CPDF_StreamContentParser::Handle_SetTextMatrix},
496 {FXBSTR_ID('T', 'r', 0, 0),
497 &CPDF_StreamContentParser::Handle_SetTextRenderMode},
498 {FXBSTR_ID('T', 's', 0, 0),
499 &CPDF_StreamContentParser::Handle_SetTextRise},
500 {FXBSTR_ID('T', 'w', 0, 0),
501 &CPDF_StreamContentParser::Handle_SetWordSpace},
502 {FXBSTR_ID('T', 'z', 0, 0),
503 &CPDF_StreamContentParser::Handle_SetHorzScale},
504 {FXBSTR_ID('W', 0, 0, 0), &CPDF_StreamContentParser::Handle_Clip},
505 {FXBSTR_ID('W', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOClip},
506 {FXBSTR_ID('b', 0, 0, 0),
507 &CPDF_StreamContentParser::Handle_CloseFillStrokePath},
508 {FXBSTR_ID('b', '*', 0, 0),
509 &CPDF_StreamContentParser::Handle_CloseEOFillStrokePath},
510 {FXBSTR_ID('c', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_123},
511 {FXBSTR_ID('c', 'm', 0, 0),
512 &CPDF_StreamContentParser::Handle_ConcatMatrix},
513 {FXBSTR_ID('c', 's', 0, 0),
514 &CPDF_StreamContentParser::Handle_SetColorSpace_Fill},
515 {FXBSTR_ID('d', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetDash},
516 {FXBSTR_ID('d', '0', 0, 0),
517 &CPDF_StreamContentParser::Handle_SetCharWidth},
518 {FXBSTR_ID('d', '1', 0, 0),
519 &CPDF_StreamContentParser::Handle_SetCachedDevice},
520 {FXBSTR_ID('f', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPath},
521 {FXBSTR_ID('f', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOFillPath},
522 {FXBSTR_ID('g', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetGray_Fill},
523 {FXBSTR_ID('g', 's', 0, 0),
524 &CPDF_StreamContentParser::Handle_SetExtendGraphState},
525 {FXBSTR_ID('h', 0, 0, 0), &CPDF_StreamContentParser::Handle_ClosePath},
526 {FXBSTR_ID('i', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetFlat},
527 {FXBSTR_ID('j', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineJoin},
528 {FXBSTR_ID('k', 0, 0, 0),
529 &CPDF_StreamContentParser::Handle_SetCMYKColor_Fill},
530 {FXBSTR_ID('l', 0, 0, 0), &CPDF_StreamContentParser::Handle_LineTo},
531 {FXBSTR_ID('m', 0, 0, 0), &CPDF_StreamContentParser::Handle_MoveTo},
532 {FXBSTR_ID('n', 0, 0, 0), &CPDF_StreamContentParser::Handle_EndPath},
533 {FXBSTR_ID('q', 0, 0, 0),
534 &CPDF_StreamContentParser::Handle_SaveGraphState},
535 {FXBSTR_ID('r', 'e', 0, 0), &CPDF_StreamContentParser::Handle_Rectangle},
536 {FXBSTR_ID('r', 'g', 0, 0),
537 &CPDF_StreamContentParser::Handle_SetRGBColor_Fill},
538 {FXBSTR_ID('r', 'i', 0, 0),
539 &CPDF_StreamContentParser::Handle_SetRenderIntent},
540 {FXBSTR_ID('s', 0, 0, 0),
541 &CPDF_StreamContentParser::Handle_CloseStrokePath},
542 {FXBSTR_ID('s', 'c', 0, 0),
543 &CPDF_StreamContentParser::Handle_SetColor_Fill},
544 {FXBSTR_ID('s', 'c', 'n', 0),
545 &CPDF_StreamContentParser::Handle_SetColorPS_Fill},
546 {FXBSTR_ID('s', 'h', 0, 0), &CPDF_StreamContentParser::Handle_ShadeFill},
547 {FXBSTR_ID('v', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_23},
548 {FXBSTR_ID('w', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineWidth},
549 {FXBSTR_ID('y', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_13},
550 });
551 }
552
OnOperator(ByteStringView op)553 void CPDF_StreamContentParser::OnOperator(ByteStringView op) {
554 static const pdfium::base::NoDestructor<OpCodes> s_OpCodes(
555 InitializeOpCodes());
556
557 auto it = s_OpCodes->find(op.GetID());
558 if (it != s_OpCodes->end())
559 (this->*it->second)();
560 }
561
Handle_CloseFillStrokePath()562 void CPDF_StreamContentParser::Handle_CloseFillStrokePath() {
563 Handle_ClosePath();
564 AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kStroke);
565 }
566
Handle_FillStrokePath()567 void CPDF_StreamContentParser::Handle_FillStrokePath() {
568 AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kStroke);
569 }
570
Handle_CloseEOFillStrokePath()571 void CPDF_StreamContentParser::Handle_CloseEOFillStrokePath() {
572 AddPathPointAndClose(m_PathStart, CFX_Path::Point::Type::kLine);
573 AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kStroke);
574 }
575
Handle_EOFillStrokePath()576 void CPDF_StreamContentParser::Handle_EOFillStrokePath() {
577 AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kStroke);
578 }
579
Handle_BeginMarkedContent_Dictionary()580 void CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary() {
581 RetainPtr<CPDF_Object> pProperty = GetObject(0);
582 if (!pProperty)
583 return;
584
585 ByteString tag = GetString(1);
586 std::unique_ptr<CPDF_ContentMarks> new_marks =
587 m_ContentMarksStack.top()->Clone();
588
589 if (pProperty->IsName()) {
590 ByteString property_name = pProperty->GetString();
591 RetainPtr<CPDF_Dictionary> pHolder = FindResourceHolder("Properties");
592 if (!pHolder || !pHolder->GetDictFor(property_name))
593 return;
594 new_marks->AddMarkWithPropertiesHolder(tag, std::move(pHolder),
595 property_name);
596 } else if (pProperty->IsDictionary()) {
597 new_marks->AddMarkWithDirectDict(tag, ToDictionary(pProperty));
598 } else {
599 return;
600 }
601 m_ContentMarksStack.push(std::move(new_marks));
602 }
603
Handle_BeginImage()604 void CPDF_StreamContentParser::Handle_BeginImage() {
605 FX_FILESIZE savePos = m_pSyntax->GetPos();
606 auto pDict = m_pDocument->New<CPDF_Dictionary>();
607 while (true) {
608 CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement();
609 if (type == CPDF_StreamParser::ElementType::kKeyword) {
610 if (m_pSyntax->GetWord() != "ID") {
611 m_pSyntax->SetPos(savePos);
612 return;
613 }
614 }
615 if (type != CPDF_StreamParser::ElementType::kName) {
616 break;
617 }
618 auto word = m_pSyntax->GetWord();
619 ByteString key(word.Last(word.GetLength() - 1));
620 auto pObj = m_pSyntax->ReadNextObject(false, false, 0);
621 if (pObj && !pObj->IsInline()) {
622 pDict->SetNewFor<CPDF_Reference>(key, m_pDocument, pObj->GetObjNum());
623 } else {
624 pDict->SetFor(key, std::move(pObj));
625 }
626 }
627 ReplaceAbbr(pDict);
628 RetainPtr<const CPDF_Object> pCSObj;
629 if (pDict->KeyExist("ColorSpace")) {
630 pCSObj = pDict->GetDirectObjectFor("ColorSpace");
631 if (pCSObj->IsName()) {
632 ByteString name = pCSObj->GetString();
633 if (name != "DeviceRGB" && name != "DeviceGray" && name != "DeviceCMYK") {
634 pCSObj = FindResourceObj("ColorSpace", name);
635 if (pCSObj && pCSObj->IsInline())
636 pDict->SetFor("ColorSpace", pCSObj->Clone());
637 }
638 }
639 }
640 pDict->SetNewFor<CPDF_Name>("Subtype", "Image");
641 RetainPtr<CPDF_Stream> pStream =
642 m_pSyntax->ReadInlineStream(m_pDocument, std::move(pDict), pCSObj.Get());
643 while (true) {
644 CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement();
645 if (type == CPDF_StreamParser::ElementType::kEndOfData)
646 break;
647
648 if (type != CPDF_StreamParser::ElementType::kKeyword)
649 continue;
650
651 if (m_pSyntax->GetWord() == "EI")
652 break;
653 }
654 CPDF_ImageObject* pObj =
655 AddImageFromStream(std::move(pStream), /*resource_name=*/"");
656 // Record the bounding box of this image, so rendering code can draw it
657 // properly.
658 if (pObj && pObj->GetImage()->IsMask())
659 m_pObjectHolder->AddImageMaskBoundingBox(pObj->GetRect());
660 }
661
Handle_BeginMarkedContent()662 void CPDF_StreamContentParser::Handle_BeginMarkedContent() {
663 std::unique_ptr<CPDF_ContentMarks> new_marks =
664 m_ContentMarksStack.top()->Clone();
665 new_marks->AddMark(GetString(0));
666 m_ContentMarksStack.push(std::move(new_marks));
667 }
668
Handle_BeginText()669 void CPDF_StreamContentParser::Handle_BeginText() {
670 m_pCurStates->m_TextMatrix = CFX_Matrix();
671 OnChangeTextMatrix();
672 m_pCurStates->m_TextPos = CFX_PointF();
673 m_pCurStates->m_TextLinePos = CFX_PointF();
674 }
675
Handle_CurveTo_123()676 void CPDF_StreamContentParser::Handle_CurveTo_123() {
677 AddPathPoint(GetPoint(4), CFX_Path::Point::Type::kBezier);
678 AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier);
679 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier);
680 }
681
Handle_ConcatMatrix()682 void CPDF_StreamContentParser::Handle_ConcatMatrix() {
683 m_pCurStates->m_CTM = GetMatrix() * m_pCurStates->m_CTM;
684 OnChangeTextMatrix();
685 }
686
Handle_SetColorSpace_Fill()687 void CPDF_StreamContentParser::Handle_SetColorSpace_Fill() {
688 RetainPtr<CPDF_ColorSpace> pCS = FindColorSpace(GetString(0));
689 if (!pCS)
690 return;
691
692 m_pCurStates->m_ColorState.GetMutableFillColor()->SetColorSpace(
693 std::move(pCS));
694 }
695
Handle_SetColorSpace_Stroke()696 void CPDF_StreamContentParser::Handle_SetColorSpace_Stroke() {
697 RetainPtr<CPDF_ColorSpace> pCS = FindColorSpace(GetString(0));
698 if (!pCS)
699 return;
700
701 m_pCurStates->m_ColorState.GetMutableStrokeColor()->SetColorSpace(
702 std::move(pCS));
703 }
704
Handle_SetDash()705 void CPDF_StreamContentParser::Handle_SetDash() {
706 RetainPtr<CPDF_Array> pArray = ToArray(GetObject(1));
707 if (!pArray)
708 return;
709
710 m_pCurStates->SetLineDash(pArray.Get(), GetNumber(0), 1.0f);
711 }
712
Handle_SetCharWidth()713 void CPDF_StreamContentParser::Handle_SetCharWidth() {
714 m_Type3Data[0] = GetNumber(1);
715 m_Type3Data[1] = GetNumber(0);
716 m_bColored = true;
717 }
718
Handle_SetCachedDevice()719 void CPDF_StreamContentParser::Handle_SetCachedDevice() {
720 for (int i = 0; i < 6; i++) {
721 m_Type3Data[i] = GetNumber(5 - i);
722 }
723 m_bColored = false;
724 }
725
Handle_ExecuteXObject()726 void CPDF_StreamContentParser::Handle_ExecuteXObject() {
727 ByteString name = GetString(0);
728 if (name == m_LastImageName && m_pLastImage && m_pLastImage->GetStream() &&
729 m_pLastImage->GetStream()->GetObjNum()) {
730 CPDF_ImageObject* pObj = AddLastImage();
731 // Record the bounding box of this image, so rendering code can draw it
732 // properly.
733 if (pObj && pObj->GetImage()->IsMask())
734 m_pObjectHolder->AddImageMaskBoundingBox(pObj->GetRect());
735 return;
736 }
737
738 RetainPtr<CPDF_Stream> pXObject(ToStream(FindResourceObj("XObject", name)));
739 if (!pXObject)
740 return;
741
742 ByteString type;
743 if (pXObject->GetDict())
744 type = pXObject->GetDict()->GetByteStringFor("Subtype");
745
746 if (type == "Form") {
747 AddForm(std::move(pXObject), name);
748 return;
749 }
750
751 if (type == "Image") {
752 CPDF_ImageObject* pObj =
753 pXObject->IsInline()
754 ? AddImageFromStream(ToStream(pXObject->Clone()), name)
755 : AddImageFromStreamObjNum(pXObject->GetObjNum(), name);
756
757 m_LastImageName = std::move(name);
758 if (pObj) {
759 m_pLastImage = pObj->GetImage();
760 if (m_pLastImage->IsMask())
761 m_pObjectHolder->AddImageMaskBoundingBox(pObj->GetRect());
762 }
763 }
764 }
765
AddForm(RetainPtr<CPDF_Stream> pStream,const ByteString & name)766 void CPDF_StreamContentParser::AddForm(RetainPtr<CPDF_Stream> pStream,
767 const ByteString& name) {
768 CPDF_AllStates status;
769 status.m_GeneralState = m_pCurStates->m_GeneralState;
770 status.m_GraphState = m_pCurStates->m_GraphState;
771 status.m_ColorState = m_pCurStates->m_ColorState;
772 status.m_TextState = m_pCurStates->m_TextState;
773 auto form = std::make_unique<CPDF_Form>(
774 m_pDocument, m_pPageResources, std::move(pStream), m_pResources.Get());
775 form->ParseContent(&status, nullptr, m_ParsedSet);
776
777 CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser;
778 auto pFormObj = std::make_unique<CPDF_FormObject>(GetCurrentStreamIndex(),
779 std::move(form), matrix);
780 pFormObj->SetResourceName(name);
781 pFormObj->SetGraphicsResourceName(m_pCurStates->m_GraphicsResourceName);
782 if (!m_pObjectHolder->BackgroundAlphaNeeded() &&
783 pFormObj->form()->BackgroundAlphaNeeded()) {
784 m_pObjectHolder->SetBackgroundAlphaNeeded(true);
785 }
786 pFormObj->CalcBoundingBox();
787 SetGraphicStates(pFormObj.get(), true, true, true);
788 m_pObjectHolder->AppendPageObject(std::move(pFormObj));
789 }
790
AddImageFromStream(RetainPtr<CPDF_Stream> pStream,const ByteString & name)791 CPDF_ImageObject* CPDF_StreamContentParser::AddImageFromStream(
792 RetainPtr<CPDF_Stream> pStream,
793 const ByteString& name) {
794 if (!pStream)
795 return nullptr;
796
797 auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex());
798 pImageObj->SetResourceName(name);
799 pImageObj->SetImage(
800 pdfium::MakeRetain<CPDF_Image>(m_pDocument, std::move(pStream)));
801
802 return AddImageObject(std::move(pImageObj));
803 }
804
AddImageFromStreamObjNum(uint32_t stream_obj_num,const ByteString & name)805 CPDF_ImageObject* CPDF_StreamContentParser::AddImageFromStreamObjNum(
806 uint32_t stream_obj_num,
807 const ByteString& name) {
808 auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex());
809 pImageObj->SetResourceName(name);
810 pImageObj->SetImage(
811 CPDF_DocPageData::FromDocument(m_pDocument)->GetImage(stream_obj_num));
812
813 return AddImageObject(std::move(pImageObj));
814 }
815
AddLastImage()816 CPDF_ImageObject* CPDF_StreamContentParser::AddLastImage() {
817 DCHECK(m_pLastImage);
818
819 auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex());
820 pImageObj->SetResourceName(m_LastImageName);
821 pImageObj->SetImage(CPDF_DocPageData::FromDocument(m_pDocument)
822 ->GetImage(m_pLastImage->GetStream()->GetObjNum()));
823
824 return AddImageObject(std::move(pImageObj));
825 }
826
AddImageObject(std::unique_ptr<CPDF_ImageObject> pImageObj)827 CPDF_ImageObject* CPDF_StreamContentParser::AddImageObject(
828 std::unique_ptr<CPDF_ImageObject> pImageObj) {
829 SetGraphicStates(pImageObj.get(), pImageObj->GetImage()->IsMask(), false,
830 false);
831
832 CFX_Matrix ImageMatrix = m_pCurStates->m_CTM * m_mtContentToUser;
833 pImageObj->SetImageMatrix(ImageMatrix);
834
835 CPDF_ImageObject* pRet = pImageObj.get();
836 m_pObjectHolder->AppendPageObject(std::move(pImageObj));
837 return pRet;
838 }
839
GetColors() const840 std::vector<float> CPDF_StreamContentParser::GetColors() const {
841 DCHECK(m_ParamCount > 0);
842 return GetNumbers(m_ParamCount);
843 }
844
GetNamedColors() const845 std::vector<float> CPDF_StreamContentParser::GetNamedColors() const {
846 DCHECK(m_ParamCount > 0);
847 const uint32_t nvalues = m_ParamCount - 1;
848 std::vector<float> values(nvalues);
849 for (size_t i = 0; i < nvalues; ++i)
850 values[i] = GetNumber(m_ParamCount - i - 1);
851 return values;
852 }
853
Handle_MarkPlace_Dictionary()854 void CPDF_StreamContentParser::Handle_MarkPlace_Dictionary() {}
855
Handle_EndImage()856 void CPDF_StreamContentParser::Handle_EndImage() {}
857
Handle_EndMarkedContent()858 void CPDF_StreamContentParser::Handle_EndMarkedContent() {
859 // First element is a sentinel, so do not pop it, ever. This may come up if
860 // the EMCs are mismatched with the BMC/BDCs.
861 if (m_ContentMarksStack.size() > 1)
862 m_ContentMarksStack.pop();
863 }
864
Handle_EndText()865 void CPDF_StreamContentParser::Handle_EndText() {
866 if (m_ClipTextList.empty())
867 return;
868
869 if (TextRenderingModeIsClipMode(m_pCurStates->m_TextState.GetTextMode()))
870 m_pCurStates->m_ClipPath.AppendTexts(&m_ClipTextList);
871
872 m_ClipTextList.clear();
873 }
874
Handle_FillPath()875 void CPDF_StreamContentParser::Handle_FillPath() {
876 AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kFill);
877 }
878
Handle_FillPathOld()879 void CPDF_StreamContentParser::Handle_FillPathOld() {
880 AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kFill);
881 }
882
Handle_EOFillPath()883 void CPDF_StreamContentParser::Handle_EOFillPath() {
884 AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kFill);
885 }
886
Handle_SetGray_Fill()887 void CPDF_StreamContentParser::Handle_SetGray_Fill() {
888 m_pCurStates->m_ColorState.SetFillColor(
889 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray),
890 GetNumbers(1));
891 }
892
Handle_SetGray_Stroke()893 void CPDF_StreamContentParser::Handle_SetGray_Stroke() {
894 m_pCurStates->m_ColorState.SetStrokeColor(
895 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray),
896 GetNumbers(1));
897 }
898
Handle_SetExtendGraphState()899 void CPDF_StreamContentParser::Handle_SetExtendGraphState() {
900 ByteString name = GetString(0);
901 RetainPtr<CPDF_Dictionary> pGS =
902 ToDictionary(FindResourceObj("ExtGState", name));
903 if (!pGS)
904 return;
905
906 m_pCurStates->m_GraphicsResourceName = name;
907 m_pCurStates->ProcessExtGS(pGS.Get(), this);
908 }
909
Handle_ClosePath()910 void CPDF_StreamContentParser::Handle_ClosePath() {
911 if (m_PathPoints.empty())
912 return;
913
914 if (m_PathStart.x != m_PathCurrent.x || m_PathStart.y != m_PathCurrent.y) {
915 AddPathPointAndClose(m_PathStart, CFX_Path::Point::Type::kLine);
916 } else {
917 m_PathPoints.back().m_CloseFigure = true;
918 }
919 }
920
Handle_SetFlat()921 void CPDF_StreamContentParser::Handle_SetFlat() {
922 m_pCurStates->m_GeneralState.SetFlatness(GetNumber(0));
923 }
924
Handle_BeginImageData()925 void CPDF_StreamContentParser::Handle_BeginImageData() {}
926
Handle_SetLineJoin()927 void CPDF_StreamContentParser::Handle_SetLineJoin() {
928 m_pCurStates->m_GraphState.SetLineJoin(
929 static_cast<CFX_GraphStateData::LineJoin>(GetInteger(0)));
930 }
931
Handle_SetLineCap()932 void CPDF_StreamContentParser::Handle_SetLineCap() {
933 m_pCurStates->m_GraphState.SetLineCap(
934 static_cast<CFX_GraphStateData::LineCap>(GetInteger(0)));
935 }
936
Handle_SetCMYKColor_Fill()937 void CPDF_StreamContentParser::Handle_SetCMYKColor_Fill() {
938 if (m_ParamCount != 4)
939 return;
940
941 m_pCurStates->m_ColorState.SetFillColor(
942 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK),
943 GetNumbers(4));
944 }
945
Handle_SetCMYKColor_Stroke()946 void CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke() {
947 if (m_ParamCount != 4)
948 return;
949
950 m_pCurStates->m_ColorState.SetStrokeColor(
951 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK),
952 GetNumbers(4));
953 }
954
Handle_LineTo()955 void CPDF_StreamContentParser::Handle_LineTo() {
956 if (m_ParamCount != 2)
957 return;
958
959 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kLine);
960 }
961
Handle_MoveTo()962 void CPDF_StreamContentParser::Handle_MoveTo() {
963 if (m_ParamCount != 2)
964 return;
965
966 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kMove);
967 ParsePathObject();
968 }
969
Handle_SetMiterLimit()970 void CPDF_StreamContentParser::Handle_SetMiterLimit() {
971 m_pCurStates->m_GraphState.SetMiterLimit(GetNumber(0));
972 }
973
Handle_MarkPlace()974 void CPDF_StreamContentParser::Handle_MarkPlace() {}
975
Handle_EndPath()976 void CPDF_StreamContentParser::Handle_EndPath() {
977 AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kFill);
978 }
979
Handle_SaveGraphState()980 void CPDF_StreamContentParser::Handle_SaveGraphState() {
981 auto pStates = std::make_unique<CPDF_AllStates>();
982 pStates->Copy(*m_pCurStates);
983 m_StateStack.push_back(std::move(pStates));
984 }
985
Handle_RestoreGraphState()986 void CPDF_StreamContentParser::Handle_RestoreGraphState() {
987 if (m_StateStack.empty())
988 return;
989 std::unique_ptr<CPDF_AllStates> pStates = std::move(m_StateStack.back());
990 m_StateStack.pop_back();
991 m_pCurStates->Copy(*pStates);
992 }
993
Handle_Rectangle()994 void CPDF_StreamContentParser::Handle_Rectangle() {
995 float x = GetNumber(3);
996 float y = GetNumber(2);
997 float w = GetNumber(1);
998 float h = GetNumber(0);
999 AddPathRect(x, y, w, h);
1000 }
1001
AddPathRect(float x,float y,float w,float h)1002 void CPDF_StreamContentParser::AddPathRect(float x, float y, float w, float h) {
1003 AddPathPoint({x, y}, CFX_Path::Point::Type::kMove);
1004 AddPathPoint({x + w, y}, CFX_Path::Point::Type::kLine);
1005 AddPathPoint({x + w, y + h}, CFX_Path::Point::Type::kLine);
1006 AddPathPoint({x, y + h}, CFX_Path::Point::Type::kLine);
1007 AddPathPointAndClose({x, y}, CFX_Path::Point::Type::kLine);
1008 }
1009
Handle_SetRGBColor_Fill()1010 void CPDF_StreamContentParser::Handle_SetRGBColor_Fill() {
1011 if (m_ParamCount != 3)
1012 return;
1013
1014 m_pCurStates->m_ColorState.SetFillColor(
1015 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB),
1016 GetNumbers(3));
1017 }
1018
Handle_SetRGBColor_Stroke()1019 void CPDF_StreamContentParser::Handle_SetRGBColor_Stroke() {
1020 if (m_ParamCount != 3)
1021 return;
1022
1023 m_pCurStates->m_ColorState.SetStrokeColor(
1024 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB),
1025 GetNumbers(3));
1026 }
1027
Handle_SetRenderIntent()1028 void CPDF_StreamContentParser::Handle_SetRenderIntent() {}
1029
Handle_CloseStrokePath()1030 void CPDF_StreamContentParser::Handle_CloseStrokePath() {
1031 Handle_ClosePath();
1032 AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kStroke);
1033 }
1034
Handle_StrokePath()1035 void CPDF_StreamContentParser::Handle_StrokePath() {
1036 AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kStroke);
1037 }
1038
Handle_SetColor_Fill()1039 void CPDF_StreamContentParser::Handle_SetColor_Fill() {
1040 int nargs = std::min(m_ParamCount, 4U);
1041 m_pCurStates->m_ColorState.SetFillColor(nullptr, GetNumbers(nargs));
1042 }
1043
Handle_SetColor_Stroke()1044 void CPDF_StreamContentParser::Handle_SetColor_Stroke() {
1045 int nargs = std::min(m_ParamCount, 4U);
1046 m_pCurStates->m_ColorState.SetStrokeColor(nullptr, GetNumbers(nargs));
1047 }
1048
Handle_SetColorPS_Fill()1049 void CPDF_StreamContentParser::Handle_SetColorPS_Fill() {
1050 RetainPtr<CPDF_Object> pLastParam = GetObject(0);
1051 if (!pLastParam)
1052 return;
1053
1054 if (!pLastParam->IsName()) {
1055 m_pCurStates->m_ColorState.SetFillColor(nullptr, GetColors());
1056 return;
1057 }
1058
1059 // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call
1060 // below is safe.
1061 RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0));
1062 if (!pPattern)
1063 return;
1064
1065 std::vector<float> values = GetNamedColors();
1066 m_pCurStates->m_ColorState.SetFillPattern(std::move(pPattern), values);
1067 }
1068
Handle_SetColorPS_Stroke()1069 void CPDF_StreamContentParser::Handle_SetColorPS_Stroke() {
1070 RetainPtr<CPDF_Object> pLastParam = GetObject(0);
1071 if (!pLastParam)
1072 return;
1073
1074 if (!pLastParam->IsName()) {
1075 m_pCurStates->m_ColorState.SetStrokeColor(nullptr, GetColors());
1076 return;
1077 }
1078
1079 // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call
1080 // below is safe.
1081 RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0));
1082 if (!pPattern)
1083 return;
1084
1085 std::vector<float> values = GetNamedColors();
1086 m_pCurStates->m_ColorState.SetStrokePattern(std::move(pPattern), values);
1087 }
1088
Handle_ShadeFill()1089 void CPDF_StreamContentParser::Handle_ShadeFill() {
1090 RetainPtr<CPDF_ShadingPattern> pShading = FindShading(GetString(0));
1091 if (!pShading)
1092 return;
1093
1094 if (!pShading->IsShadingObject() || !pShading->Load())
1095 return;
1096
1097 CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser;
1098 auto pObj = std::make_unique<CPDF_ShadingObject>(GetCurrentStreamIndex(),
1099 pShading, matrix);
1100 SetGraphicStates(pObj.get(), false, false, false);
1101 CFX_FloatRect bbox =
1102 pObj->m_ClipPath.HasRef() ? pObj->m_ClipPath.GetClipBox() : m_BBox;
1103 if (pShading->IsMeshShading())
1104 bbox.Intersect(GetShadingBBox(pShading.Get(), pObj->matrix()));
1105 pObj->SetRect(bbox);
1106 m_pObjectHolder->AppendPageObject(std::move(pObj));
1107 }
1108
Handle_SetCharSpace()1109 void CPDF_StreamContentParser::Handle_SetCharSpace() {
1110 m_pCurStates->m_TextState.SetCharSpace(GetNumber(0));
1111 }
1112
Handle_MoveTextPoint()1113 void CPDF_StreamContentParser::Handle_MoveTextPoint() {
1114 m_pCurStates->m_TextLinePos += GetPoint(0);
1115 m_pCurStates->m_TextPos = m_pCurStates->m_TextLinePos;
1116 }
1117
Handle_MoveTextPoint_SetLeading()1118 void CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading() {
1119 Handle_MoveTextPoint();
1120 m_pCurStates->m_TextLeading = -GetNumber(0);
1121 }
1122
Handle_SetFont()1123 void CPDF_StreamContentParser::Handle_SetFont() {
1124 m_pCurStates->m_TextState.SetFontSize(GetNumber(0));
1125 RetainPtr<CPDF_Font> pFont = FindFont(GetString(1));
1126 if (pFont)
1127 m_pCurStates->m_TextState.SetFont(std::move(pFont));
1128 }
1129
FindResourceHolder(const ByteString & type)1130 RetainPtr<CPDF_Dictionary> CPDF_StreamContentParser::FindResourceHolder(
1131 const ByteString& type) {
1132 if (!m_pResources)
1133 return nullptr;
1134
1135 RetainPtr<CPDF_Dictionary> pDict = m_pResources->GetMutableDictFor(type);
1136 if (pDict)
1137 return pDict;
1138
1139 if (m_pResources == m_pPageResources || !m_pPageResources)
1140 return nullptr;
1141
1142 return m_pPageResources->GetMutableDictFor(type);
1143 }
1144
FindResourceObj(const ByteString & type,const ByteString & name)1145 RetainPtr<CPDF_Object> CPDF_StreamContentParser::FindResourceObj(
1146 const ByteString& type,
1147 const ByteString& name) {
1148 RetainPtr<CPDF_Dictionary> pHolder = FindResourceHolder(type);
1149 return pHolder ? pHolder->GetMutableDirectObjectFor(name) : nullptr;
1150 }
1151
FindFont(const ByteString & name)1152 RetainPtr<CPDF_Font> CPDF_StreamContentParser::FindFont(
1153 const ByteString& name) {
1154 RetainPtr<CPDF_Dictionary> pFontDict(
1155 ToDictionary(FindResourceObj("Font", name)));
1156 if (!pFontDict) {
1157 return CPDF_Font::GetStockFont(m_pDocument, CFX_Font::kDefaultAnsiFontName);
1158 }
1159 RetainPtr<CPDF_Font> pFont = CPDF_DocPageData::FromDocument(m_pDocument)
1160 ->GetFont(std::move(pFontDict));
1161 if (pFont) {
1162 // Save `name` for later retrieval by the CPDF_TextObject that uses the
1163 // font.
1164 pFont->SetResourceName(name);
1165 if (pFont->IsType3Font()) {
1166 pFont->AsType3Font()->SetPageResources(m_pResources.Get());
1167 pFont->AsType3Font()->CheckType3FontMetrics();
1168 }
1169 }
1170 return pFont;
1171 }
1172
FindColorSpace(const ByteString & name)1173 RetainPtr<CPDF_ColorSpace> CPDF_StreamContentParser::FindColorSpace(
1174 const ByteString& name) {
1175 if (name == "Pattern")
1176 return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kPattern);
1177
1178 if (name == "DeviceGray" || name == "DeviceCMYK" || name == "DeviceRGB") {
1179 ByteString defname = "Default";
1180 defname += name.Last(name.GetLength() - 7);
1181 RetainPtr<const CPDF_Object> pDefObj =
1182 FindResourceObj("ColorSpace", defname);
1183 if (!pDefObj) {
1184 if (name == "DeviceGray") {
1185 return CPDF_ColorSpace::GetStockCS(
1186 CPDF_ColorSpace::Family::kDeviceGray);
1187 }
1188 if (name == "DeviceRGB")
1189 return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB);
1190
1191 return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK);
1192 }
1193 return CPDF_DocPageData::FromDocument(m_pDocument)
1194 ->GetColorSpace(pDefObj.Get(), nullptr);
1195 }
1196 RetainPtr<const CPDF_Object> pCSObj = FindResourceObj("ColorSpace", name);
1197 if (!pCSObj)
1198 return nullptr;
1199 return CPDF_DocPageData::FromDocument(m_pDocument)
1200 ->GetColorSpace(pCSObj.Get(), nullptr);
1201 }
1202
FindPattern(const ByteString & name)1203 RetainPtr<CPDF_Pattern> CPDF_StreamContentParser::FindPattern(
1204 const ByteString& name) {
1205 RetainPtr<CPDF_Object> pPattern = FindResourceObj("Pattern", name);
1206 if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream()))
1207 return nullptr;
1208 return CPDF_DocPageData::FromDocument(m_pDocument)
1209 ->GetPattern(std::move(pPattern), m_pCurStates->m_ParentMatrix);
1210 }
1211
FindShading(const ByteString & name)1212 RetainPtr<CPDF_ShadingPattern> CPDF_StreamContentParser::FindShading(
1213 const ByteString& name) {
1214 RetainPtr<CPDF_Object> pPattern = FindResourceObj("Shading", name);
1215 if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream()))
1216 return nullptr;
1217 return CPDF_DocPageData::FromDocument(m_pDocument)
1218 ->GetShading(std::move(pPattern), m_pCurStates->m_ParentMatrix);
1219 }
1220
AddTextObject(const ByteString * pStrs,float fInitKerning,const std::vector<float> & kernings,size_t nSegs)1221 void CPDF_StreamContentParser::AddTextObject(const ByteString* pStrs,
1222 float fInitKerning,
1223 const std::vector<float>& kernings,
1224 size_t nSegs) {
1225 RetainPtr<CPDF_Font> pFont = m_pCurStates->m_TextState.GetFont();
1226 if (!pFont)
1227 return;
1228
1229 if (fInitKerning != 0) {
1230 if (pFont->IsVertWriting())
1231 m_pCurStates->m_TextPos.y -= GetVerticalTextSize(fInitKerning);
1232 else
1233 m_pCurStates->m_TextPos.x -= GetHorizontalTextSize(fInitKerning);
1234 }
1235 if (nSegs == 0)
1236 return;
1237
1238 const TextRenderingMode text_mode =
1239 pFont->IsType3Font() ? TextRenderingMode::MODE_FILL
1240 : m_pCurStates->m_TextState.GetTextMode();
1241 {
1242 auto pText = std::make_unique<CPDF_TextObject>(GetCurrentStreamIndex());
1243 pText->SetResourceName(pFont->GetResourceName());
1244 SetGraphicStates(pText.get(), true, true, true);
1245 if (TextRenderingModeIsStrokeMode(text_mode)) {
1246 pdfium::span<float> pCTM = pText->m_TextState.GetMutableCTM();
1247 pCTM[0] = m_pCurStates->m_CTM.a;
1248 pCTM[1] = m_pCurStates->m_CTM.c;
1249 pCTM[2] = m_pCurStates->m_CTM.b;
1250 pCTM[3] = m_pCurStates->m_CTM.d;
1251 }
1252 pText->SetSegments(pStrs, kernings, nSegs);
1253 pText->SetPosition(
1254 m_mtContentToUser.Transform(m_pCurStates->m_CTM.Transform(
1255 m_pCurStates->m_TextMatrix.Transform(CFX_PointF(
1256 m_pCurStates->m_TextPos.x,
1257 m_pCurStates->m_TextPos.y + m_pCurStates->m_TextRise)))));
1258
1259 m_pCurStates->m_TextPos +=
1260 pText->CalcPositionData(m_pCurStates->m_TextHorzScale);
1261 if (TextRenderingModeIsClipMode(text_mode))
1262 m_ClipTextList.push_back(pText->Clone());
1263 m_pObjectHolder->AppendPageObject(std::move(pText));
1264 }
1265 if (!kernings.empty() && kernings[nSegs - 1] != 0) {
1266 if (pFont->IsVertWriting())
1267 m_pCurStates->m_TextPos.y -= GetVerticalTextSize(kernings[nSegs - 1]);
1268 else
1269 m_pCurStates->m_TextPos.x -= GetHorizontalTextSize(kernings[nSegs - 1]);
1270 }
1271 }
1272
GetHorizontalTextSize(float fKerning) const1273 float CPDF_StreamContentParser::GetHorizontalTextSize(float fKerning) const {
1274 return GetVerticalTextSize(fKerning) * m_pCurStates->m_TextHorzScale;
1275 }
1276
GetVerticalTextSize(float fKerning) const1277 float CPDF_StreamContentParser::GetVerticalTextSize(float fKerning) const {
1278 return fKerning * m_pCurStates->m_TextState.GetFontSize() / 1000;
1279 }
1280
GetCurrentStreamIndex()1281 int32_t CPDF_StreamContentParser::GetCurrentStreamIndex() {
1282 auto it =
1283 std::upper_bound(m_StreamStartOffsets.begin(), m_StreamStartOffsets.end(),
1284 m_pSyntax->GetPos() + m_StartParseOffset);
1285 return (it - m_StreamStartOffsets.begin()) - 1;
1286 }
1287
Handle_ShowText()1288 void CPDF_StreamContentParser::Handle_ShowText() {
1289 ByteString str = GetString(0);
1290 if (!str.IsEmpty())
1291 AddTextObject(&str, 0, std::vector<float>(), 1);
1292 }
1293
Handle_ShowText_Positioning()1294 void CPDF_StreamContentParser::Handle_ShowText_Positioning() {
1295 RetainPtr<CPDF_Array> pArray = ToArray(GetObject(0));
1296 if (!pArray)
1297 return;
1298
1299 size_t n = pArray->size();
1300 size_t nsegs = 0;
1301 for (size_t i = 0; i < n; i++) {
1302 RetainPtr<const CPDF_Object> pDirectObject = pArray->GetDirectObjectAt(i);
1303 if (pDirectObject && pDirectObject->IsString())
1304 nsegs++;
1305 }
1306 if (nsegs == 0) {
1307 for (size_t i = 0; i < n; i++) {
1308 float fKerning = pArray->GetFloatAt(i);
1309 if (fKerning != 0)
1310 m_pCurStates->m_TextPos.x -= GetHorizontalTextSize(fKerning);
1311 }
1312 return;
1313 }
1314 std::vector<ByteString> strs(nsegs);
1315 std::vector<float> kernings(nsegs);
1316 size_t iSegment = 0;
1317 float fInitKerning = 0;
1318 for (size_t i = 0; i < n; i++) {
1319 RetainPtr<const CPDF_Object> pObj = pArray->GetDirectObjectAt(i);
1320 if (!pObj)
1321 continue;
1322
1323 if (pObj->IsString()) {
1324 ByteString str = pObj->GetString();
1325 if (str.IsEmpty())
1326 continue;
1327 strs[iSegment] = std::move(str);
1328 kernings[iSegment++] = 0;
1329 } else {
1330 float num = pObj->GetNumber();
1331 if (iSegment == 0)
1332 fInitKerning += num;
1333 else
1334 kernings[iSegment - 1] += num;
1335 }
1336 }
1337 AddTextObject(strs.data(), fInitKerning, kernings, iSegment);
1338 }
1339
Handle_SetTextLeading()1340 void CPDF_StreamContentParser::Handle_SetTextLeading() {
1341 m_pCurStates->m_TextLeading = GetNumber(0);
1342 }
1343
Handle_SetTextMatrix()1344 void CPDF_StreamContentParser::Handle_SetTextMatrix() {
1345 m_pCurStates->m_TextMatrix = GetMatrix();
1346 OnChangeTextMatrix();
1347 m_pCurStates->m_TextPos = CFX_PointF();
1348 m_pCurStates->m_TextLinePos = CFX_PointF();
1349 }
1350
OnChangeTextMatrix()1351 void CPDF_StreamContentParser::OnChangeTextMatrix() {
1352 CFX_Matrix text_matrix(m_pCurStates->m_TextHorzScale, 0.0f, 0.0f, 1.0f, 0.0f,
1353 0.0f);
1354 text_matrix.Concat(m_pCurStates->m_TextMatrix);
1355 text_matrix.Concat(m_pCurStates->m_CTM);
1356 text_matrix.Concat(m_mtContentToUser);
1357 pdfium::span<float> pTextMatrix =
1358 m_pCurStates->m_TextState.GetMutableMatrix();
1359 pTextMatrix[0] = text_matrix.a;
1360 pTextMatrix[1] = text_matrix.c;
1361 pTextMatrix[2] = text_matrix.b;
1362 pTextMatrix[3] = text_matrix.d;
1363 }
1364
Handle_SetTextRenderMode()1365 void CPDF_StreamContentParser::Handle_SetTextRenderMode() {
1366 TextRenderingMode mode;
1367 if (SetTextRenderingModeFromInt(GetInteger(0), &mode))
1368 m_pCurStates->m_TextState.SetTextMode(mode);
1369 }
1370
Handle_SetTextRise()1371 void CPDF_StreamContentParser::Handle_SetTextRise() {
1372 m_pCurStates->m_TextRise = GetNumber(0);
1373 }
1374
Handle_SetWordSpace()1375 void CPDF_StreamContentParser::Handle_SetWordSpace() {
1376 m_pCurStates->m_TextState.SetWordSpace(GetNumber(0));
1377 }
1378
Handle_SetHorzScale()1379 void CPDF_StreamContentParser::Handle_SetHorzScale() {
1380 if (m_ParamCount != 1) {
1381 return;
1382 }
1383 m_pCurStates->m_TextHorzScale = GetNumber(0) / 100;
1384 OnChangeTextMatrix();
1385 }
1386
Handle_MoveToNextLine()1387 void CPDF_StreamContentParser::Handle_MoveToNextLine() {
1388 m_pCurStates->m_TextLinePos.y -= m_pCurStates->m_TextLeading;
1389 m_pCurStates->m_TextPos = m_pCurStates->m_TextLinePos;
1390 }
1391
Handle_CurveTo_23()1392 void CPDF_StreamContentParser::Handle_CurveTo_23() {
1393 AddPathPoint(m_PathCurrent, CFX_Path::Point::Type::kBezier);
1394 AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier);
1395 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier);
1396 }
1397
Handle_SetLineWidth()1398 void CPDF_StreamContentParser::Handle_SetLineWidth() {
1399 m_pCurStates->m_GraphState.SetLineWidth(GetNumber(0));
1400 }
1401
Handle_Clip()1402 void CPDF_StreamContentParser::Handle_Clip() {
1403 m_PathClipType = CFX_FillRenderOptions::FillType::kWinding;
1404 }
1405
Handle_EOClip()1406 void CPDF_StreamContentParser::Handle_EOClip() {
1407 m_PathClipType = CFX_FillRenderOptions::FillType::kEvenOdd;
1408 }
1409
Handle_CurveTo_13()1410 void CPDF_StreamContentParser::Handle_CurveTo_13() {
1411 AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier);
1412 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier);
1413 AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier);
1414 }
1415
Handle_NextLineShowText()1416 void CPDF_StreamContentParser::Handle_NextLineShowText() {
1417 Handle_MoveToNextLine();
1418 Handle_ShowText();
1419 }
1420
Handle_NextLineShowText_Space()1421 void CPDF_StreamContentParser::Handle_NextLineShowText_Space() {
1422 m_pCurStates->m_TextState.SetWordSpace(GetNumber(2));
1423 m_pCurStates->m_TextState.SetCharSpace(GetNumber(1));
1424 Handle_NextLineShowText();
1425 }
1426
Handle_Invalid()1427 void CPDF_StreamContentParser::Handle_Invalid() {}
1428
AddPathPoint(const CFX_PointF & point,CFX_Path::Point::Type type)1429 void CPDF_StreamContentParser::AddPathPoint(const CFX_PointF& point,
1430 CFX_Path::Point::Type type) {
1431 // If the path point is the same move as the previous one and neither of them
1432 // closes the path, then just skip it.
1433 if (type == CFX_Path::Point::Type::kMove && !m_PathPoints.empty() &&
1434 !m_PathPoints.back().m_CloseFigure &&
1435 m_PathPoints.back().m_Type == type && m_PathCurrent == point) {
1436 return;
1437 }
1438
1439 m_PathCurrent = point;
1440 if (type == CFX_Path::Point::Type::kMove) {
1441 m_PathStart = point;
1442 if (!m_PathPoints.empty() &&
1443 m_PathPoints.back().IsTypeAndOpen(CFX_Path::Point::Type::kMove)) {
1444 m_PathPoints.back().m_Point = point;
1445 return;
1446 }
1447 } else if (m_PathPoints.empty()) {
1448 return;
1449 }
1450 m_PathPoints.emplace_back(point, type, /*close=*/false);
1451 }
1452
AddPathPointAndClose(const CFX_PointF & point,CFX_Path::Point::Type type)1453 void CPDF_StreamContentParser::AddPathPointAndClose(
1454 const CFX_PointF& point,
1455 CFX_Path::Point::Type type) {
1456 m_PathCurrent = point;
1457 if (m_PathPoints.empty())
1458 return;
1459
1460 m_PathPoints.emplace_back(point, type, /*close=*/true);
1461 }
1462
AddPathObject(CFX_FillRenderOptions::FillType fill_type,RenderType render_type)1463 void CPDF_StreamContentParser::AddPathObject(
1464 CFX_FillRenderOptions::FillType fill_type,
1465 RenderType render_type) {
1466 std::vector<CFX_Path::Point> path_points;
1467 path_points.swap(m_PathPoints);
1468 CFX_FillRenderOptions::FillType path_clip_type = m_PathClipType;
1469 m_PathClipType = CFX_FillRenderOptions::FillType::kNoFill;
1470
1471 if (path_points.empty())
1472 return;
1473
1474 if (path_points.size() == 1) {
1475 if (path_clip_type != CFX_FillRenderOptions::FillType::kNoFill) {
1476 CPDF_Path path;
1477 path.AppendRect(0, 0, 0, 0);
1478 m_pCurStates->m_ClipPath.AppendPathWithAutoMerge(
1479 path, CFX_FillRenderOptions::FillType::kWinding);
1480 return;
1481 }
1482
1483 CFX_Path::Point& point = path_points.front();
1484 if (point.m_Type != CFX_Path::Point::Type::kMove || !point.m_CloseFigure ||
1485 m_pCurStates->m_GraphState.GetLineCap() !=
1486 CFX_GraphStateData::LineCap::kRound) {
1487 return;
1488 }
1489
1490 // For round line cap only: When a path moves to a point and immediately
1491 // gets closed, we can treat it as drawing a path from this point to itself
1492 // and closing the path. This should not apply to butt line cap or
1493 // projecting square line cap since they should not be rendered.
1494 point.m_CloseFigure = false;
1495 path_points.emplace_back(point.m_Point, CFX_Path::Point::Type::kLine,
1496 /*close=*/true);
1497 }
1498
1499 if (path_points.back().IsTypeAndOpen(CFX_Path::Point::Type::kMove))
1500 path_points.pop_back();
1501
1502 CPDF_Path path;
1503 for (const auto& point : path_points) {
1504 if (point.m_CloseFigure)
1505 path.AppendPointAndClose(point.m_Point, point.m_Type);
1506 else
1507 path.AppendPoint(point.m_Point, point.m_Type);
1508 }
1509
1510 CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser;
1511 bool bStroke = render_type == RenderType::kStroke;
1512 if (bStroke || fill_type != CFX_FillRenderOptions::FillType::kNoFill) {
1513 auto pPathObj = std::make_unique<CPDF_PathObject>(GetCurrentStreamIndex());
1514 pPathObj->set_stroke(bStroke);
1515 pPathObj->set_filltype(fill_type);
1516 pPathObj->path() = path;
1517 SetGraphicStates(pPathObj.get(), true, false, true);
1518 pPathObj->SetPathMatrix(matrix);
1519 m_pObjectHolder->AppendPageObject(std::move(pPathObj));
1520 }
1521 if (path_clip_type != CFX_FillRenderOptions::FillType::kNoFill) {
1522 if (!matrix.IsIdentity())
1523 path.Transform(matrix);
1524 m_pCurStates->m_ClipPath.AppendPathWithAutoMerge(path, path_clip_type);
1525 }
1526 }
1527
Parse(pdfium::span<const uint8_t> pData,uint32_t start_offset,uint32_t max_cost,const std::vector<uint32_t> & stream_start_offsets)1528 uint32_t CPDF_StreamContentParser::Parse(
1529 pdfium::span<const uint8_t> pData,
1530 uint32_t start_offset,
1531 uint32_t max_cost,
1532 const std::vector<uint32_t>& stream_start_offsets) {
1533 DCHECK(start_offset < pData.size());
1534
1535 // Parsing will be done from within |pDataStart|.
1536 pdfium::span<const uint8_t> pDataStart = pData.subspan(start_offset);
1537 m_StartParseOffset = start_offset;
1538 if (m_ParsedSet->size() > kMaxFormLevel ||
1539 pdfium::Contains(*m_ParsedSet, pDataStart.data())) {
1540 return fxcrt::CollectionSize<uint32_t>(pDataStart);
1541 }
1542
1543 m_StreamStartOffsets = stream_start_offsets;
1544
1545 ScopedSetInsertion<const uint8_t*> scopedInsert(m_ParsedSet,
1546 pDataStart.data());
1547
1548 uint32_t init_obj_count = m_pObjectHolder->GetPageObjectCount();
1549 AutoNuller<std::unique_ptr<CPDF_StreamParser>> auto_clearer(&m_pSyntax);
1550 m_pSyntax = std::make_unique<CPDF_StreamParser>(
1551 pDataStart, m_pDocument->GetByteStringPool());
1552
1553 while (true) {
1554 uint32_t cost = m_pObjectHolder->GetPageObjectCount() - init_obj_count;
1555 if (max_cost && cost >= max_cost) {
1556 break;
1557 }
1558 switch (m_pSyntax->ParseNextElement()) {
1559 case CPDF_StreamParser::ElementType::kEndOfData:
1560 return m_pSyntax->GetPos();
1561 case CPDF_StreamParser::ElementType::kKeyword:
1562 OnOperator(m_pSyntax->GetWord());
1563 ClearAllParams();
1564 break;
1565 case CPDF_StreamParser::ElementType::kNumber:
1566 AddNumberParam(m_pSyntax->GetWord());
1567 break;
1568 case CPDF_StreamParser::ElementType::kName: {
1569 auto word = m_pSyntax->GetWord();
1570 AddNameParam(word.Last(word.GetLength() - 1));
1571 break;
1572 }
1573 default:
1574 AddObjectParam(m_pSyntax->GetObject());
1575 }
1576 }
1577 return m_pSyntax->GetPos();
1578 }
1579
ParsePathObject()1580 void CPDF_StreamContentParser::ParsePathObject() {
1581 float params[6] = {};
1582 int nParams = 0;
1583 int last_pos = m_pSyntax->GetPos();
1584 while (true) {
1585 CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement();
1586 bool bProcessed = true;
1587 switch (type) {
1588 case CPDF_StreamParser::ElementType::kEndOfData:
1589 return;
1590 case CPDF_StreamParser::ElementType::kKeyword: {
1591 ByteStringView strc = m_pSyntax->GetWord();
1592 int len = strc.GetLength();
1593 if (len == 1) {
1594 switch (strc[0]) {
1595 case kPathOperatorSubpath:
1596 AddPathPoint({params[0], params[1]},
1597 CFX_Path::Point::Type::kMove);
1598 nParams = 0;
1599 break;
1600 case kPathOperatorLine:
1601 AddPathPoint({params[0], params[1]},
1602 CFX_Path::Point::Type::kLine);
1603 nParams = 0;
1604 break;
1605 case kPathOperatorCubicBezier1:
1606 AddPathPoint({params[0], params[1]},
1607 CFX_Path::Point::Type::kBezier);
1608 AddPathPoint({params[2], params[3]},
1609 CFX_Path::Point::Type::kBezier);
1610 AddPathPoint({params[4], params[5]},
1611 CFX_Path::Point::Type::kBezier);
1612 nParams = 0;
1613 break;
1614 case kPathOperatorCubicBezier2:
1615 AddPathPoint(m_PathCurrent, CFX_Path::Point::Type::kBezier);
1616 AddPathPoint({params[0], params[1]},
1617 CFX_Path::Point::Type::kBezier);
1618 AddPathPoint({params[2], params[3]},
1619 CFX_Path::Point::Type::kBezier);
1620 nParams = 0;
1621 break;
1622 case kPathOperatorCubicBezier3:
1623 AddPathPoint({params[0], params[1]},
1624 CFX_Path::Point::Type::kBezier);
1625 AddPathPoint({params[2], params[3]},
1626 CFX_Path::Point::Type::kBezier);
1627 AddPathPoint({params[2], params[3]},
1628 CFX_Path::Point::Type::kBezier);
1629 nParams = 0;
1630 break;
1631 case kPathOperatorClosePath:
1632 Handle_ClosePath();
1633 nParams = 0;
1634 break;
1635 default:
1636 bProcessed = false;
1637 break;
1638 }
1639 } else if (len == 2) {
1640 if (strc[0] == kPathOperatorRectangle[0] &&
1641 strc[1] == kPathOperatorRectangle[1]) {
1642 AddPathRect(params[0], params[1], params[2], params[3]);
1643 nParams = 0;
1644 } else {
1645 bProcessed = false;
1646 }
1647 } else {
1648 bProcessed = false;
1649 }
1650 if (bProcessed) {
1651 last_pos = m_pSyntax->GetPos();
1652 }
1653 break;
1654 }
1655 case CPDF_StreamParser::ElementType::kNumber: {
1656 if (nParams == 6)
1657 break;
1658
1659 FX_Number number(m_pSyntax->GetWord());
1660 params[nParams++] = number.GetFloat();
1661 break;
1662 }
1663 default:
1664 bProcessed = false;
1665 }
1666 if (!bProcessed) {
1667 m_pSyntax->SetPos(last_pos);
1668 return;
1669 }
1670 }
1671 }
1672
1673 // static
FindKeyAbbreviationForTesting(ByteStringView abbr)1674 ByteStringView CPDF_StreamContentParser::FindKeyAbbreviationForTesting(
1675 ByteStringView abbr) {
1676 return FindFullName(kInlineKeyAbbr, abbr);
1677 }
1678
1679 // static
FindValueAbbreviationForTesting(ByteStringView abbr)1680 ByteStringView CPDF_StreamContentParser::FindValueAbbreviationForTesting(
1681 ByteStringView abbr) {
1682 return FindFullName(kInlineValueAbbr, abbr);
1683 }
1684
1685 CPDF_StreamContentParser::ContentParam::ContentParam() = default;
1686
1687 CPDF_StreamContentParser::ContentParam::~ContentParam() = default;
1688