Example #1
0
CPDF_Object* CPDF_ActionFields::GetField(size_t iIndex) const {
  if (!m_pAction)
    return nullptr;

  CPDF_Dictionary* pDict = m_pAction->GetDict();
  if (!pDict)
    return nullptr;

  CFX_ByteString csType = pDict->GetStringFor("S");
  CPDF_Object* pFields = nullptr;
  if (csType == "Hide")
    pFields = pDict->GetDirectObjectFor("T");
  else
    pFields = pDict->GetArrayFor("Fields");

  if (!pFields)
    return nullptr;

  CPDF_Object* pFindObj = nullptr;
  if (pFields->IsDictionary() || pFields->IsString()) {
    if (iIndex == 0)
      pFindObj = pFields;
  } else if (CPDF_Array* pArray = pFields->AsArray()) {
    pFindObj = pArray->GetDirectObjectAt(iIndex);
  }
  return pFindObj;
}
Example #2
0
DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot,
                                                   int quadIndex,
                                                   FS_QUADPOINTSF* quadPoints) {
  if (!linkAnnot || !quadPoints)
    return FALSE;
  CPDF_Dictionary* pAnnotDict =
      ToDictionary(static_cast<CPDF_Object*>(linkAnnot));
  CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints");
  if (pArray) {
    if (quadIndex < 0 ||
        static_cast<size_t>(quadIndex) >= pArray->GetCount() / 8 ||
        (static_cast<size_t>(quadIndex * 8 + 7) >= pArray->GetCount()))
      return FALSE;
    quadPoints->x1 = pArray->GetNumberAt(quadIndex * 8);
    quadPoints->y1 = pArray->GetNumberAt(quadIndex * 8 + 1);
    quadPoints->x2 = pArray->GetNumberAt(quadIndex * 8 + 2);
    quadPoints->y2 = pArray->GetNumberAt(quadIndex * 8 + 3);
    quadPoints->x3 = pArray->GetNumberAt(quadIndex * 8 + 4);
    quadPoints->y3 = pArray->GetNumberAt(quadIndex * 8 + 5);
    quadPoints->x4 = pArray->GetNumberAt(quadIndex * 8 + 6);
    quadPoints->y4 = pArray->GetNumberAt(quadIndex * 8 + 7);
    return TRUE;
  }
  return FALSE;
}
Example #3
0
std::vector<CPDF_Object*> CPDF_ActionFields::GetAllFields() const {
  std::vector<CPDF_Object*> fields;
  if (!m_pAction)
    return fields;

  CPDF_Dictionary* pDict = m_pAction->GetDict();
  if (!pDict)
    return fields;

  CFX_ByteString csType = pDict->GetStringFor("S");
  CPDF_Object* pFields;
  if (csType == "Hide")
    pFields = pDict->GetDirectObjectFor("T");
  else
    pFields = pDict->GetArrayFor("Fields");

  if (!pFields)
    return fields;

  if (pFields->IsDictionary() || pFields->IsString()) {
    fields.push_back(pFields);
  } else if (CPDF_Array* pArray = pFields->AsArray()) {
    for (size_t i = 0; i < pArray->GetCount(); ++i) {
      CPDF_Object* pObj = pArray->GetDirectObjectAt(i);
      if (pObj)
        fields.push_back(pObj);
    }
  }
  return fields;
}
Example #4
0
size_t CPDF_ActionFields::GetFieldsCount() const {
  if (!m_pAction)
    return 0;

  CPDF_Dictionary* pDict = m_pAction->GetDict();
  if (!pDict)
    return 0;

  CFX_ByteString csType = pDict->GetStringFor("S");
  CPDF_Object* pFields = nullptr;
  if (csType == "Hide")
    pFields = pDict->GetDirectObjectFor("T");
  else
    pFields = pDict->GetArrayFor("Fields");

  if (!pFields)
    return 0;
  if (pFields->IsDictionary())
    return 1;
  if (pFields->IsString())
    return 1;
  if (CPDF_Array* pArray = pFields->AsArray())
    return pArray->GetCount();
  return 0;
}
Example #5
0
bool CPDF_OCContext::LoadOCGStateFromConfig(
    const ByteString& csConfig,
    const CPDF_Dictionary* pOCGDict) const {
  CPDF_Dictionary* pConfig = GetConfig(m_pDocument.Get(), pOCGDict);
  if (!pConfig)
    return true;

  bool bState = pConfig->GetStringFor("BaseState", "ON") != "OFF";
  CPDF_Array* pArray = pConfig->GetArrayFor("ON");
  if (pArray) {
    if (FindGroup(pArray, pOCGDict) >= 0)
      bState = true;
  }
  pArray = pConfig->GetArrayFor("OFF");
  if (pArray) {
    if (FindGroup(pArray, pOCGDict) >= 0)
      bState = false;
  }
  pArray = pConfig->GetArrayFor("AS");
  if (!pArray)
    return bState;

  ByteString csFind = csConfig + "State";
  for (size_t i = 0; i < pArray->size(); i++) {
    CPDF_Dictionary* pUsage = pArray->GetDictAt(i);
    if (!pUsage)
      continue;

    if (pUsage->GetStringFor("Event", "View") != csConfig)
      continue;

    CPDF_Array* pOCGs = pUsage->GetArrayFor("OCGs");
    if (!pOCGs)
      continue;

    if (FindGroup(pOCGs, pOCGDict) < 0)
      continue;

    CPDF_Dictionary* pState = pUsage->GetDictFor(csConfig);
    if (!pState)
      continue;

    bState = pState->GetStringFor(csFind) != "OFF";
  }
  return bState;
}
Example #6
0
DLLEXPORT int STDCALL FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot) {
  if (!linkAnnot)
    return 0;
  CPDF_Dictionary* pAnnotDict =
      ToDictionary(static_cast<CPDF_Object*>(linkAnnot));
  CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints");
  if (!pArray)
    return 0;
  return static_cast<int>(pArray->GetCount() / 8);
}
Example #7
0
void CheckUnSupportError(CPDF_Document* pDoc, uint32_t err_code) {
  // Security
  if (err_code == FPDF_ERR_SECURITY) {
    FPDF_UnSupportError(FPDF_UNSP_DOC_SECURITY);
    return;
  }
  if (!pDoc)
    return;

  // Portfolios and Packages
  CPDF_Dictionary* pRootDict = pDoc->GetRoot();
  if (pRootDict) {
    CFX_ByteString cbString;
    if (pRootDict->KeyExist("Collection")) {
      FPDF_UnSupportError(FPDF_UNSP_DOC_PORTABLECOLLECTION);
      return;
    }
    if (pRootDict->KeyExist("Names")) {
      CPDF_Dictionary* pNameDict = pRootDict->GetDictFor("Names");
      if (pNameDict && pNameDict->KeyExist("EmbeddedFiles")) {
        FPDF_UnSupportError(FPDF_UNSP_DOC_ATTACHMENT);
        return;
      }
      if (pNameDict && pNameDict->KeyExist("JavaScript")) {
        CPDF_Dictionary* pJSDict = pNameDict->GetDictFor("JavaScript");
        CPDF_Array* pArray = pJSDict ? pJSDict->GetArrayFor("Names") : nullptr;
        if (pArray) {
          for (size_t i = 0; i < pArray->GetCount(); i++) {
            CFX_ByteString cbStr = pArray->GetStringAt(i);
            if (cbStr.Compare("com.adobe.acrobat.SharedReview.Register") == 0) {
              FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDREVIEW);
              return;
            }
          }
        }
      }
    }
  }

  // SharedForm
  CPDF_Metadata metaData(pDoc);
  const CXML_Element* pElement = metaData.GetRoot();
  if (pElement)
    CheckSharedForm(pElement, "workflowType");

#ifndef PDF_ENABLE_XFA
  // XFA Forms
  CPDF_InterForm interform(pDoc);
  if (interform.HasXFAForm())
    FPDF_UnSupportError(FPDF_UNSP_DOC_XFAFORM);
#endif  // PDF_ENABLE_XFA
}
Example #8
0
void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) {
  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
  if (!pPageDict)
    return;

  CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots");
  if (!pAnnots)
    return;

  for (size_t i = 0; i < pAnnots->GetCount(); i++) {
    CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i);
    if (pAnnot && pAnnot->GetStringFor("Subtype") == "Widget")
      LoadField(pAnnot, 0);
  }
}
Example #9
0
FX_BOOL CPDF_PageOrganizer::PDFDocInit(CPDF_Document* pDestPDFDoc,
                                       CPDF_Document* pSrcPDFDoc) {
  if (!pDestPDFDoc || !pSrcPDFDoc)
    return FALSE;

  CPDF_Dictionary* pNewRoot = pDestPDFDoc->GetRoot();
  if (!pNewRoot)
    return FALSE;

  CPDF_Dictionary* DInfoDict = pDestPDFDoc->GetInfo();
  if (!DInfoDict)
    return FALSE;

  CFX_ByteString producerstr;
  producerstr.Format("PDFium");
  DInfoDict->SetFor("Producer", new CPDF_String(producerstr, FALSE));

  CFX_ByteString cbRootType = pNewRoot->GetStringFor("Type", "");
  if (cbRootType.IsEmpty())
    pNewRoot->SetFor("Type", new CPDF_Name("Catalog"));

  CPDF_Object* pElement = pNewRoot->GetObjectFor("Pages");
  CPDF_Dictionary* pNewPages =
      pElement ? ToDictionary(pElement->GetDirect()) : nullptr;
  if (!pNewPages) {
    pNewPages = new CPDF_Dictionary(pDestPDFDoc->GetByteStringPool());
    pNewRoot->SetReferenceFor("Pages", pDestPDFDoc,
                              pDestPDFDoc->AddIndirectObject(pNewPages));
  }

  CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", "");
  if (cbPageType == "") {
    pNewPages->SetFor("Type", new CPDF_Name("Pages"));
  }

  if (!pNewPages->GetArrayFor("Kids")) {
    pNewPages->SetIntegerFor("Count", 0);
    pNewPages->SetReferenceFor("Kids", pDestPDFDoc,
                               pDestPDFDoc->AddIndirectObject(new CPDF_Array));
  }

  return TRUE;
}
Example #10
0
FX_BOOL CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf,
                                               FX_STRSIZE& nBufSize) {
  CFDF_Document* pFDF = CFDF_Document::ParseMemory(pBuf, nBufSize);
  if (!pFDF)
    return TRUE;

  CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictFor("FDF");
  if (!pMainDict)
    return FALSE;

  CPDF_Array* pFields = pMainDict->GetArrayFor("Fields");
  if (!pFields)
    return FALSE;

  CFX_ByteTextBuf fdfEncodedData;
  for (uint32_t i = 0; i < pFields->GetCount(); i++) {
    CPDF_Dictionary* pField = pFields->GetDictAt(i);
    if (!pField)
      continue;
    CFX_WideString name;
    name = pField->GetUnicodeTextFor("T");
    CFX_ByteString name_b = CFX_ByteString::FromUnicode(name);
    CFX_ByteString csBValue = pField->GetStringFor("V");
    CFX_WideString csWValue = PDF_DecodeText(csBValue);
    CFX_ByteString csValue_b = CFX_ByteString::FromUnicode(csWValue);

    fdfEncodedData << name_b.GetBuffer(name_b.GetLength());
    name_b.ReleaseBuffer();
    fdfEncodedData << "=";
    fdfEncodedData << csValue_b.GetBuffer(csValue_b.GetLength());
    csValue_b.ReleaseBuffer();
    if (i != pFields->GetCount() - 1)
      fdfEncodedData << "&";
  }

  nBufSize = fdfEncodedData.GetLength();
  pBuf = FX_Alloc(uint8_t, nBufSize);
  FXSYS_memcpy(pBuf, fdfEncodedData.GetBuffer(), nBufSize);
  return TRUE;
}
Example #11
0
void CPDF_Font::LoadPDFEncoding(CPDF_Object* pEncoding,
                                int& iBaseEncoding,
                                std::vector<CFX_ByteString>* pCharNames,
                                bool bEmbedded,
                                bool bTrueType) {
  if (!pEncoding) {
    if (m_BaseFont == "Symbol") {
      iBaseEncoding = bTrueType ? PDFFONT_ENCODING_MS_SYMBOL
                                : PDFFONT_ENCODING_ADOBE_SYMBOL;
    } else if (!bEmbedded && iBaseEncoding == PDFFONT_ENCODING_BUILTIN) {
      iBaseEncoding = PDFFONT_ENCODING_WINANSI;
    }
    return;
  }
  if (pEncoding->IsName()) {
    if (iBaseEncoding == PDFFONT_ENCODING_ADOBE_SYMBOL ||
        iBaseEncoding == PDFFONT_ENCODING_ZAPFDINGBATS) {
      return;
    }
    if ((m_Flags & PDFFONT_SYMBOLIC) && m_BaseFont == "Symbol") {
      if (!bTrueType) {
        iBaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL;
      }
      return;
    }
    CFX_ByteString bsEncoding = pEncoding->GetString();
    if (bsEncoding.Compare("MacExpertEncoding") == 0) {
      bsEncoding = "WinAnsiEncoding";
    }
    GetPredefinedEncoding(bsEncoding, &iBaseEncoding);
    return;
  }

  CPDF_Dictionary* pDict = pEncoding->AsDictionary();
  if (!pDict)
    return;

  if (iBaseEncoding != PDFFONT_ENCODING_ADOBE_SYMBOL &&
      iBaseEncoding != PDFFONT_ENCODING_ZAPFDINGBATS) {
    CFX_ByteString bsEncoding = pDict->GetStringFor("BaseEncoding");
    if (bsEncoding.Compare("MacExpertEncoding") == 0 && bTrueType) {
      bsEncoding = "WinAnsiEncoding";
    }
    GetPredefinedEncoding(bsEncoding, &iBaseEncoding);
  }
  if ((!bEmbedded || bTrueType) && iBaseEncoding == PDFFONT_ENCODING_BUILTIN)
    iBaseEncoding = PDFFONT_ENCODING_STANDARD;

  CPDF_Array* pDiffs = pDict->GetArrayFor("Differences");
  if (!pDiffs)
    return;

  pCharNames->resize(256);
  uint32_t cur_code = 0;
  for (uint32_t i = 0; i < pDiffs->GetCount(); i++) {
    CPDF_Object* pElement = pDiffs->GetDirectObjectAt(i);
    if (!pElement)
      continue;

    if (CPDF_Name* pName = pElement->AsName()) {
      if (cur_code < 256)
        (*pCharNames)[cur_code] = pName->GetString();
      cur_code++;
    } else {
      cur_code = pElement->GetInteger();
    }
  }
}
Example #12
0
bool CPDF_CIDFont::Load() {
  if (m_pFontDict->GetStringFor("Subtype") == "TrueType") {
    LoadGB2312();
    return true;
  }

  CPDF_Array* pFonts = m_pFontDict->GetArrayFor("DescendantFonts");
  if (!pFonts || pFonts->GetCount() != 1)
    return false;

  CPDF_Dictionary* pCIDFontDict = pFonts->GetDictAt(0);
  if (!pCIDFontDict)
    return false;

  m_BaseFont = pCIDFontDict->GetStringFor("BaseFont");
  if ((m_BaseFont.Compare("CourierStd") == 0 ||
       m_BaseFont.Compare("CourierStd-Bold") == 0 ||
       m_BaseFont.Compare("CourierStd-BoldOblique") == 0 ||
       m_BaseFont.Compare("CourierStd-Oblique") == 0) &&
      !IsEmbedded()) {
    m_bAdobeCourierStd = true;
  }
  CPDF_Dictionary* pFontDesc = pCIDFontDict->GetDictFor("FontDescriptor");
  if (pFontDesc)
    LoadFontDescriptor(pFontDesc);

  CPDF_Object* pEncoding = m_pFontDict->GetDirectObjectFor("Encoding");
  if (!pEncoding)
    return false;

  CFX_ByteString subtype = pCIDFontDict->GetStringFor("Subtype");
  m_bType1 = (subtype == "CIDFontType0");

  CPDF_CMapManager& manager = GetFontGlobals()->m_CMapManager;
  if (pEncoding->IsName()) {
    CFX_ByteString cmap = pEncoding->GetString();
    bool bPromptCJK = m_pFontFile && m_bType1;
    m_pCMap = manager.GetPredefinedCMap(cmap, bPromptCJK);
    if (!m_pCMap)
      return false;
  } else if (CPDF_Stream* pStream = pEncoding->AsStream()) {
    m_pCMap = pdfium::MakeUnique<CPDF_CMap>();
    CPDF_StreamAcc acc;
    acc.LoadAllData(pStream, false);
    m_pCMap->LoadEmbedded(acc.GetData(), acc.GetSize());
  } else {
    return false;
  }

  m_Charset = m_pCMap->m_Charset;
  if (m_Charset == CIDSET_UNKNOWN) {
    CPDF_Dictionary* pCIDInfo = pCIDFontDict->GetDictFor("CIDSystemInfo");
    if (pCIDInfo) {
      m_Charset =
          CharsetFromOrdering(pCIDInfo->GetStringFor("Ordering").AsStringC());
    }
  }
  if (m_Charset != CIDSET_UNKNOWN) {
    bool bPromptCJK = !m_pFontFile && (m_pCMap->m_Coding == CIDCODING_CID ||
                                       pCIDFontDict->KeyExist("W"));
    m_pCID2UnicodeMap = manager.GetCID2UnicodeMap(m_Charset, bPromptCJK);
  }
  if (m_Font.GetFace()) {
    if (m_bType1)
      FXFT_Select_Charmap(m_Font.GetFace(), FXFT_ENCODING_UNICODE);
    else
      FT_UseCIDCharmap(m_Font.GetFace(), m_pCMap->m_Coding);
  }
  m_DefaultWidth = pCIDFontDict->GetIntegerFor("DW", 1000);
  CPDF_Array* pWidthArray = pCIDFontDict->GetArrayFor("W");
  if (pWidthArray)
    LoadMetricsArray(pWidthArray, &m_WidthList, 1);
  if (!IsEmbedded())
    LoadSubstFont();

  if (m_pFontFile || (GetSubstFont()->m_SubstFlags & FXFONT_SUBST_EXACT)) {
    CPDF_Object* pmap = pCIDFontDict->GetDirectObjectFor("CIDToGIDMap");
    if (pmap) {
      if (CPDF_Stream* pStream = pmap->AsStream()) {
        m_pStreamAcc = pdfium::MakeUnique<CPDF_StreamAcc>();
        m_pStreamAcc->LoadAllData(pStream, false);
      } else if (pmap->GetString() == "Identity") {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
        if (m_pFontFile)
          m_bCIDIsGID = true;
#else
        m_bCIDIsGID = true;
#endif
      }
    }
  }

  CheckFontMetrics();
  if (IsVertWriting()) {
    pWidthArray = pCIDFontDict->GetArrayFor("W2");
    if (pWidthArray)
      LoadMetricsArray(pWidthArray, &m_VertMetrics, 3);
    CPDF_Array* pDefaultArray = pCIDFontDict->GetArrayFor("DW2");
    if (pDefaultArray) {
      m_DefaultVY = pDefaultArray->GetIntegerAt(0);
      m_DefaultW1 = pDefaultArray->GetIntegerAt(1);
    } else {
      m_DefaultVY = 880;
      m_DefaultW1 = -1000;
    }
  }
  return true;
}
DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page,
                                                       FS_MATRIX* matrix,
                                                       FS_RECTF* clipRect) {
  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
  if (!pPage)
    return false;

  CFX_ByteTextBuf textBuf;
  textBuf << "q ";
  CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right,
                     clipRect->top);
  rect.Normalize();
  CFX_ByteString bsClipping;
  bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom,
                    rect.Width(), rect.Height());
  textBuf << bsClipping;

  CFX_ByteString bsMatix;
  bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b, matrix->c,
                 matrix->d, matrix->e, matrix->f);
  textBuf << bsMatix;

  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
  CPDF_Object* pContentObj =
      pPageDic ? pPageDic->GetObjectFor("Contents") : nullptr;
  if (!pContentObj)
    pContentObj = pPageDic ? pPageDic->GetArrayFor("Contents") : nullptr;
  if (!pContentObj)
    return false;

  CPDF_Document* pDoc = pPage->m_pDocument;
  if (!pDoc)
    return false;

  CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>(
      nullptr, 0,
      pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
  pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize());

  CPDF_Stream* pEndStream = pDoc->NewIndirect<CPDF_Stream>(
      nullptr, 0,
      pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
  pEndStream->SetData((const uint8_t*)" Q", 2);

  CPDF_Array* pContentArray = nullptr;
  CPDF_Array* pArray = ToArray(pContentObj);
  if (pArray) {
    pContentArray = pArray;
    pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
    pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
  } else if (CPDF_Reference* pReference = ToReference(pContentObj)) {
    CPDF_Object* pDirectObj = pReference->GetDirect();
    if (pDirectObj) {
      CPDF_Array* pObjArray = pDirectObj->AsArray();
      if (pObjArray) {
        pContentArray = pObjArray;
        pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc,
                                                   pStream->GetObjNum());
        pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
      } else if (pDirectObj->IsStream()) {
        pContentArray = pDoc->NewIndirect<CPDF_Array>();
        pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
        pContentArray->AddNew<CPDF_Reference>(pDoc, pDirectObj->GetObjNum());
        pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
        pPageDic->SetNewFor<CPDF_Reference>("Contents", pDoc,
                                            pContentArray->GetObjNum());
      }
    }
  }

  // Need to transform the patterns as well.
  CPDF_Dictionary* pRes = pPageDic->GetDictFor("Resources");
  if (pRes) {
    CPDF_Dictionary* pPattenDict = pRes->GetDictFor("Pattern");
    if (pPattenDict) {
      for (const auto& it : *pPattenDict) {
        CPDF_Object* pObj = it.second.get();
        if (pObj->IsReference())
          pObj = pObj->GetDirect();

        CPDF_Dictionary* pDict = nullptr;
        if (pObj->IsDictionary())
          pDict = pObj->AsDictionary();
        else if (CPDF_Stream* pObjStream = pObj->AsStream())
          pDict = pObjStream->GetDict();
        else
          continue;

        CFX_Matrix m = pDict->GetMatrixFor("Matrix");
        CFX_Matrix t = *(CFX_Matrix*)matrix;
        m.Concat(t);
        pDict->SetMatrixFor("Matrix", m);
      }
    }
  }

  return true;
}
DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,
                                               FPDF_CLIPPATH clipPath) {
  CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
  if (!pPage)
    return;

  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
  CPDF_Object* pContentObj =
      pPageDic ? pPageDic->GetObjectFor("Contents") : nullptr;
  if (!pContentObj)
    pContentObj = pPageDic ? pPageDic->GetArrayFor("Contents") : nullptr;
  if (!pContentObj)
    return;

  CFX_ByteTextBuf strClip;
  CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;
  uint32_t i;
  for (i = 0; i < pClipPath->GetPathCount(); i++) {
    CPDF_Path path = pClipPath->GetPath(i);
    int iClipType = pClipPath->GetClipType(i);
    if (path.GetPoints().empty()) {
      // Empty clipping (totally clipped out)
      strClip << "0 0 m W n ";
    } else {
      OutputPath(strClip, path);
      if (iClipType == FXFILL_WINDING)
        strClip << "W n\n";
      else
        strClip << "W* n\n";
    }
  }
  CPDF_Document* pDoc = pPage->m_pDocument;
  if (!pDoc)
    return;

  CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>(
      nullptr, 0,
      pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()));
  pStream->SetData(strClip.GetBuffer(), strClip.GetSize());

  CPDF_Array* pArray = ToArray(pContentObj);
  if (pArray) {
    pArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
    return;
  }
  CPDF_Reference* pReference = ToReference(pContentObj);
  if (!pReference)
    return;

  CPDF_Object* pDirectObj = pReference->GetDirect();
  if (!pDirectObj)
    return;

  CPDF_Array* pObjArray = pDirectObj->AsArray();
  if (pObjArray) {
    pObjArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
    return;
  }
  if (pDirectObj->IsStream()) {
    CPDF_Array* pContentArray = pDoc->NewIndirect<CPDF_Array>();
    pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
    pContentArray->AddNew<CPDF_Reference>(pDoc, pDirectObj->GetObjNum());
    pPageDic->SetNewFor<CPDF_Reference>("Contents", pDoc,
                                        pContentArray->GetObjNum());
  }
}