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