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