Home | History | Annotate | Download | only in page
      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, &param.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