// Copyright 2014 The PDFium Authors // 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 #include "build/build_config.h" #include "constants/font_encodings.h" #include "core/fpdfapi/font/cpdf_fontglobals.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_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/fxcodec/icc/icc_transform.h" #include "core/fxcrt/check.h" #include "core/fxcrt/containers/contains.h" #include "core/fxcrt/fixed_size_data_vector.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxcrt/fx_memory.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/scoped_set_insertion.h" #include "core/fxcrt/span.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" 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->AppendNew(first + static_cast(widths.size()) - 1); pWidthArray->AppendNew(widths[0]); return; } auto pWidthArray1 = pWidthArray->AppendNew(); for (int w : widths) pWidthArray1->AppendNew(w); } #if BUILDFLAG(IS_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) { auto buffer = FixedSizeDataVector::Uninit(size); ::GetFontData(hDC, 'eman', 0, buffer.span().data(), buffer.size()); result = GetNameFromTT(buffer, 6); } return result; } #endif // BUILDFLAG(IS_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(RetainPtr 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_ImageMap) { it.second->WillBeDestroyed(); } for (auto& it : m_FontMap) { it.second->WillBeDestroyed(); } } CPDF_DocPageData::HashIccProfileKey::HashIccProfileKey( DataVector digest, uint32_t components) : digest(std::move(digest)), components(components) {} CPDF_DocPageData::HashIccProfileKey::HashIccProfileKey( const HashIccProfileKey& that) = default; CPDF_DocPageData::HashIccProfileKey::~HashIccProfileKey() = default; bool CPDF_DocPageData::HashIccProfileKey::operator<( const HashIccProfileKey& other) const { if (components == other.components) { return digest < other.digest; } return components < other.components; } void CPDF_DocPageData::ClearStockFont() { CPDF_FontGlobals::GetInstance()->Clear(GetDocument()); } RetainPtr CPDF_DocPageData::GetFont( RetainPtr 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[std::move(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); } auto 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[std::move(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::Contains(*pVisitedInternal, pCSObj)) return nullptr; ScopedSetInsertion insertion(pVisitedInternal, pCSObj); if (pCSObj->IsName()) { ByteString name = pCSObj->GetString(); RetainPtr pCS = CPDF_ColorSpace::GetStockCSForName(name); if (!pCS && pResources) { RetainPtr pList = pResources->GetDictFor("ColorSpace"); if (pList) { return GetColorSpaceInternal(pList->GetDirectObjectFor(name).Get(), nullptr, pVisited, pVisitedInternal); } } if (!pCS || !pResources) return pCS; RetainPtr pColorSpaces = pResources->GetDictFor("ColorSpace"); if (!pColorSpaces) return pCS; RetainPtr pDefaultCS; switch (pCS->GetFamily()) { case CPDF_ColorSpace::Family::kDeviceRGB: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); break; case CPDF_ColorSpace::Family::kDeviceGray: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); break; case CPDF_ColorSpace::Family::kDeviceCMYK: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); break; default: break; } if (!pDefaultCS) return pCS; return GetColorSpaceInternal(pDefaultCS.Get(), nullptr, pVisited, pVisitedInternal); } RetainPtr pArray(pCSObj->AsArray()); if (!pArray || pArray->IsEmpty()) return nullptr; if (pArray->size() == 1) { return GetColorSpaceInternal(pArray->GetDirectObjectAt(0).Get(), pResources, pVisited, pVisitedInternal); } auto it = m_ColorSpaceMap.find(pArray); if (it != m_ColorSpaceMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr pCS = CPDF_ColorSpace::Load(GetDocument(), pArray.Get(), pVisited); if (!pCS) return nullptr; m_ColorSpaceMap[std::move(pArray)].Reset(pCS.Get()); return pCS; } RetainPtr CPDF_DocPageData::GetPattern( RetainPtr pPatternObj, const CFX_Matrix& matrix) { CHECK(pPatternObj->IsDictionary() || pPatternObj->IsStream()); auto it = m_PatternMap.find(pPatternObj); if (it != m_PatternMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr pattern; switch (pPatternObj->GetDict()->GetIntegerFor("PatternType")) { case CPDF_Pattern::kTiling: pattern = pdfium::MakeRetain(GetDocument(), pPatternObj, matrix); break; case CPDF_Pattern::kShading: pattern = pdfium::MakeRetain( GetDocument(), pPatternObj, false, matrix); break; default: return nullptr; } m_PatternMap[pPatternObj].Reset(pattern.Get()); return pattern; } RetainPtr CPDF_DocPageData::GetShading( RetainPtr pPatternObj, const CFX_Matrix& matrix) { CHECK(pPatternObj->IsDictionary() || pPatternObj->IsStream()); auto it = m_PatternMap.find(pPatternObj); if (it != m_PatternMap.end() && it->second) return pdfium::WrapRetain(it->second->AsShadingPattern()); auto pPattern = pdfium::MakeRetain( GetDocument(), pPatternObj, true, matrix); m_PatternMap[pPatternObj].Reset(pPattern.Get()); return pPattern; } RetainPtr CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) { DCHECK(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) { DCHECK(dwStreamObjNum); auto it = m_ImageMap.find(dwStreamObjNum); if (it != m_ImageMap.end() && it->second->HasOneRef()) m_ImageMap.erase(it); } RetainPtr CPDF_DocPageData::GetIccProfile( RetainPtr pProfileStream) { CHECK(pProfileStream); auto it = m_IccProfileMap.find(pProfileStream); if (it != m_IccProfileMap.end()) { return it->second; } auto pAccessor = pdfium::MakeRetain(pProfileStream); pAccessor->LoadAllDataFiltered(); // This should not fail, as the caller should have checked this already. const int expected_components = pProfileStream->GetDict()->GetIntegerFor("N"); CHECK(fxcodec::IccTransform::IsValidIccComponents(expected_components)); // Since CPDF_IccProfile can behave differently depending on // `expected_components`, `hash_profile_key` needs to take that into // consideration, in addition to the digest value. const HashIccProfileKey hash_profile_key(pAccessor->ComputeDigest(), expected_components); auto hash_it = m_HashIccProfileMap.find(hash_profile_key); if (hash_it != m_HashIccProfileMap.end()) { auto it_copied_stream = m_IccProfileMap.find(hash_it->second); if (it_copied_stream != m_IccProfileMap.end()) { return it_copied_stream->second; } } auto pProfile = pdfium::MakeRetain(pAccessor, expected_components); m_IccProfileMap[pProfileStream] = pProfile; m_HashIccProfileMap[hash_profile_key] = std::move(pProfileStream); return pProfile; } RetainPtr CPDF_DocPageData::GetFontFileStreamAcc( RetainPtr pFontStream) { DCHECK(pFontStream); auto it = m_FontFileMap.find(pFontStream); if (it != m_FontFileMap.end()) return it->second; RetainPtr 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[std::move(pFontStream)] = pFontAcc; return pFontAcc; } void CPDF_DocPageData::MaybePurgeFontFileStreamAcc( RetainPtr&& pStreamAcc) { if (!pStreamAcc) return; RetainPtr pFontStream = pStreamAcc->GetStream(); if (!pFontStream) return; pStreamAcc.Reset(); // Drop moved caller's reference. 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, RetainPtr pPageResources, RetainPtr pFormStream) { return std::make_unique(pDocument, std::move(pPageResources), std::move(pFormStream)); } RetainPtr CPDF_DocPageData::AddStandardFont( const ByteString& fontName, const CPDF_FontEncoding* pEncoding) { ByteString mutable_name(fontName); std::optional font_id = CFX_FontMapper::GetStandardFontName(&mutable_name); if (!font_id.has_value()) return nullptr; return GetStandardFont(mutable_name, pEncoding); } RetainPtr CPDF_DocPageData::AddFont(std::unique_ptr pFont, FX_Charset 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::kSymbol); auto pBaseDict = GetDocument()->NewIndirect(); pBaseDict->SetNewFor("Type", "Font"); auto pEncoding = std::make_unique(pFont.get()); RetainPtr 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->AppendNew(char_width); } if (charset == FX_Charset::kANSI || charset == FX_Charset::kDefault || charset == FX_Charset::kSymbol) { pBaseDict->SetNewFor("Encoding", pdfium::font_encodings::kWinAnsiEncoding); for (int charcode = 128; charcode <= 255; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); pWidths->AppendNew(char_width); } } else { size_t i = CalculateEncodingDict(charset, pBaseDict.Get()); if (i < std::size(kFX_CharsetUnicodes)) { pdfium::span pUnicodes = kFX_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->AppendNew(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().value_or(FX_RECT()); auto pBBox = pdfium::MakeRetain(); pBBox->AppendNew(bbox.left); pBBox->AppendNew(bbox.bottom); pBBox->AppendNew(bbox.right); pBBox->AppendNew(bbox.top); int32_t nStemV = 0; if (pFont->GetSubstFont()) { nStemV = pFont->GetSubstFont()->m_Weight / 5; } else { static constexpr char kStemChars[] = {'i', 'I', '!', '1'}; static constexpr pdfium::span kStemSpan{kStemChars}; uint32_t glyph = pEncoding->GlyphFromCharCode(kStemSpan.front()); const auto remaining = kStemSpan.subspan<1>(); nStemV = pFont->GetGlyphWidth(glyph); for (auto ch : remaining) { glyph = pEncoding->GlyphFromCharCode(ch); int width = pFont->GetGlyphWidth(glyph); if (width > 0 && width < nStemV) nStemV = width; } } RetainPtr pFontDesc = CalculateFontDesc( GetDocument(), basefont, flags, italicangle, pFont->GetAscent(), pFont->GetDescent(), std::move(pBBox), nStemV); uint32_t new_objnum = GetDocument()->AddIndirectObject(std::move(pFontDesc)); pFontDict->SetNewFor("FontDescriptor", GetDocument(), new_objnum); return GetFont(pBaseDict); } #if BUILDFLAG(IS_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 == static_cast(FX_Charset::kSymbol)); const FX_Charset eCharset = FX_GetCharsetFromInt(pLogFont->lfCharSet); const bool bCJK = FX_CharSetIsCJK(eCharset); 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; std::array bbox = {{ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}}; FX_Free(tm_buf); basefont.Replace(" ", ""); auto pBaseDict = GetDocument()->NewIndirect(); pBaseDict->SetNewFor("Type", "Font"); RetainPtr pFontDict = pBaseDict; if (!bCJK) { if (eCharset == FX_Charset::kANSI || eCharset == FX_Charset::kDefault || eCharset == FX_Charset::kSymbol) { pBaseDict->SetNewFor("Encoding", pdfium::font_encodings::kWinAnsiEncoding); } else { CalculateEncodingDict(eCharset, pBaseDict.Get()); } std::array char_widths; GetCharWidth(hDC, 32, 255, char_widths.data()); auto pWidths = pdfium::MakeRetain(); for (const auto char_width : char_widths) { pWidths->AppendNew(char_width); } ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, std::move(pWidths)); } else { pFontDict = ProcessbCJK(pBaseDict, eCharset, basefont, [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } auto pBBox = pdfium::MakeRetain(); for (const auto bound : bbox) { pBBox->AppendNew(bound); } RetainPtr pFontDesc = CalculateFontDesc(GetDocument(), basefont, flags, italicangle, ascend, descend, std::move(pBBox), pLogFont->lfWeight / 5); pFontDesc->SetNewFor("CapHeight", capheight); GetDocument()->AddIndirectObject(pFontDesc); pFontDict->SetFor("FontDescriptor", pFontDesc->MakeReference(GetDocument())); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return GetFont(std::move(pBaseDict)); } #endif // BUILDFLAG(IS_WIN) size_t CPDF_DocPageData::CalculateEncodingDict(FX_Charset charset, CPDF_Dictionary* pBaseDict) { size_t i; for (i = 0; i < std::size(kFX_CharsetUnicodes); ++i) { if (kFX_CharsetUnicodes[i].m_Charset == charset) break; } if (i == std::size(kFX_CharsetUnicodes)) return i; auto pEncodingDict = GetDocument()->NewIndirect(); pEncodingDict->SetNewFor("BaseEncoding", pdfium::font_encodings::kWinAnsiEncoding); auto pArray = pEncodingDict->SetNewFor("Differences"); pArray->AppendNew(128); pdfium::span pUnicodes = kFX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j++) { ByteString name = AdobeNameFromUnicode(pUnicodes[j]); pArray->AppendNew(name.IsEmpty() ? ".notdef" : name); } pBaseDict->SetNewFor("Encoding", GetDocument(), pEncodingDict->GetObjNum()); return i; } RetainPtr CPDF_DocPageData::ProcessbCJK( RetainPtr pBaseDict, FX_Charset charset, ByteString basefont, std::function Insert) { auto pFontDict = GetDocument()->NewIndirect(); ByteString cmap; ByteString ordering; int supplement = 0; auto pWidthArray = pFontDict->SetNewFor("W"); switch (charset) { case FX_Charset::kChineseTraditional: cmap = "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; pWidthArray->AppendNew(1); Insert(0x20, 0x7e, pWidthArray.Get()); break; case FX_Charset::kChineseSimplified: cmap = "GBK-EUC-H"; ordering = "GB1"; supplement = 2; pWidthArray->AppendNew(7716); Insert(0x20, 0x20, pWidthArray.Get()); pWidthArray->AppendNew(814); Insert(0x21, 0x7e, pWidthArray.Get()); break; case FX_Charset::kHangul: cmap = "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; pWidthArray->AppendNew(1); Insert(0x20, 0x7e, pWidthArray.Get()); break; case FX_Charset::kShiftJIS: cmap = "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; pWidthArray->AppendNew(231); Insert(0x20, 0x7d, pWidthArray.Get()); pWidthArray->AppendNew(326); Insert(0xa0, 0xa0, pWidthArray.Get()); pWidthArray->AppendNew(327); Insert(0xa1, 0xdf, pWidthArray.Get()); pWidthArray->AppendNew(631); Insert(0x7e, 0x7e, pWidthArray.Get()); break; default: 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); auto pCIDSysInfo = pFontDict->SetNewFor("CIDSystemInfo"); pCIDSysInfo->SetNewFor("Registry", "Adobe"); pCIDSysInfo->SetNewFor("Ordering", ordering); pCIDSysInfo->SetNewFor("Supplement", supplement); auto pArray = pBaseDict->SetNewFor("DescendantFonts"); pArray->AppendNew(GetDocument(), pFontDict->GetObjNum()); return pFontDict; }