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