CFX_ByteString CPDF_PageContentGenerator::RealizeResource( CPDF_Object* pResourceObj, const CFX_ByteString& bsType) { if (!m_pPage->m_pResources) { m_pPage->m_pResources = new CPDF_Dictionary(m_pDocument->GetByteStringPool()); m_pPage->m_pFormDict->SetReferenceFor( "Resources", m_pDocument, m_pDocument->AddIndirectObject(m_pPage->m_pResources)); } CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDictFor(bsType); if (!pResList) { pResList = new CPDF_Dictionary(m_pDocument->GetByteStringPool()); m_pPage->m_pResources->SetFor(bsType, pResList); } CFX_ByteString name; int idnum = 1; while (1) { name.Format("FX%c%d", bsType[0], idnum); if (!pResList->KeyExist(name)) { break; } idnum++; } pResList->SetReferenceFor(name, m_pDocument, m_pDocument->AddIndirectObject(pResourceObj)); return name; }
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; }
void CPDF_PageContentGenerator::GenerateContent() { CFX_ByteTextBuf buf; CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict; for (int i = 0; i < m_pageObjects.GetSize(); ++i) { CPDF_PageObject* pPageObj = m_pageObjects[i]; if (!pPageObj || !pPageObj->IsImage()) { continue; } ProcessImage(buf, pPageObj->AsImage()); } CPDF_Object* pContent = pPageDict ? pPageDict->GetDirectObjectFor("Contents") : nullptr; if (pContent) pPageDict->RemoveFor("Contents"); CPDF_Stream* pStream = new CPDF_Stream; pStream->SetData(buf.GetBuffer(), buf.GetLength()); pPageDict->SetReferenceFor("Contents", m_pDocument, m_pDocument->AddIndirectObject(pStream)); }
TEST(cpdf_formfield, FPDF_GetFullName) { CFX_WideString name = FPDF_GetFullName(nullptr); EXPECT_TRUE(name.IsEmpty()); CPDF_IndirectObjectHolder obj_holder; CPDF_Dictionary* root = new CPDF_Dictionary(); obj_holder.AddIndirectObject(root); root->SetNameFor("T", "foo"); name = FPDF_GetFullName(root); EXPECT_STREQ("foo", name.UTF8Encode().c_str()); CPDF_Dictionary* dict1 = new CPDF_Dictionary(); root->SetReferenceFor("Parent", &obj_holder, obj_holder.AddIndirectObject(dict1)); dict1->SetNameFor("T", "bar"); name = FPDF_GetFullName(root); EXPECT_STREQ("bar.foo", name.UTF8Encode().c_str()); CPDF_Dictionary* dict2 = new CPDF_Dictionary(); dict1->SetFor("Parent", dict2); name = FPDF_GetFullName(root); EXPECT_STREQ("bar.foo", name.UTF8Encode().c_str()); CPDF_Dictionary* dict3 = new CPDF_Dictionary(); dict2->SetReferenceFor("Parent", &obj_holder, obj_holder.AddIndirectObject(dict3)); dict3->SetNameFor("T", "qux"); name = FPDF_GetFullName(root); EXPECT_STREQ("qux.bar.foo", name.UTF8Encode().c_str()); dict3->SetReferenceFor("Parent", &obj_holder, root->GetObjNum()); name = FPDF_GetFullName(root); EXPECT_STREQ("qux.bar.foo", name.UTF8Encode().c_str()); name = FPDF_GetFullName(dict1); EXPECT_STREQ("foo.qux.bar", name.UTF8Encode().c_str()); name = FPDF_GetFullName(dict2); EXPECT_STREQ("bar.foo.qux", name.UTF8Encode().c_str()); name = FPDF_GetFullName(dict3); EXPECT_STREQ("bar.foo.qux", name.UTF8Encode().c_str()); }
CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName) { pLogFont->lfHeight = -1000; pLogFont->lfWidth = 0; HGDIOBJ hFont = CreateFontIndirectA(pLogFont); HDC hDC = CreateCompatibleDC(nullptr); hFont = SelectObject(hDC, hFont); int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr); if (tm_size == 0) { hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return nullptr; } LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf); GetOutlineTextMetrics(hDC, tm_size, ptm); int flags = CalculateFlags(false, pLogFont->lfItalic != 0, (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET); bool bCJK = pLogFont->lfCharSet == FXFONT_CHINESEBIG5_CHARSET || pLogFont->lfCharSet == FXFONT_GB2312_CHARSET || pLogFont->lfCharSet == FXFONT_HANGUL_CHARSET || pLogFont->lfCharSet == FXFONT_SHIFTJIS_CHARSET; CFX_ByteString basefont; if (bTranslateName && bCJK) basefont = FPDF_GetPSNameFromTT(hDC); if (basefont.IsEmpty()) basefont = pLogFont->lfFaceName; int italicangle = ptm->otmItalicAngle / 10; int ascend = ptm->otmrcFontBox.top; int descend = ptm->otmrcFontBox.bottom; int capheight = ptm->otmsCapEmHeight; int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; FX_Free(tm_buf); basefont.Replace(" ", ""); CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); pBaseDict->SetNameFor("Type", "Font"); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { if (pLogFont->lfCharSet == FXFONT_ANSI_CHARSET || pLogFont->lfCharSet == FXFONT_DEFAULT_CHARSET || pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET) { pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); } else { CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); } int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); CPDF_Array* pWidths = new CPDF_Array; for (size_t i = 0; i < 224; i++) pWidths->AddInteger(char_widths[i]); ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, pWidths); } else { pFontDict = ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont, [&hDC](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } AddIndirectObject(pBaseDict); CPDF_Array* pBBox = new CPDF_Array; for (int i = 0; i < 4; i++) pBBox->AddInteger(bbox[i]); CPDF_Dictionary* pFontDesc = CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend, pBBox, pLogFont->lfWeight / 5); pFontDesc->SetIntegerFor("CapHeight", capheight); pFontDict->SetReferenceFor("FontDescriptor", this, AddIndirectObject(pFontDesc)); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return LoadFont(pBaseDict); }
CPDF_Font* CPDF_Document::AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert) { if (!pFont) return nullptr; bool bCJK = charset == FXFONT_CHINESEBIG5_CHARSET || charset == FXFONT_GB2312_CHARSET || charset == FXFONT_HANGUL_CHARSET || charset == FXFONT_SHIFTJIS_CHARSET; CFX_ByteString basefont = pFont->GetFamilyName(); basefont.Replace(" ", ""); int flags = CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(), false, false, charset == FXFONT_SYMBOL_CHARSET); CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); pBaseDict->SetNameFor("Type", "Font"); std::unique_ptr<CFX_UnicodeEncoding> pEncoding( new CFX_UnicodeEncoding(pFont)); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { CPDF_Array* pWidths = new CPDF_Array; for (int charcode = 32; charcode < 128; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AddInteger(char_width); } if (charset == FXFONT_ANSI_CHARSET || charset == FXFONT_DEFAULT_CHARSET || charset == FXFONT_SYMBOL_CHARSET) { pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); for (int charcode = 128; charcode <= 255; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AddInteger(char_width); } } else { size_t i = CalculateEncodingDict(charset, pBaseDict); if (i < FX_ArraySize(g_FX_CharsetUnicodes)) { const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j++) { int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AddInteger(char_width); } } } ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont, pWidths); } else { pFontDict = ProcessbCJK(pBaseDict, charset, bVert, basefont, [pFont, &pEncoding](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { InsertWidthArray1(pFont, pEncoding.get(), start, end, widthArr); }); } AddIndirectObject(pBaseDict); int italicangle = pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0; FX_RECT bbox; pFont->GetBBox(bbox); CPDF_Array* pBBox = new CPDF_Array; pBBox->AddInteger(bbox.left); pBBox->AddInteger(bbox.bottom); pBBox->AddInteger(bbox.right); pBBox->AddInteger(bbox.top); int32_t nStemV = 0; if (pFont->GetSubstFont()) { nStemV = pFont->GetSubstFont()->m_Weight / 5; } else { static const FX_CHAR stem_chars[] = {'i', 'I', '!', '1'}; const size_t count = FX_ArraySize(stem_chars); uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]); nStemV = pFont->GetGlyphWidth(glyph); for (size_t i = 1; i < count; i++) { glyph = pEncoding->GlyphFromCharCode(stem_chars[i]); int width = pFont->GetGlyphWidth(glyph); if (width > 0 && width < nStemV) nStemV = width; } } CPDF_Dictionary* pFontDesc = CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(), pFont->GetDescent(), pBBox, nStemV); pFontDict->SetReferenceFor("FontDescriptor", this, AddIndirectObject(pFontDesc)); return LoadFont(pBaseDict); }
DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) { CPDF_Page* pPage = CPDFPageFromFPDFPage(page); if (!page) { return FLATTEN_FAIL; } CPDF_Document* pDocument = pPage->m_pDocument; CPDF_Dictionary* pPageDict = pPage->m_pFormDict; if (!pDocument || !pPageDict) { return FLATTEN_FAIL; } CPDF_ObjectArray ObjectArray; CPDF_RectArray RectArray; int iRet = FLATTEN_FAIL; iRet = ParserAnnots(pDocument, pPageDict, &RectArray, &ObjectArray, nFlag); if (iRet == FLATTEN_NOTHINGTODO || iRet == FLATTEN_FAIL) return iRet; CFX_FloatRect rcOriginalCB; CFX_FloatRect rcMerger = CalculateRect(&RectArray); CFX_FloatRect rcOriginalMB = pPageDict->GetRectFor("MediaBox"); if (pPageDict->KeyExist("CropBox")) rcOriginalMB = pPageDict->GetRectFor("CropBox"); if (rcOriginalMB.IsEmpty()) { rcOriginalMB = CFX_FloatRect(0.0f, 0.0f, 612.0f, 792.0f); } rcMerger.left = rcMerger.left < rcOriginalMB.left ? rcOriginalMB.left : rcMerger.left; rcMerger.right = rcMerger.right > rcOriginalMB.right ? rcOriginalMB.right : rcMerger.right; rcMerger.top = rcMerger.top > rcOriginalMB.top ? rcOriginalMB.top : rcMerger.top; rcMerger.bottom = rcMerger.bottom < rcOriginalMB.bottom ? rcOriginalMB.bottom : rcMerger.bottom; if (pPageDict->KeyExist("ArtBox")) rcOriginalCB = pPageDict->GetRectFor("ArtBox"); else rcOriginalCB = rcOriginalMB; if (!rcOriginalMB.IsEmpty()) { CPDF_Array* pMediaBox = new CPDF_Array(); pMediaBox->Add(new CPDF_Number(rcOriginalMB.left)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.bottom)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.right)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.top)); pPageDict->SetFor("MediaBox", pMediaBox); } if (!rcOriginalCB.IsEmpty()) { CPDF_Array* pCropBox = new CPDF_Array(); pCropBox->Add(new CPDF_Number(rcOriginalCB.left)); pCropBox->Add(new CPDF_Number(rcOriginalCB.bottom)); pCropBox->Add(new CPDF_Number(rcOriginalCB.right)); pCropBox->Add(new CPDF_Number(rcOriginalCB.top)); pPageDict->SetFor("ArtBox", pCropBox); } CPDF_Dictionary* pRes = pPageDict->GetDictFor("Resources"); if (!pRes) { pRes = new CPDF_Dictionary(pDocument->GetByteStringPool()); pPageDict->SetFor("Resources", pRes); } CPDF_Stream* pNewXObject = new CPDF_Stream( nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); uint32_t dwObjNum = pDocument->AddIndirectObject(pNewXObject); CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); if (!pPageXObject) { pPageXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); pRes->SetFor("XObject", pPageXObject); } CFX_ByteString key = ""; int nStreams = ObjectArray.GetSize(); if (nStreams > 0) { for (int iKey = 0; /*iKey < 100*/; iKey++) { char sExtend[5] = {}; FXSYS_itoa(iKey, sExtend, 10); key = CFX_ByteString("FFT") + CFX_ByteString(sExtend); if (!pPageXObject->KeyExist(key)) break; } } SetPageContents(key, pPageDict, pDocument); CPDF_Dictionary* pNewXORes = nullptr; if (!key.IsEmpty()) { pPageXObject->SetReferenceFor(key, pDocument, dwObjNum); CPDF_Dictionary* pNewOXbjectDic = pNewXObject->GetDict(); pNewXORes = new CPDF_Dictionary(pDocument->GetByteStringPool()); pNewOXbjectDic->SetFor("Resources", pNewXORes); pNewOXbjectDic->SetNameFor("Type", "XObject"); pNewOXbjectDic->SetNameFor("Subtype", "Form"); pNewOXbjectDic->SetIntegerFor("FormType", 1); pNewOXbjectDic->SetNameFor("Name", "FRM"); CFX_FloatRect rcBBox = pPageDict->GetRectFor("ArtBox"); pNewOXbjectDic->SetRectFor("BBox", rcBBox); } for (int i = 0; i < nStreams; i++) { CPDF_Dictionary* pAnnotDic = ObjectArray.GetAt(i); if (!pAnnotDic) continue; CFX_FloatRect rcAnnot = pAnnotDic->GetRectFor("Rect"); rcAnnot.Normalize(); CFX_ByteString sAnnotState = pAnnotDic->GetStringFor("AS"); CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictFor("AP"); if (!pAnnotAP) continue; CPDF_Stream* pAPStream = pAnnotAP->GetStreamFor("N"); if (!pAPStream) { CPDF_Dictionary* pAPDic = pAnnotAP->GetDictFor("N"); if (!pAPDic) continue; if (!sAnnotState.IsEmpty()) { pAPStream = pAPDic->GetStreamFor(sAnnotState); } else { auto it = pAPDic->begin(); if (it != pAPDic->end()) { CPDF_Object* pFirstObj = it->second; if (pFirstObj) { if (pFirstObj->IsReference()) pFirstObj = pFirstObj->GetDirect(); if (!pFirstObj->IsStream()) continue; pAPStream = pFirstObj->AsStream(); } } } } if (!pAPStream) continue; CPDF_Dictionary* pAPDic = pAPStream->GetDict(); CFX_Matrix matrix = pAPDic->GetMatrixFor("Matrix"); CFX_FloatRect rcStream; if (pAPDic->KeyExist("Rect")) rcStream = pAPDic->GetRectFor("Rect"); else if (pAPDic->KeyExist("BBox")) rcStream = pAPDic->GetRectFor("BBox"); if (rcStream.IsEmpty()) continue; CPDF_Object* pObj = pAPStream; if (pObj) { CPDF_Dictionary* pObjDic = pObj->GetDict(); if (pObjDic) { pObjDic->SetNameFor("Type", "XObject"); pObjDic->SetNameFor("Subtype", "Form"); } } CPDF_Dictionary* pXObject = pNewXORes->GetDictFor("XObject"); if (!pXObject) { pXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); pNewXORes->SetFor("XObject", pXObject); } CFX_ByteString sFormName; sFormName.Format("F%d", i); pXObject->SetReferenceFor(sFormName, pDocument, pDocument->AddIndirectObject(pObj)); CPDF_StreamAcc acc; acc.LoadAllData(pNewXObject); const uint8_t* pData = acc.GetData(); CFX_ByteString sStream(pData, acc.GetSize()); if (matrix.IsIdentity()) { matrix.a = 1.0f; matrix.b = 0.0f; matrix.c = 0.0f; matrix.d = 1.0f; matrix.e = 0.0f; matrix.f = 0.0f; } CFX_ByteString sTemp; CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix); sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f, sFormName.c_str()); sStream += sTemp; pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); } pPageDict->RemoveFor("Annots"); ObjectArray.RemoveAll(); RectArray.RemoveAll(); return FLATTEN_SUCCESS; }