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