// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfapi/page/cpdf_docpagedata.h" #include #include #include #include #include #include "build/build_config.h" #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_iccprofile.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/cpdf_pattern.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxge/cfx_font.h" #include "core/fxge/cfx_fontmapper.h" #include "core/fxge/cfx_substfont.h" #include "core/fxge/cfx_unicodeencoding.h" #include "core/fxge/fx_font.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" namespace { void InsertWidthArrayImpl(std::vector widths, CPDF_Array* pWidthArray) { size_t i; for (i = 1; i < widths.size(); i++) { if (widths[i] != widths[0]) break; } if (i == widths.size()) { int first = pWidthArray->GetIntegerAt(pWidthArray->size() - 1); pWidthArray->AddNew(first + static_cast(widths.size()) - 1); pWidthArray->AddNew(widths[0]); return; } CPDF_Array* pWidthArray1 = pWidthArray->AddNew(); for (int w : widths) pWidthArray1->AddNew(w); } #if defined(OS_WIN) void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) { std::vector widths(end - start + 1); GetCharWidth(hDC, start, end, widths.data()); InsertWidthArrayImpl(std::move(widths), pWidthArray); } ByteString GetPSNameFromTT(HDC hDC) { ByteString result; DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0); if (size != GDI_ERROR) { LPBYTE buffer = FX_Alloc(BYTE, size); ::GetFontData(hDC, 'eman', 0, buffer, size); result = GetNameFromTT({buffer, size}, 6); FX_Free(buffer); } return result; } #endif // defined(OS_WIN) void InsertWidthArray1(CFX_Font* pFont, CFX_UnicodeEncoding* pEncoding, wchar_t start, wchar_t end, CPDF_Array* pWidthArray) { std::vector widths(end - start + 1); for (size_t i = 0; i < widths.size(); ++i) { int glyph_index = pEncoding->GlyphFromCharCode(start + i); widths[i] = pFont->GetGlyphWidth(glyph_index); } InsertWidthArrayImpl(std::move(widths), pWidthArray); } int CalculateFlags(bool bold, bool italic, bool fixedPitch, bool serif, bool script, bool symbolic) { int flags = 0; if (bold) flags |= FXFONT_FORCE_BOLD; if (italic) flags |= FXFONT_ITALIC; if (fixedPitch) flags |= FXFONT_FIXED_PITCH; if (serif) flags |= FXFONT_SERIF; if (script) flags |= FXFONT_SCRIPT; if (symbolic) flags |= FXFONT_SYMBOLIC; else flags |= FXFONT_NONSYMBOLIC; return flags; } void ProcessNonbCJK(CPDF_Dictionary* pBaseDict, bool bold, bool italic, ByteString basefont, RetainPtr pWidths) { if (bold && italic) basefont += ",BoldItalic"; else if (bold) basefont += ",Bold"; else if (italic) basefont += ",Italic"; pBaseDict->SetNewFor("Subtype", "TrueType"); pBaseDict->SetNewFor("BaseFont", basefont); pBaseDict->SetNewFor("FirstChar", 32); pBaseDict->SetNewFor("LastChar", 255); pBaseDict->SetFor("Widths", pWidths); } RetainPtr CalculateFontDesc(CPDF_Document* pDoc, ByteString basefont, int flags, int italicangle, int ascend, int descend, RetainPtr bbox, int32_t stemV) { auto pFontDesc = pDoc->New(); pFontDesc->SetNewFor("Type", "FontDescriptor"); pFontDesc->SetNewFor("FontName", basefont); pFontDesc->SetNewFor("Flags", flags); pFontDesc->SetFor("FontBBox", bbox); pFontDesc->SetNewFor("ItalicAngle", italicangle); pFontDesc->SetNewFor("Ascent", ascend); pFontDesc->SetNewFor("Descent", descend); pFontDesc->SetNewFor("StemV", stemV); return pFontDesc; } } // namespace // static CPDF_DocPageData* CPDF_DocPageData::FromDocument(const CPDF_Document* pDoc) { return static_cast(pDoc->GetPageData()); } CPDF_DocPageData::CPDF_DocPageData() = default; CPDF_DocPageData::~CPDF_DocPageData() { for (auto& it : m_FontMap) { if (it.second) it.second->WillBeDestroyed(); } } void CPDF_DocPageData::ClearStockFont() { CPDF_PageModule::GetInstance()->ClearStockFont(GetDocument()); } RetainPtr CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) { if (!pFontDict) return nullptr; auto it = m_FontMap.find(pFontDict); if (it != m_FontMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr pFont = CPDF_Font::Create(GetDocument(), pFontDict, this); if (!pFont) return nullptr; m_FontMap[pFontDict].Reset(pFont.Get()); return pFont; } RetainPtr CPDF_DocPageData::GetStandardFont( const ByteString& fontName, const CPDF_FontEncoding* pEncoding) { if (fontName.IsEmpty()) return nullptr; for (auto& it : m_FontMap) { CPDF_Font* pFont = it.second.Get(); if (!pFont) continue; if (pFont->GetBaseFontName() != fontName) continue; if (pFont->IsEmbedded()) continue; if (!pFont->IsType1Font()) continue; if (pFont->GetFontDict()->KeyExist("Widths")) continue; CPDF_Type1Font* pT1Font = pFont->AsType1Font(); if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) continue; return pdfium::WrapRetain(pFont); } CPDF_Dictionary* pDict = GetDocument()->NewIndirect(); pDict->SetNewFor("Type", "Font"); pDict->SetNewFor("Subtype", "Type1"); pDict->SetNewFor("BaseFont", fontName); if (pEncoding) { pDict->SetFor("Encoding", pEncoding->Realize(GetDocument()->GetByteStringPool())); } // Note: NULL FormFactoryIface OK since known Type1 font from above. RetainPtr pFont = CPDF_Font::Create(GetDocument(), pDict, nullptr); if (!pFont) return nullptr; m_FontMap[pDict].Reset(pFont.Get()); return pFont; } RetainPtr CPDF_DocPageData::GetColorSpace( const CPDF_Object* pCSObj, const CPDF_Dictionary* pResources) { std::set visited; return GetColorSpaceGuarded(pCSObj, pResources, &visited); } RetainPtr CPDF_DocPageData::GetColorSpaceGuarded( const CPDF_Object* pCSObj, const CPDF_Dictionary* pResources, std::set* pVisited) { std::set visitedLocal; return GetColorSpaceInternal(pCSObj, pResources, pVisited, &visitedLocal); } RetainPtr CPDF_DocPageData::GetColorSpaceInternal( const CPDF_Object* pCSObj, const CPDF_Dictionary* pResources, std::set* pVisited, std::set* pVisitedInternal) { if (!pCSObj) return nullptr; if (pdfium::ContainsKey(*pVisitedInternal, pCSObj)) return nullptr; pdfium::ScopedSetInsertion insertion(pVisitedInternal, pCSObj); if (pCSObj->IsName()) { ByteString name = pCSObj->GetString(); RetainPtr pCS = CPDF_ColorSpace::ColorspaceFromName(name); if (!pCS && pResources) { const CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace"); if (pList) { return GetColorSpaceInternal(pList->GetDirectObjectFor(name), nullptr, pVisited, pVisitedInternal); } } if (!pCS || !pResources) return pCS; const CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace"); if (!pColorSpaces) return pCS; const CPDF_Object* pDefaultCS = nullptr; switch (pCS->GetFamily()) { case PDFCS_DEVICERGB: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); break; case PDFCS_DEVICEGRAY: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); break; case PDFCS_DEVICECMYK: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); break; } if (!pDefaultCS) return pCS; return GetColorSpaceInternal(pDefaultCS, nullptr, pVisited, pVisitedInternal); } const CPDF_Array* pArray = pCSObj->AsArray(); if (!pArray || pArray->IsEmpty()) return nullptr; if (pArray->size() == 1) { return GetColorSpaceInternal(pArray->GetDirectObjectAt(0), pResources, pVisited, pVisitedInternal); } auto it = m_ColorSpaceMap.find(pCSObj); if (it != m_ColorSpaceMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr pCS = CPDF_ColorSpace::Load(GetDocument(), pArray, pVisited); if (!pCS) return nullptr; m_ColorSpaceMap[pCSObj].Reset(pCS.Get()); return pCS; } RetainPtr CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, bool bShading, const CFX_Matrix& matrix) { if (!pPatternObj) return nullptr; auto it = m_PatternMap.find(pPatternObj); if (it != m_PatternMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr pPattern; if (bShading) { pPattern = pdfium::MakeRetain( GetDocument(), pPatternObj, true, matrix); } else { CPDF_Dictionary* pDict = pPatternObj->GetDict(); if (!pDict) return nullptr; int type = pDict->GetIntegerFor("PatternType"); if (type == CPDF_Pattern::kTiling) { pPattern = pdfium::MakeRetain(GetDocument(), pPatternObj, matrix); } else if (type == CPDF_Pattern::kShading) { pPattern = pdfium::MakeRetain( GetDocument(), pPatternObj, false, matrix); } else { return nullptr; } } m_PatternMap[pPatternObj].Reset(pPattern.Get()); return pPattern; } RetainPtr CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) { ASSERT(dwStreamObjNum); auto it = m_ImageMap.find(dwStreamObjNum); if (it != m_ImageMap.end()) return it->second; auto pImage = pdfium::MakeRetain(GetDocument(), dwStreamObjNum); m_ImageMap[dwStreamObjNum] = pImage; return pImage; } void CPDF_DocPageData::MaybePurgeImage(uint32_t dwStreamObjNum) { ASSERT(dwStreamObjNum); auto it = m_ImageMap.find(dwStreamObjNum); if (it != m_ImageMap.end() && it->second->HasOneRef()) m_ImageMap.erase(it); } RetainPtr CPDF_DocPageData::GetIccProfile( const CPDF_Stream* pProfileStream) { if (!pProfileStream) return nullptr; auto it = m_IccProfileMap.find(pProfileStream); if (it != m_IccProfileMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); auto pAccessor = pdfium::MakeRetain(pProfileStream); pAccessor->LoadAllDataFiltered(); ByteString bsDigest = pAccessor->ComputeDigest(); auto hash_it = m_HashProfileMap.find(bsDigest); if (hash_it != m_HashProfileMap.end()) { auto it_copied_stream = m_IccProfileMap.find(hash_it->second.Get()); if (it_copied_stream != m_IccProfileMap.end() && it_copied_stream->second) return pdfium::WrapRetain(it_copied_stream->second.Get()); } auto pProfile = pdfium::MakeRetain(pProfileStream, pAccessor->GetSpan()); m_IccProfileMap[pProfileStream].Reset(pProfile.Get()); m_HashProfileMap[bsDigest].Reset(pProfileStream); return pProfile; } RetainPtr CPDF_DocPageData::GetFontFileStreamAcc( const CPDF_Stream* pFontStream) { ASSERT(pFontStream); auto it = m_FontFileMap.find(pFontStream); if (it != m_FontFileMap.end()) return it->second; const CPDF_Dictionary* pFontDict = pFontStream->GetDict(); int32_t len1 = pFontDict->GetIntegerFor("Length1"); int32_t len2 = pFontDict->GetIntegerFor("Length2"); int32_t len3 = pFontDict->GetIntegerFor("Length3"); uint32_t org_size = 0; if (len1 >= 0 && len2 >= 0 && len3 >= 0) { FX_SAFE_UINT32 safe_org_size = len1; safe_org_size += len2; safe_org_size += len3; org_size = safe_org_size.ValueOrDefault(0); } auto pFontAcc = pdfium::MakeRetain(pFontStream); pFontAcc->LoadAllDataFilteredWithEstimatedSize(org_size); m_FontFileMap[pFontStream] = pFontAcc; return pFontAcc; } void CPDF_DocPageData::MaybePurgeFontFileStreamAcc( const CPDF_Stream* pFontStream) { if (!pFontStream) return; auto it = m_FontFileMap.find(pFontStream); if (it != m_FontFileMap.end() && it->second->HasOneRef()) m_FontFileMap.erase(it); } std::unique_ptr CPDF_DocPageData::CreateForm( CPDF_Document* pDocument, CPDF_Dictionary* pPageResources, CPDF_Stream* pFormStream) { return pdfium::MakeUnique(pDocument, pPageResources, pFormStream); } RetainPtr CPDF_DocPageData::AddStandardFont( const ByteString& fontName, const CPDF_FontEncoding* pEncoding) { ByteString mutable_name(fontName); if (!CFX_FontMapper::GetStandardFontName(&mutable_name)) return nullptr; return GetStandardFont(mutable_name, pEncoding); } RetainPtr CPDF_DocPageData::AddFont(std::unique_ptr pFont, int charset) { if (!pFont) return nullptr; const bool bCJK = FX_CharSetIsCJK(charset); ByteString basefont = pFont->GetFamilyName(); basefont.Replace(" ", ""); int flags = CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(), false, false, charset == FX_CHARSET_Symbol); CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect(); pBaseDict->SetNewFor("Type", "Font"); auto pEncoding = pdfium::MakeUnique(pFont.get()); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { auto pWidths = pdfium::MakeRetain(); for (int charcode = 32; charcode < 128; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AddNew(char_width); } if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default || charset == FX_CHARSET_Symbol) { pBaseDict->SetNewFor("Encoding", "WinAnsiEncoding"); for (int charcode = 128; charcode <= 255; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AddNew(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->AddNew(char_width); } } } ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont, std::move(pWidths)); } else { pFontDict = ProcessbCJK( pBaseDict, charset, basefont, [&pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) { InsertWidthArray1(pFont.get(), pEncoding.get(), start, end, widthArr); }); } int italicangle = pFont->GetSubstFontItalicAngle(); FX_RECT bbox; pFont->GetBBox(&bbox); auto pBBox = pdfium::MakeRetain(); pBBox->AddNew(bbox.left); pBBox->AddNew(bbox.bottom); pBBox->AddNew(bbox.right); pBBox->AddNew(bbox.top); int32_t nStemV = 0; if (pFont->GetSubstFont()) { nStemV = pFont->GetSubstFont()->m_Weight / 5; } else { static const 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 = ToDictionary(GetDocument()->AddIndirectObject(CalculateFontDesc( GetDocument(), basefont, flags, italicangle, pFont->GetAscent(), pFont->GetDescent(), std::move(pBBox), nStemV))); pFontDict->SetNewFor("FontDescriptor", GetDocument(), pFontDesc->GetObjNum()); return GetFont(pBaseDict); } #if defined(OS_WIN) RetainPtr CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) { 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(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 == FX_CHARSET_Symbol); const bool bCJK = FX_CharSetIsCJK(pLogFont->lfCharSet); ByteString basefont; if (bCJK) basefont = 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 = GetDocument()->NewIndirect(); pBaseDict->SetNewFor("Type", "Font"); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { if (pLogFont->lfCharSet == FX_CHARSET_ANSI || pLogFont->lfCharSet == FX_CHARSET_Default || pLogFont->lfCharSet == FX_CHARSET_Symbol) { pBaseDict->SetNewFor("Encoding", "WinAnsiEncoding"); } else { CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); } int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); auto pWidths = pdfium::MakeRetain(); for (size_t i = 0; i < 224; i++) pWidths->AddNew(char_widths[i]); ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, std::move(pWidths)); } else { pFontDict = ProcessbCJK(pBaseDict, pLogFont->lfCharSet, basefont, [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } auto pBBox = pdfium::MakeRetain(); for (int i = 0; i < 4; i++) pBBox->AddNew(bbox[i]); RetainPtr pFontDesc = CalculateFontDesc(GetDocument(), basefont, flags, italicangle, ascend, descend, std::move(pBBox), pLogFont->lfWeight / 5); pFontDesc->SetNewFor("CapHeight", capheight); pFontDict->SetFor("FontDescriptor", GetDocument() ->AddIndirectObject(std::move(pFontDesc)) ->MakeReference(GetDocument())); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return GetFont(pBaseDict); } #endif // defined(OS_WIN) size_t CPDF_DocPageData::CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict) { size_t i; for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) { if (g_FX_CharsetUnicodes[i].m_Charset == charset) break; } if (i == FX_ArraySize(g_FX_CharsetUnicodes)) return i; CPDF_Dictionary* pEncodingDict = GetDocument()->NewIndirect(); pEncodingDict->SetNewFor("BaseEncoding", "WinAnsiEncoding"); CPDF_Array* pArray = pEncodingDict->SetNewFor("Differences"); pArray->AddNew(128); const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j++) { ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); pArray->AddNew(name.IsEmpty() ? ".notdef" : name); } pBaseDict->SetNewFor("Encoding", GetDocument(), pEncodingDict->GetObjNum()); return i; } CPDF_Dictionary* CPDF_DocPageData::ProcessbCJK( CPDF_Dictionary* pBaseDict, int charset, ByteString basefont, std::function Insert) { CPDF_Dictionary* pFontDict = GetDocument()->NewIndirect(); ByteString cmap; ByteString ordering; int supplement = 0; CPDF_Array* pWidthArray = pFontDict->SetNewFor("W"); switch (charset) { case FX_CHARSET_ChineseTraditional: cmap = "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; pWidthArray->AddNew(1); Insert(0x20, 0x7e, pWidthArray); break; case FX_CHARSET_ChineseSimplified: cmap = "GBK-EUC-H"; ordering = "GB1"; supplement = 2; pWidthArray->AddNew(7716); Insert(0x20, 0x20, pWidthArray); pWidthArray->AddNew(814); Insert(0x21, 0x7e, pWidthArray); break; case FX_CHARSET_Hangul: cmap = "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; pWidthArray->AddNew(1); Insert(0x20, 0x7e, pWidthArray); break; case FX_CHARSET_ShiftJIS: cmap = "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; pWidthArray->AddNew(231); Insert(0x20, 0x7d, pWidthArray); pWidthArray->AddNew(326); Insert(0xa0, 0xa0, pWidthArray); pWidthArray->AddNew(327); Insert(0xa1, 0xdf, pWidthArray); pWidthArray->AddNew(631); Insert(0x7e, 0x7e, pWidthArray); break; } pBaseDict->SetNewFor("Subtype", "Type0"); pBaseDict->SetNewFor("BaseFont", basefont); pBaseDict->SetNewFor("Encoding", cmap); pFontDict->SetNewFor("Type", "Font"); pFontDict->SetNewFor("Subtype", "CIDFontType2"); pFontDict->SetNewFor("BaseFont", basefont); CPDF_Dictionary* pCIDSysInfo = pFontDict->SetNewFor("CIDSystemInfo"); pCIDSysInfo->SetNewFor("Registry", "Adobe", false); pCIDSysInfo->SetNewFor("Ordering", ordering, false); pCIDSysInfo->SetNewFor("Supplement", supplement); CPDF_Array* pArray = pBaseDict->SetNewFor("DescendantFonts"); pArray->AddNew(GetDocument(), pFontDict->GetObjNum()); return pFontDict; }