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