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