• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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