blob: 13f5db244b263a3c871f447d517421260243e88d [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// Copyright 2014 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.
Lei Zhang95e854f2015-06-13 00:58:06 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
dsinclair488b7ad2016-10-04 11:55:50 -07007#include "core/fpdfapi/parser/cpdf_document.h"
Tom Sepez461a26d2015-06-02 14:29:00 -07008
thestig823df2a2016-07-29 06:15:39 -07009#include <memory>
Wei Li215816b2016-01-14 12:29:02 -080010#include <set>
tsepez0e606b52016-11-18 16:22:41 -080011#include <utility>
thestig823df2a2016-07-29 06:15:39 -070012#include <vector>
Wei Li215816b2016-01-14 12:29:02 -080013
dsinclair39c62fd2016-09-29 12:49:17 -070014#include "core/fpdfapi/cpdf_modulemgr.h"
dsinclairbc5e6d22016-10-04 11:08:49 -070015#include "core/fpdfapi/font/cpdf_fontencoding.h"
tsepez9fa95ef2016-10-11 12:29:38 -070016#include "core/fpdfapi/page/cpdf_docpagedata.h"
Dan Sinclair5acacd32017-05-25 14:04:59 -040017#include "core/fpdfapi/page/cpdf_iccprofile.h"
dsinclair41872fa2016-10-04 11:29:35 -070018#include "core/fpdfapi/page/cpdf_pagemodule.h"
dsinclair488b7ad2016-10-04 11:55:50 -070019#include "core/fpdfapi/parser/cpdf_array.h"
20#include "core/fpdfapi/parser/cpdf_dictionary.h"
tsepezc09625c2016-11-07 11:46:09 -080021#include "core/fpdfapi/parser/cpdf_linearized_header.h"
tsepez8a3aa452016-11-16 12:26:06 -080022#include "core/fpdfapi/parser/cpdf_name.h"
tsepez10a28532016-10-10 18:45:55 -070023#include "core/fpdfapi/parser/cpdf_number.h"
dsinclair488b7ad2016-10-04 11:55:50 -070024#include "core/fpdfapi/parser/cpdf_parser.h"
25#include "core/fpdfapi/parser/cpdf_reference.h"
26#include "core/fpdfapi/parser/cpdf_stream.h"
dsinclair37b6d142016-11-21 17:05:58 -080027#include "core/fpdfapi/parser/cpdf_string.h"
Nicolas Pena0ef7ba02017-01-04 16:18:57 -050028#include "core/fpdfapi/render/cpdf_dibsource.h"
npm935c6312016-11-17 10:47:43 -080029#include "core/fpdfapi/render/cpdf_docrenderdata.h"
dsinclair8a4e2862016-09-29 13:43:30 -070030#include "core/fxcodec/JBig2_DocumentContext.h"
Dan Sinclairf51a02a2017-04-19 12:46:53 -040031#include "core/fxcrt/fx_codepage.h"
dsinclair74a34fc2016-09-29 16:41:42 -070032#include "core/fxge/cfx_unicodeencoding.h"
33#include "core/fxge/fx_font.h"
tsepez36eb4bd2016-10-03 15:24:27 -070034#include "third_party/base/ptr_util.h"
Wei Li215816b2016-01-14 12:29:02 -080035#include "third_party/base/stl_util.h"
36
37namespace {
38
thestig931bf372016-04-26 22:24:30 -070039const int FX_MAX_PAGE_LEVEL = 1024;
40
npme9988dd2016-09-16 13:57:22 -070041void InsertWidthArrayImpl(int* widths, int size, CPDF_Array* pWidthArray) {
thestig931bf372016-04-26 22:24:30 -070042 int i;
43 for (i = 1; i < size; i++) {
44 if (widths[i] != *widths)
45 break;
46 }
47 if (i == size) {
48 int first = pWidthArray->GetIntegerAt(pWidthArray->GetCount() - 1);
tsepez8a3aa452016-11-16 12:26:06 -080049 pWidthArray->AddNew<CPDF_Number>(first + size - 1);
50 pWidthArray->AddNew<CPDF_Number>(*widths);
thestig931bf372016-04-26 22:24:30 -070051 } else {
tsepez8a3aa452016-11-16 12:26:06 -080052 CPDF_Array* pWidthArray1 = pWidthArray->AddNew<CPDF_Array>();
npm01b67ed2016-09-12 13:38:52 -070053 for (i = 0; i < size; i++)
tsepez8a3aa452016-11-16 12:26:06 -080054 pWidthArray1->AddNew<CPDF_Number>(widths[i]);
thestig931bf372016-04-26 22:24:30 -070055 }
56 FX_Free(widths);
57}
58
Dan Sinclair698aed72017-09-26 16:24:49 -040059#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
npme9988dd2016-09-16 13:57:22 -070060void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) {
61 int size = end - start + 1;
62 int* widths = FX_Alloc(int, size);
63 GetCharWidth(hDC, start, end, widths);
64 InsertWidthArrayImpl(widths, size, pWidthArray);
65}
66
Ryan Harrison275e2602017-09-18 14:23:18 -040067ByteString FPDF_GetPSNameFromTT(HDC hDC) {
68 ByteString result;
thestig931bf372016-04-26 22:24:30 -070069 DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0);
70 if (size != GDI_ERROR) {
71 LPBYTE buffer = FX_Alloc(BYTE, size);
72 ::GetFontData(hDC, 'eman', 0, buffer, size);
73 result = GetNameFromTT(buffer, size, 6);
74 FX_Free(buffer);
75 }
76 return result;
77}
Dan Sinclair698aed72017-09-26 16:24:49 -040078#endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
thestig931bf372016-04-26 22:24:30 -070079
thestig931bf372016-04-26 22:24:30 -070080void InsertWidthArray1(CFX_Font* pFont,
81 CFX_UnicodeEncoding* pEncoding,
Dan Sinclair812e96c2017-03-13 16:43:37 -040082 wchar_t start,
83 wchar_t end,
thestig931bf372016-04-26 22:24:30 -070084 CPDF_Array* pWidthArray) {
85 int size = end - start + 1;
86 int* widths = FX_Alloc(int, size);
87 int i;
88 for (i = 0; i < size; i++) {
89 int glyph_index = pEncoding->GlyphFromCharCode(start + i);
90 widths[i] = pFont->GetGlyphWidth(glyph_index);
91 }
npme9988dd2016-09-16 13:57:22 -070092 InsertWidthArrayImpl(widths, size, pWidthArray);
thestig931bf372016-04-26 22:24:30 -070093}
94
Wei Li215816b2016-01-14 12:29:02 -080095int CountPages(CPDF_Dictionary* pPages,
96 std::set<CPDF_Dictionary*>* visited_pages) {
dsinclair38fd8442016-09-15 10:15:32 -070097 int count = pPages->GetIntegerFor("Count");
npm01b67ed2016-09-12 13:38:52 -070098 if (count > 0 && count < FPDF_PAGE_MAX_NUM)
Wei Li215816b2016-01-14 12:29:02 -080099 return count;
dsinclair38fd8442016-09-15 10:15:32 -0700100 CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
npm01b67ed2016-09-12 13:38:52 -0700101 if (!pKidList)
Wei Li215816b2016-01-14 12:29:02 -0800102 return 0;
Wei Li215816b2016-01-14 12:29:02 -0800103 count = 0;
Wei Lie1aebd42016-04-11 10:02:09 -0700104 for (size_t i = 0; i < pKidList->GetCount(); i++) {
Wei Li9b761132016-01-29 15:44:20 -0800105 CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
npm01b67ed2016-09-12 13:38:52 -0700106 if (!pKid || pdfium::ContainsKey(*visited_pages, pKid))
Wei Li215816b2016-01-14 12:29:02 -0800107 continue;
Wei Li215816b2016-01-14 12:29:02 -0800108 if (pKid->KeyExist("Kids")) {
109 // Use |visited_pages| to help detect circular references of pages.
Tom Sepez99406192016-03-09 17:37:12 -0800110 pdfium::ScopedSetInsertion<CPDF_Dictionary*> local_add(visited_pages,
111 pKid);
Wei Li215816b2016-01-14 12:29:02 -0800112 count += CountPages(pKid, visited_pages);
113 } else {
114 // This page is a leaf node.
115 count++;
116 }
117 }
tsepez0e606b52016-11-18 16:22:41 -0800118 pPages->SetNewFor<CPDF_Number>("Count", count);
Wei Li215816b2016-01-14 12:29:02 -0800119 return count;
120}
121
npm01b67ed2016-09-12 13:38:52 -0700122int CalculateFlags(bool bold,
123 bool italic,
124 bool fixedPitch,
125 bool serif,
126 bool script,
127 bool symbolic) {
128 int flags = 0;
129 if (bold)
Nicolas Pena412fa652017-02-24 16:16:02 -0500130 flags |= FXFONT_BOLD;
npm01b67ed2016-09-12 13:38:52 -0700131 if (italic)
Nicolas Pena412fa652017-02-24 16:16:02 -0500132 flags |= FXFONT_ITALIC;
npm01b67ed2016-09-12 13:38:52 -0700133 if (fixedPitch)
Nicolas Pena412fa652017-02-24 16:16:02 -0500134 flags |= FXFONT_FIXED_PITCH;
npm01b67ed2016-09-12 13:38:52 -0700135 if (serif)
Nicolas Pena412fa652017-02-24 16:16:02 -0500136 flags |= FXFONT_SERIF;
npm01b67ed2016-09-12 13:38:52 -0700137 if (script)
Nicolas Pena412fa652017-02-24 16:16:02 -0500138 flags |= FXFONT_SCRIPT;
npm01b67ed2016-09-12 13:38:52 -0700139 if (symbolic)
Nicolas Pena412fa652017-02-24 16:16:02 -0500140 flags |= FXFONT_SYMBOLIC;
npm01b67ed2016-09-12 13:38:52 -0700141 else
Nicolas Pena412fa652017-02-24 16:16:02 -0500142 flags |= FXFONT_NONSYMBOLIC;
npm01b67ed2016-09-12 13:38:52 -0700143 return flags;
144}
145
146void ProcessNonbCJK(CPDF_Dictionary* pBaseDict,
147 bool bold,
148 bool italic,
Ryan Harrison275e2602017-09-18 14:23:18 -0400149 ByteString basefont,
tsepez06104a82016-11-21 16:22:10 -0800150 std::unique_ptr<CPDF_Array> pWidths) {
npm01b67ed2016-09-12 13:38:52 -0700151 if (bold && italic)
152 basefont += ",BoldItalic";
153 else if (bold)
154 basefont += ",Bold";
155 else if (italic)
156 basefont += ",Italic";
tsepez0e606b52016-11-18 16:22:41 -0800157 pBaseDict->SetNewFor<CPDF_Name>("Subtype", "TrueType");
158 pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
159 pBaseDict->SetNewFor<CPDF_Number>("FirstChar", 32);
160 pBaseDict->SetNewFor<CPDF_Number>("LastChar", 255);
tsepez06104a82016-11-21 16:22:10 -0800161 pBaseDict->SetFor("Widths", std::move(pWidths));
npm01b67ed2016-09-12 13:38:52 -0700162}
163
tsepez06104a82016-11-21 16:22:10 -0800164std::unique_ptr<CPDF_Dictionary> CalculateFontDesc(
165 CPDF_Document* pDoc,
Ryan Harrison275e2602017-09-18 14:23:18 -0400166 ByteString basefont,
tsepez06104a82016-11-21 16:22:10 -0800167 int flags,
168 int italicangle,
169 int ascend,
170 int descend,
171 std::unique_ptr<CPDF_Array> bbox,
172 int32_t stemV) {
tsepez70c4afd2016-11-15 11:33:44 -0800173 auto pFontDesc =
174 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
tsepez0e606b52016-11-18 16:22:41 -0800175 pFontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
176 pFontDesc->SetNewFor<CPDF_Name>("FontName", basefont);
177 pFontDesc->SetNewFor<CPDF_Number>("Flags", flags);
tsepez06104a82016-11-21 16:22:10 -0800178 pFontDesc->SetFor("FontBBox", std::move(bbox));
tsepez0e606b52016-11-18 16:22:41 -0800179 pFontDesc->SetNewFor<CPDF_Number>("ItalicAngle", italicangle);
180 pFontDesc->SetNewFor<CPDF_Number>("Ascent", ascend);
181 pFontDesc->SetNewFor<CPDF_Number>("Descent", descend);
182 pFontDesc->SetNewFor<CPDF_Number>("StemV", stemV);
npme9988dd2016-09-16 13:57:22 -0700183 return pFontDesc;
184}
185
Wei Li215816b2016-01-14 12:29:02 -0800186} // namespace
Wei Liaa0f69a2016-01-07 10:49:33 -0800187
dsinclaircedaa552016-08-24 11:12:19 -0700188CPDF_Document::CPDF_Document(std::unique_ptr<CPDF_Parser> pParser)
dsinclaira61c01e2016-08-24 10:31:23 -0700189 : CPDF_IndirectObjectHolder(),
dsinclaircedaa552016-08-24 11:12:19 -0700190 m_pParser(std::move(pParser)),
dsinclaird647a6b2016-04-26 13:13:20 -0700191 m_pRootDict(nullptr),
npmec64cee2016-11-04 12:54:51 -0700192 m_iNextPageToTraverse(0),
Nicolas Pena83c5eac2017-01-03 14:33:20 -0500193 m_bReachedMaxPageLevel(false),
dsinclaird647a6b2016-04-26 13:13:20 -0700194 m_bLinearized(false),
thestig931bf372016-04-26 22:24:30 -0700195 m_iFirstPageNo(0),
dsinclaird647a6b2016-04-26 13:13:20 -0700196 m_dwFirstPageObjNum(0),
Tom Sepez012ae892017-04-25 16:39:34 -0700197 m_pDocPage(pdfium::MakeUnique<CPDF_DocPageData>(this)),
198 m_pDocRender(pdfium::MakeUnique<CPDF_DocRenderData>(this)) {
dsinclaira61c01e2016-08-24 10:31:23 -0700199 if (pParser)
200 SetLastObjNum(m_pParser->GetLastObjNum());
201}
dsinclaird647a6b2016-04-26 13:13:20 -0700202
thestig931bf372016-04-26 22:24:30 -0700203CPDF_Document::~CPDF_Document() {
npmfd5ae3f2016-10-21 09:42:33 -0700204 CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700205}
dsinclaird647a6b2016-04-26 13:13:20 -0700206
tsepez5ab31ef2016-11-07 13:49:17 -0800207std::unique_ptr<CPDF_Object> CPDF_Document::ParseIndirectObject(
208 uint32_t objnum) {
dsinclaira61c01e2016-08-24 10:31:23 -0700209 return m_pParser ? m_pParser->ParseIndirectObject(this, objnum) : nullptr;
210}
211
dsinclair260f5fb2016-08-17 12:45:26 -0700212void CPDF_Document::LoadDocInternal() {
dsinclair03bd7c72016-08-23 20:13:41 -0700213 SetLastObjNum(m_pParser->GetLastObjNum());
dsinclair260f5fb2016-08-17 12:45:26 -0700214
dsinclair03bd7c72016-08-23 20:13:41 -0700215 CPDF_Object* pRootObj = GetOrParseIndirectObject(m_pParser->GetRootObjNum());
dsinclairf85e7e22016-08-16 11:43:23 -0700216 if (!pRootObj)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700217 return;
dsinclairf85e7e22016-08-16 11:43:23 -0700218
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700219 m_pRootDict = pRootObj->GetDict();
dsinclairf85e7e22016-08-16 11:43:23 -0700220 if (!m_pRootDict)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700221 return;
dsinclairf85e7e22016-08-16 11:43:23 -0700222
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -0400223 LoadDocumentInfo();
224}
225
226void CPDF_Document::LoadDocumentInfo() {
Lei Zhangd78ef3b2017-10-20 17:23:40 -0700227 if (!m_pParser)
228 return;
229
dsinclair03bd7c72016-08-23 20:13:41 -0700230 CPDF_Object* pInfoObj = GetOrParseIndirectObject(m_pParser->GetInfoObjNum());
dsinclairf85e7e22016-08-16 11:43:23 -0700231 if (pInfoObj)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700232 m_pInfoDict = pInfoObj->GetDict();
dsinclairf85e7e22016-08-16 11:43:23 -0700233}
234
235void CPDF_Document::LoadDoc() {
236 LoadDocInternal();
tsepez0fa47172017-01-09 07:01:36 -0800237 LoadPages();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700238}
thestig931bf372016-04-26 22:24:30 -0700239
art-snake240dec52016-11-07 08:42:04 -0800240void CPDF_Document::LoadLinearizedDoc(
tsepezc09625c2016-11-07 11:46:09 -0800241 const CPDF_LinearizedHeader* pLinearizationParams) {
thestig931bf372016-04-26 22:24:30 -0700242 m_bLinearized = true;
dsinclairf85e7e22016-08-16 11:43:23 -0700243 LoadDocInternal();
tsepez0fa47172017-01-09 07:01:36 -0800244 m_PageList.resize(pLinearizationParams->GetPageCount());
art-snake240dec52016-11-07 08:42:04 -0800245 m_iFirstPageNo = pLinearizationParams->GetFirstPageNo();
246 m_dwFirstPageObjNum = pLinearizationParams->GetFirstPageObjNum();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700247}
dsinclaird647a6b2016-04-26 13:13:20 -0700248
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700249void CPDF_Document::LoadPages() {
tsepez0fa47172017-01-09 07:01:36 -0800250 m_PageList.resize(RetrievePageCount());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700251}
dsinclaird647a6b2016-04-26 13:13:20 -0700252
npmec64cee2016-11-04 12:54:51 -0700253CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage,
254 int* nPagesToGo,
255 size_t level) {
Nicolas Pena83c5eac2017-01-03 14:33:20 -0500256 if (*nPagesToGo < 0 || m_bReachedMaxPageLevel)
thestig931bf372016-04-26 22:24:30 -0700257 return nullptr;
tsepez0fa47172017-01-09 07:01:36 -0800258
npmec64cee2016-11-04 12:54:51 -0700259 CPDF_Dictionary* pPages = m_pTreeTraversal[level].first;
260 CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
261 if (!pKidList) {
Nicolas Pena478c2262017-03-21 14:06:04 -0400262 m_pTreeTraversal.pop_back();
npmec64cee2016-11-04 12:54:51 -0700263 if (*nPagesToGo != 1)
264 return nullptr;
tsepez0fa47172017-01-09 07:01:36 -0800265 m_PageList[iPage] = pPages->GetObjNum();
npmec64cee2016-11-04 12:54:51 -0700266 return pPages;
267 }
npmec64cee2016-11-04 12:54:51 -0700268 if (level >= FX_MAX_PAGE_LEVEL) {
269 m_pTreeTraversal.pop_back();
Nicolas Pena83c5eac2017-01-03 14:33:20 -0500270 m_bReachedMaxPageLevel = true;
npmec64cee2016-11-04 12:54:51 -0700271 return nullptr;
272 }
npmec64cee2016-11-04 12:54:51 -0700273 CPDF_Dictionary* page = nullptr;
274 for (size_t i = m_pTreeTraversal[level].second; i < pKidList->GetCount();
275 i++) {
276 if (*nPagesToGo == 0)
277 break;
Artem Strygin3fab4e32017-08-23 22:16:13 +0300278 pKidList->ConvertToIndirectObjectAt(i, this);
Wei Li9b761132016-01-29 15:44:20 -0800279 CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
Lei Zhang412e9082015-12-14 18:34:00 -0800280 if (!pKid) {
npmec64cee2016-11-04 12:54:51 -0700281 (*nPagesToGo)--;
282 m_pTreeTraversal[level].second++;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700283 continue;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700284 }
npmec64cee2016-11-04 12:54:51 -0700285 if (pKid == pPages) {
286 m_pTreeTraversal[level].second++;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700287 continue;
npmec64cee2016-11-04 12:54:51 -0700288 }
Lei Zhangd983b092015-12-14 16:58:33 -0800289 if (!pKid->KeyExist("Kids")) {
tsepez0fa47172017-01-09 07:01:36 -0800290 m_PageList[iPage - (*nPagesToGo) + 1] = pKid->GetObjNum();
npmec64cee2016-11-04 12:54:51 -0700291 (*nPagesToGo)--;
292 m_pTreeTraversal[level].second++;
293 if (*nPagesToGo == 0) {
294 page = pKid;
295 break;
296 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700297 } else {
npmec64cee2016-11-04 12:54:51 -0700298 // If the vector has size level+1, the child is not in yet
299 if (m_pTreeTraversal.size() == level + 1)
300 m_pTreeTraversal.push_back(std::make_pair(pKid, 0));
301 // Now m_pTreeTraversal[level+1] should exist and be equal to pKid.
302 CPDF_Dictionary* pageKid = TraversePDFPages(iPage, nPagesToGo, level + 1);
303 // Check if child was completely processed, i.e. it popped itself out
304 if (m_pTreeTraversal.size() == level + 1)
305 m_pTreeTraversal[level].second++;
Nicolas Pena83c5eac2017-01-03 14:33:20 -0500306 // If child did not finish, no pages to go, or max level reached, end
307 if (m_pTreeTraversal.size() != level + 1 || *nPagesToGo == 0 ||
308 m_bReachedMaxPageLevel) {
npmec64cee2016-11-04 12:54:51 -0700309 page = pageKid;
310 break;
311 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700312 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700313 }
npmec64cee2016-11-04 12:54:51 -0700314 if (m_pTreeTraversal[level].second == pKidList->GetCount())
315 m_pTreeTraversal.pop_back();
316 return page;
317}
318
319void CPDF_Document::ResetTraversal() {
320 m_iNextPageToTraverse = 0;
Nicolas Pena83c5eac2017-01-03 14:33:20 -0500321 m_bReachedMaxPageLevel = false;
npmec64cee2016-11-04 12:54:51 -0700322 m_pTreeTraversal.clear();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700323}
Lei Zhang6de7f2f2015-09-03 14:51:53 -0700324
npm01b67ed2016-09-12 13:38:52 -0700325CPDF_Dictionary* CPDF_Document::GetPagesDict() const {
Lei Zhang01581062017-08-30 14:19:26 -0700326 const CPDF_Dictionary* pRoot = GetRoot();
dsinclair38fd8442016-09-15 10:15:32 -0700327 return pRoot ? pRoot->GetDictFor("Pages") : nullptr;
npm01b67ed2016-09-12 13:38:52 -0700328}
329
dsinclair23e173a2016-09-20 12:35:36 -0700330bool CPDF_Document::IsPageLoaded(int iPage) const {
tsepez0fa47172017-01-09 07:01:36 -0800331 return !!m_PageList[iPage];
dsinclair23e173a2016-09-20 12:35:36 -0700332}
333
Tom Sepez967aa072018-05-08 13:40:20 +0000334CPDF_Dictionary* CPDF_Document::GetPageDictionary(int iPage) {
Tom Sepez193e6ca2017-03-14 15:53:36 -0700335 if (!pdfium::IndexInBounds(m_PageList, iPage))
Lei Zhang6de7f2f2015-09-03 14:51:53 -0700336 return nullptr;
337
Tom Sepez193e6ca2017-03-14 15:53:36 -0700338 if (m_bLinearized && iPage == m_iFirstPageNo) {
Dan Sinclairf1251c12015-10-20 16:24:45 -0400339 if (CPDF_Dictionary* pDict =
dsinclair03bd7c72016-08-23 20:13:41 -0700340 ToDictionary(GetOrParseIndirectObject(m_dwFirstPageObjNum))) {
Dan Sinclairf1251c12015-10-20 16:24:45 -0400341 return pDict;
Tom Sepez0f687852016-01-25 13:37:42 -0800342 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700343 }
tsepez0fa47172017-01-09 07:01:36 -0800344 uint32_t objnum = m_PageList[iPage];
345 if (objnum)
346 return ToDictionary(GetOrParseIndirectObject(objnum));
npm900f4212016-10-28 14:30:44 -0700347
348 CPDF_Dictionary* pPages = GetPagesDict();
349 if (!pPages)
350 return nullptr;
351
Nicolas Penac467d462017-03-15 16:21:02 -0400352 if (m_pTreeTraversal.empty()) {
353 ResetTraversal();
npmec64cee2016-11-04 12:54:51 -0700354 m_pTreeTraversal.push_back(std::make_pair(pPages, 0));
Nicolas Penac467d462017-03-15 16:21:02 -0400355 }
356 int nPagesToGo = iPage - m_iNextPageToTraverse + 1;
npmec64cee2016-11-04 12:54:51 -0700357 CPDF_Dictionary* pPage = TraversePDFPages(iPage, &nPagesToGo, 0);
358 m_iNextPageToTraverse = iPage + 1;
npm900f4212016-10-28 14:30:44 -0700359 return pPage;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700360}
Lei Zhang6de7f2f2015-09-03 14:51:53 -0700361
dsinclair23e173a2016-09-20 12:35:36 -0700362void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) {
tsepez0fa47172017-01-09 07:01:36 -0800363 m_PageList[iPage] = objNum;
dsinclair23e173a2016-09-20 12:35:36 -0700364}
365
thestig931bf372016-04-26 22:24:30 -0700366int CPDF_Document::FindPageIndex(CPDF_Dictionary* pNode,
tsepeze507dc52017-01-18 10:24:35 -0800367 uint32_t* skip_count,
thestig931bf372016-04-26 22:24:30 -0700368 uint32_t objnum,
tsepeze507dc52017-01-18 10:24:35 -0800369 int* index,
Lei Zhang01581062017-08-30 14:19:26 -0700370 int level) const {
thestig931bf372016-04-26 22:24:30 -0700371 if (!pNode->KeyExist("Kids")) {
372 if (objnum == pNode->GetObjNum())
tsepeze507dc52017-01-18 10:24:35 -0800373 return *index;
thestig931bf372016-04-26 22:24:30 -0700374
tsepeze507dc52017-01-18 10:24:35 -0800375 if (*skip_count)
376 (*skip_count)--;
thestig931bf372016-04-26 22:24:30 -0700377
tsepeze507dc52017-01-18 10:24:35 -0800378 (*index)++;
thestig931bf372016-04-26 22:24:30 -0700379 return -1;
380 }
381
dsinclair38fd8442016-09-15 10:15:32 -0700382 CPDF_Array* pKidList = pNode->GetArrayFor("Kids");
thestig931bf372016-04-26 22:24:30 -0700383 if (!pKidList)
384 return -1;
385
386 if (level >= FX_MAX_PAGE_LEVEL)
387 return -1;
388
dsinclair38fd8442016-09-15 10:15:32 -0700389 size_t count = pNode->GetIntegerFor("Count");
tsepeze507dc52017-01-18 10:24:35 -0800390 if (count <= *skip_count) {
391 (*skip_count) -= count;
392 (*index) += count;
thestig931bf372016-04-26 22:24:30 -0700393 return -1;
394 }
395
396 if (count && count == pKidList->GetCount()) {
397 for (size_t i = 0; i < count; i++) {
tsepeze507dc52017-01-18 10:24:35 -0800398 CPDF_Reference* pKid = ToReference(pKidList->GetObjectAt(i));
399 if (pKid && pKid->GetRefObjNum() == objnum)
400 return static_cast<int>(*index + i);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700401 }
thestig931bf372016-04-26 22:24:30 -0700402 }
403
404 for (size_t i = 0; i < pKidList->GetCount(); i++) {
405 CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
406 if (!pKid || pKid == pNode)
407 continue;
408
409 int found_index = FindPageIndex(pKid, skip_count, objnum, index, level + 1);
410 if (found_index >= 0)
411 return found_index;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700412 }
413 return -1;
414}
thestig931bf372016-04-26 22:24:30 -0700415
tsepezb5e8f142016-03-25 15:18:35 -0700416int CPDF_Document::GetPageIndex(uint32_t objnum) {
tsepez0fa47172017-01-09 07:01:36 -0800417 uint32_t nPages = m_PageList.size();
tsepezb5e8f142016-03-25 15:18:35 -0700418 uint32_t skip_count = 0;
thestig931bf372016-04-26 22:24:30 -0700419 bool bSkipped = false;
tsepezb5e8f142016-03-25 15:18:35 -0700420 for (uint32_t i = 0; i < nPages; i++) {
tsepez0fa47172017-01-09 07:01:36 -0800421 if (m_PageList[i] == objnum)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700422 return i;
thestig931bf372016-04-26 22:24:30 -0700423
tsepez0fa47172017-01-09 07:01:36 -0800424 if (!bSkipped && m_PageList[i] == 0) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700425 skip_count = i;
thestig931bf372016-04-26 22:24:30 -0700426 bSkipped = true;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700427 }
428 }
npm01b67ed2016-09-12 13:38:52 -0700429 CPDF_Dictionary* pPages = GetPagesDict();
thestig931bf372016-04-26 22:24:30 -0700430 if (!pPages)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700431 return -1;
thestig931bf372016-04-26 22:24:30 -0700432
tsepeze507dc52017-01-18 10:24:35 -0800433 int start_index = 0;
434 int found_index = FindPageIndex(pPages, &skip_count, objnum, &start_index);
435
436 // Corrupt page tree may yield out-of-range results.
Tom Sepez193e6ca2017-03-14 15:53:36 -0700437 if (!pdfium::IndexInBounds(m_PageList, found_index))
tsepeze507dc52017-01-18 10:24:35 -0800438 return -1;
439
440 m_PageList[found_index] = objnum;
441 return found_index;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700442}
thestig931bf372016-04-26 22:24:30 -0700443
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700444int CPDF_Document::GetPageCount() const {
tsepez0fa47172017-01-09 07:01:36 -0800445 return pdfium::CollectionSize<int>(m_PageList);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700446}
Wei Li215816b2016-01-14 12:29:02 -0800447
448int CPDF_Document::RetrievePageCount() const {
npm01b67ed2016-09-12 13:38:52 -0700449 CPDF_Dictionary* pPages = GetPagesDict();
thestig931bf372016-04-26 22:24:30 -0700450 if (!pPages)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700451 return 0;
thestig931bf372016-04-26 22:24:30 -0700452
453 if (!pPages->KeyExist("Kids"))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700454 return 1;
thestig931bf372016-04-26 22:24:30 -0700455
Wei Li215816b2016-01-14 12:29:02 -0800456 std::set<CPDF_Dictionary*> visited_pages;
457 visited_pages.insert(pPages);
458 return CountPages(pPages, &visited_pages);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700459}
Wei Li215816b2016-01-14 12:29:02 -0800460
thestig27ddf162016-05-23 15:06:59 -0700461uint32_t CPDF_Document::GetUserPermissions() const {
462 // https://bugs.chromium.org/p/pdfium/issues/detail?id=499
463 if (!m_pParser) {
464#ifndef PDF_ENABLE_XFA
465 return 0;
466#else // PDF_ENABLE_XFA
467 return 0xFFFFFFFF;
468#endif
469 }
470 return m_pParser->GetPermissions();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700471}
Tom Sepez02056fa2016-01-25 12:15:28 -0800472
thestig931bf372016-04-26 22:24:30 -0700473CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) {
474 ASSERT(pFontDict);
npme883afc2016-10-05 13:43:25 -0700475 return m_pDocPage->GetFont(pFontDict);
thestig931bf372016-04-26 22:24:30 -0700476}
477
Dan Sinclair0b950422017-09-21 15:49:49 -0400478RetainPtr<CPDF_StreamAcc> CPDF_Document::LoadFontFile(CPDF_Stream* pStream) {
thestig931bf372016-04-26 22:24:30 -0700479 return m_pDocPage->GetFontFileStreamAcc(pStream);
480}
481
482CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj,
483 CPDF_Dictionary* pResources) {
484 return m_pDocPage->GetColorSpace(pCSObj, pResources);
485}
486
487CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj,
npme883afc2016-10-05 13:43:25 -0700488 bool bShading,
thestig12168d72016-04-26 22:41:36 -0700489 const CFX_Matrix& matrix) {
thestig931bf372016-04-26 22:24:30 -0700490 return m_pDocPage->GetPattern(pPatternObj, bShading, matrix);
491}
492
Dan Sinclair0b950422017-09-21 15:49:49 -0400493RetainPtr<CPDF_IccProfile> CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) {
thestig931bf372016-04-26 22:24:30 -0700494 return m_pDocPage->GetIccProfile(pStream);
495}
496
Dan Sinclair0b950422017-09-21 15:49:49 -0400497RetainPtr<CPDF_Image> CPDF_Document::LoadImageFromPageData(
Tom Sepez7d4f6a82017-03-31 17:10:34 -0700498 uint32_t dwStreamObjNum) {
tsepez137a3442016-11-14 15:03:55 -0800499 ASSERT(dwStreamObjNum);
500 return m_pDocPage->GetImage(dwStreamObjNum);
thestig931bf372016-04-26 22:24:30 -0700501}
502
thestig931bf372016-04-26 22:24:30 -0700503void CPDF_Document::CreateNewDoc() {
Lei Zhang01581062017-08-30 14:19:26 -0700504 ASSERT(!m_pRootDict);
505 ASSERT(!m_pInfoDict);
tsepez5913a6c2016-11-16 17:31:18 -0800506 m_pRootDict = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800507 m_pRootDict->SetNewFor<CPDF_Name>("Type", "Catalog");
tsepez698c5712016-09-28 16:47:07 -0700508
tsepez5913a6c2016-11-16 17:31:18 -0800509 CPDF_Dictionary* pPages = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800510 pPages->SetNewFor<CPDF_Name>("Type", "Pages");
511 pPages->SetNewFor<CPDF_Number>("Count", 0);
512 pPages->SetNewFor<CPDF_Array>("Kids");
513 m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, pPages->GetObjNum());
tsepez5913a6c2016-11-16 17:31:18 -0800514 m_pInfoDict = NewIndirect<CPDF_Dictionary>();
thestig931bf372016-04-26 22:24:30 -0700515}
516
517CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) {
tsepez5913a6c2016-11-16 17:31:18 -0800518 CPDF_Dictionary* pDict = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800519 pDict->SetNewFor<CPDF_Name>("Type", "Page");
tsepez70c4afd2016-11-15 11:33:44 -0800520 uint32_t dwObjNum = pDict->GetObjNum();
npm20ef5b92016-11-03 11:47:43 -0700521 if (!InsertNewPage(iPage, pDict)) {
tsepez33fdebc2016-11-04 11:38:40 -0700522 DeleteIndirectObject(dwObjNum);
thestig931bf372016-04-26 22:24:30 -0700523 return nullptr;
524 }
525 return pDict;
526}
527
npm20ef5b92016-11-03 11:47:43 -0700528bool CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages,
529 int nPagesToGo,
530 CPDF_Dictionary* pPageDict,
531 bool bInsert,
532 std::set<CPDF_Dictionary*>* pVisited) {
533 CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
534 if (!pKidList)
535 return false;
536
537 for (size_t i = 0; i < pKidList->GetCount(); i++) {
538 CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
539 if (pKid->GetStringFor("Type") == "Page") {
540 if (nPagesToGo != 0) {
541 nPagesToGo--;
542 continue;
543 }
544 if (bInsert) {
tsepez8a3aa452016-11-16 12:26:06 -0800545 pKidList->InsertNewAt<CPDF_Reference>(i, this, pPageDict->GetObjNum());
tsepez0e606b52016-11-18 16:22:41 -0800546 pPageDict->SetNewFor<CPDF_Reference>("Parent", this,
547 pPages->GetObjNum());
npm20ef5b92016-11-03 11:47:43 -0700548 } else {
549 pKidList->RemoveAt(i);
550 }
tsepez0e606b52016-11-18 16:22:41 -0800551 pPages->SetNewFor<CPDF_Number>(
npm20ef5b92016-11-03 11:47:43 -0700552 "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
npmec64cee2016-11-04 12:54:51 -0700553 ResetTraversal();
npm20ef5b92016-11-03 11:47:43 -0700554 break;
555 }
556 int nPages = pKid->GetIntegerFor("Count");
557 if (nPagesToGo >= nPages) {
558 nPagesToGo -= nPages;
559 continue;
560 }
561 if (pdfium::ContainsKey(*pVisited, pKid))
562 return false;
563
564 pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid);
565 if (!InsertDeletePDFPage(pKid, nPagesToGo, pPageDict, bInsert, pVisited))
566 return false;
567
tsepez0e606b52016-11-18 16:22:41 -0800568 pPages->SetNewFor<CPDF_Number>(
569 "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
npm20ef5b92016-11-03 11:47:43 -0700570 break;
571 }
572 return true;
573}
574
575bool CPDF_Document::InsertNewPage(int iPage, CPDF_Dictionary* pPageDict) {
Lei Zhang01581062017-08-30 14:19:26 -0700576 const CPDF_Dictionary* pRoot = GetRoot();
npm20ef5b92016-11-03 11:47:43 -0700577 CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr;
578 if (!pPages)
579 return false;
580
581 int nPages = GetPageCount();
582 if (iPage < 0 || iPage > nPages)
583 return false;
584
585 if (iPage == nPages) {
586 CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
tsepez0e606b52016-11-18 16:22:41 -0800587 if (!pPagesList)
588 pPagesList = pPages->SetNewFor<CPDF_Array>("Kids");
tsepez8a3aa452016-11-16 12:26:06 -0800589 pPagesList->AddNew<CPDF_Reference>(this, pPageDict->GetObjNum());
tsepez0e606b52016-11-18 16:22:41 -0800590 pPages->SetNewFor<CPDF_Number>("Count", nPages + 1);
591 pPageDict->SetNewFor<CPDF_Reference>("Parent", this, pPages->GetObjNum());
npmec64cee2016-11-04 12:54:51 -0700592 ResetTraversal();
npm20ef5b92016-11-03 11:47:43 -0700593 } else {
594 std::set<CPDF_Dictionary*> stack = {pPages};
595 if (!InsertDeletePDFPage(pPages, iPage, pPageDict, true, &stack))
596 return false;
597 }
tsepez0fa47172017-01-09 07:01:36 -0800598 m_PageList.insert(m_PageList.begin() + iPage, pPageDict->GetObjNum());
npm20ef5b92016-11-03 11:47:43 -0700599 return true;
600}
601
thestig931bf372016-04-26 22:24:30 -0700602void CPDF_Document::DeletePage(int iPage) {
npm01b67ed2016-09-12 13:38:52 -0700603 CPDF_Dictionary* pPages = GetPagesDict();
thestig931bf372016-04-26 22:24:30 -0700604 if (!pPages)
605 return;
606
dsinclair38fd8442016-09-15 10:15:32 -0700607 int nPages = pPages->GetIntegerFor("Count");
thestig931bf372016-04-26 22:24:30 -0700608 if (iPage < 0 || iPage >= nPages)
609 return;
610
611 std::set<CPDF_Dictionary*> stack = {pPages};
npm20ef5b92016-11-03 11:47:43 -0700612 if (!InsertDeletePDFPage(pPages, iPage, nullptr, false, &stack))
thestig931bf372016-04-26 22:24:30 -0700613 return;
614
tsepez0fa47172017-01-09 07:01:36 -0800615 m_PageList.erase(m_PageList.begin() + iPage);
thestig931bf372016-04-26 22:24:30 -0700616}
617
Dan Sinclair812e96c2017-03-13 16:43:37 -0400618CPDF_Font* CPDF_Document::AddStandardFont(const char* font,
thestig931bf372016-04-26 22:24:30 -0700619 CPDF_FontEncoding* pEncoding) {
Ryan Harrison275e2602017-09-18 14:23:18 -0400620 ByteString name(font);
thestig931bf372016-04-26 22:24:30 -0700621 if (PDF_GetStandardFontName(&name) < 0)
622 return nullptr;
tsepez71a452f2016-05-13 17:51:27 -0700623 return GetPageData()->GetStandardFont(name, pEncoding);
thestig931bf372016-04-26 22:24:30 -0700624}
625
npm01b67ed2016-09-12 13:38:52 -0700626size_t CPDF_Document::CalculateEncodingDict(int charset,
627 CPDF_Dictionary* pBaseDict) {
628 size_t i;
629 for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) {
630 if (g_FX_CharsetUnicodes[i].m_Charset == charset)
631 break;
632 }
633 if (i == FX_ArraySize(g_FX_CharsetUnicodes))
634 return i;
tsepez70c4afd2016-11-15 11:33:44 -0800635
tsepez5913a6c2016-11-16 17:31:18 -0800636 CPDF_Dictionary* pEncodingDict = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800637 pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding");
tsepez70c4afd2016-11-15 11:33:44 -0800638
tsepez0e606b52016-11-18 16:22:41 -0800639 CPDF_Array* pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences");
tsepez8a3aa452016-11-16 12:26:06 -0800640 pArray->AddNew<CPDF_Number>(128);
tsepez70c4afd2016-11-15 11:33:44 -0800641
npm01b67ed2016-09-12 13:38:52 -0700642 const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
643 for (int j = 0; j < 128; j++) {
Ryan Harrison275e2602017-09-18 14:23:18 -0400644 ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]);
tsepez8a3aa452016-11-16 12:26:06 -0800645 pArray->AddNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name);
npm01b67ed2016-09-12 13:38:52 -0700646 }
tsepez0e606b52016-11-18 16:22:41 -0800647 pBaseDict->SetNewFor<CPDF_Reference>("Encoding", this,
648 pEncodingDict->GetObjNum());
npm01b67ed2016-09-12 13:38:52 -0700649 return i;
650}
651
npme9988dd2016-09-16 13:57:22 -0700652CPDF_Dictionary* CPDF_Document::ProcessbCJK(
653 CPDF_Dictionary* pBaseDict,
654 int charset,
tsepez12f3e4a2016-11-02 15:17:29 -0700655 bool bVert,
Ryan Harrison275e2602017-09-18 14:23:18 -0400656 ByteString basefont,
Dan Sinclair812e96c2017-03-13 16:43:37 -0400657 std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) {
tsepez5913a6c2016-11-16 17:31:18 -0800658 CPDF_Dictionary* pFontDict = NewIndirect<CPDF_Dictionary>();
Ryan Harrison275e2602017-09-18 14:23:18 -0400659 ByteString cmap;
660 ByteString ordering;
npme9988dd2016-09-16 13:57:22 -0700661 int supplement = 0;
tsepez0e606b52016-11-18 16:22:41 -0800662 CPDF_Array* pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W");
npme9988dd2016-09-16 13:57:22 -0700663 switch (charset) {
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400664 case FX_CHARSET_ChineseTraditional:
npme9988dd2016-09-16 13:57:22 -0700665 cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H";
666 ordering = "CNS1";
667 supplement = 4;
tsepez8a3aa452016-11-16 12:26:06 -0800668 pWidthArray->AddNew<CPDF_Number>(1);
npme9988dd2016-09-16 13:57:22 -0700669 Insert(0x20, 0x7e, pWidthArray);
670 break;
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400671 case FX_CHARSET_ChineseSimplified:
npme9988dd2016-09-16 13:57:22 -0700672 cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H";
673 ordering = "GB1";
674 supplement = 2;
tsepez8a3aa452016-11-16 12:26:06 -0800675 pWidthArray->AddNew<CPDF_Number>(7716);
npme9988dd2016-09-16 13:57:22 -0700676 Insert(0x20, 0x20, pWidthArray);
tsepez8a3aa452016-11-16 12:26:06 -0800677 pWidthArray->AddNew<CPDF_Number>(814);
npme9988dd2016-09-16 13:57:22 -0700678 Insert(0x21, 0x7e, pWidthArray);
679 break;
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400680 case FX_CHARSET_Hangul:
npme9988dd2016-09-16 13:57:22 -0700681 cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H";
682 ordering = "Korea1";
683 supplement = 2;
tsepez8a3aa452016-11-16 12:26:06 -0800684 pWidthArray->AddNew<CPDF_Number>(1);
npme9988dd2016-09-16 13:57:22 -0700685 Insert(0x20, 0x7e, pWidthArray);
686 break;
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400687 case FX_CHARSET_ShiftJIS:
npme9988dd2016-09-16 13:57:22 -0700688 cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H";
689 ordering = "Japan1";
690 supplement = 5;
tsepez8a3aa452016-11-16 12:26:06 -0800691 pWidthArray->AddNew<CPDF_Number>(231);
npme9988dd2016-09-16 13:57:22 -0700692 Insert(0x20, 0x7d, pWidthArray);
tsepez8a3aa452016-11-16 12:26:06 -0800693 pWidthArray->AddNew<CPDF_Number>(326);
npme9988dd2016-09-16 13:57:22 -0700694 Insert(0xa0, 0xa0, pWidthArray);
tsepez8a3aa452016-11-16 12:26:06 -0800695 pWidthArray->AddNew<CPDF_Number>(327);
npme9988dd2016-09-16 13:57:22 -0700696 Insert(0xa1, 0xdf, pWidthArray);
tsepez8a3aa452016-11-16 12:26:06 -0800697 pWidthArray->AddNew<CPDF_Number>(631);
npme9988dd2016-09-16 13:57:22 -0700698 Insert(0x7e, 0x7e, pWidthArray);
699 break;
700 }
tsepez0e606b52016-11-18 16:22:41 -0800701 pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
702 pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
703 pBaseDict->SetNewFor<CPDF_Name>("Encoding", cmap);
704 pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
705 pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2");
706 pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
707
708 CPDF_Dictionary* pCIDSysInfo =
709 pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo");
710 pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
711 pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false);
712 pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
713
714 CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
tsepez8a3aa452016-11-16 12:26:06 -0800715 pArray->AddNew<CPDF_Reference>(this, pFontDict->GetObjNum());
npme9988dd2016-09-16 13:57:22 -0700716 return pFontDict;
717}
718
tsepez12f3e4a2016-11-02 15:17:29 -0700719CPDF_Font* CPDF_Document::AddFont(CFX_Font* pFont, int charset, bool bVert) {
thestig931bf372016-04-26 22:24:30 -0700720 if (!pFont)
721 return nullptr;
722
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400723 bool bCJK = charset == FX_CHARSET_ChineseTraditional ||
724 charset == FX_CHARSET_ChineseSimplified ||
725 charset == FX_CHARSET_Hangul || charset == FX_CHARSET_ShiftJIS;
Ryan Harrison275e2602017-09-18 14:23:18 -0400726 ByteString basefont = pFont->GetFamilyName();
thestig931bf372016-04-26 22:24:30 -0700727 basefont.Replace(" ", "");
npm01b67ed2016-09-12 13:38:52 -0700728 int flags =
729 CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400730 false, false, charset == FX_CHARSET_Symbol);
thestig931bf372016-04-26 22:24:30 -0700731
tsepez5913a6c2016-11-16 17:31:18 -0800732 CPDF_Dictionary* pBaseDict = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800733 pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
Tom Sepez827db142017-04-26 13:50:33 -0700734 auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont);
thestig931bf372016-04-26 22:24:30 -0700735 CPDF_Dictionary* pFontDict = pBaseDict;
736 if (!bCJK) {
tsepez06104a82016-11-21 16:22:10 -0800737 auto pWidths = pdfium::MakeUnique<CPDF_Array>();
thestig931bf372016-04-26 22:24:30 -0700738 for (int charcode = 32; charcode < 128; charcode++) {
739 int glyph_index = pEncoding->GlyphFromCharCode(charcode);
740 int char_width = pFont->GetGlyphWidth(glyph_index);
tsepez8a3aa452016-11-16 12:26:06 -0800741 pWidths->AddNew<CPDF_Number>(char_width);
thestig931bf372016-04-26 22:24:30 -0700742 }
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400743 if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default ||
744 charset == FX_CHARSET_Symbol) {
tsepez0e606b52016-11-18 16:22:41 -0800745 pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
thestig931bf372016-04-26 22:24:30 -0700746 for (int charcode = 128; charcode <= 255; charcode++) {
747 int glyph_index = pEncoding->GlyphFromCharCode(charcode);
748 int char_width = pFont->GetGlyphWidth(glyph_index);
tsepez8a3aa452016-11-16 12:26:06 -0800749 pWidths->AddNew<CPDF_Number>(char_width);
thestig931bf372016-04-26 22:24:30 -0700750 }
751 } else {
npm01b67ed2016-09-12 13:38:52 -0700752 size_t i = CalculateEncodingDict(charset, pBaseDict);
thestig931bf372016-04-26 22:24:30 -0700753 if (i < FX_ArraySize(g_FX_CharsetUnicodes)) {
thestig931bf372016-04-26 22:24:30 -0700754 const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
755 for (int j = 0; j < 128; j++) {
thestig931bf372016-04-26 22:24:30 -0700756 int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]);
757 int char_width = pFont->GetGlyphWidth(glyph_index);
tsepez8a3aa452016-11-16 12:26:06 -0800758 pWidths->AddNew<CPDF_Number>(char_width);
thestig931bf372016-04-26 22:24:30 -0700759 }
thestig931bf372016-04-26 22:24:30 -0700760 }
761 }
npm01b67ed2016-09-12 13:38:52 -0700762 ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont,
tsepez06104a82016-11-21 16:22:10 -0800763 std::move(pWidths));
thestig931bf372016-04-26 22:24:30 -0700764 } else {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400765 pFontDict = ProcessbCJK(
766 pBaseDict, charset, bVert, basefont,
767 [pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
768 InsertWidthArray1(pFont, pEncoding.get(), start, end, widthArr);
769 });
thestig931bf372016-04-26 22:24:30 -0700770 }
npme9988dd2016-09-16 13:57:22 -0700771 int italicangle =
772 pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0;
thestig931bf372016-04-26 22:24:30 -0700773 FX_RECT bbox;
Lei Zhang1c23a6d2018-04-12 15:37:39 +0000774 pFont->GetBBox(&bbox);
tsepez06104a82016-11-21 16:22:10 -0800775 auto pBBox = pdfium::MakeUnique<CPDF_Array>();
tsepez8a3aa452016-11-16 12:26:06 -0800776 pBBox->AddNew<CPDF_Number>(bbox.left);
777 pBBox->AddNew<CPDF_Number>(bbox.bottom);
778 pBBox->AddNew<CPDF_Number>(bbox.right);
779 pBBox->AddNew<CPDF_Number>(bbox.top);
thestig931bf372016-04-26 22:24:30 -0700780 int32_t nStemV = 0;
781 if (pFont->GetSubstFont()) {
782 nStemV = pFont->GetSubstFont()->m_Weight / 5;
783 } else {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400784 static const char stem_chars[] = {'i', 'I', '!', '1'};
thestig931bf372016-04-26 22:24:30 -0700785 const size_t count = FX_ArraySize(stem_chars);
786 uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]);
787 nStemV = pFont->GetGlyphWidth(glyph);
788 for (size_t i = 1; i < count; i++) {
789 glyph = pEncoding->GlyphFromCharCode(stem_chars[i]);
790 int width = pFont->GetGlyphWidth(glyph);
npm01b67ed2016-09-12 13:38:52 -0700791 if (width > 0 && width < nStemV)
thestig931bf372016-04-26 22:24:30 -0700792 nStemV = width;
thestig931bf372016-04-26 22:24:30 -0700793 }
794 }
tsepez70c4afd2016-11-15 11:33:44 -0800795 CPDF_Dictionary* pFontDesc = ToDictionary(AddIndirectObject(
tsepez698c5712016-09-28 16:47:07 -0700796 CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(),
tsepez06104a82016-11-21 16:22:10 -0800797 pFont->GetDescent(), std::move(pBBox), nStemV)));
tsepez0e606b52016-11-18 16:22:41 -0800798 pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", this,
799 pFontDesc->GetObjNum());
thestig931bf372016-04-26 22:24:30 -0700800 return LoadFont(pBaseDict);
801}
802
Dan Sinclair698aed72017-09-26 16:24:49 -0400803#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
thestig931bf372016-04-26 22:24:30 -0700804CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTW* pLogFont,
tsepez12f3e4a2016-11-02 15:17:29 -0700805 bool bVert,
806 bool bTranslateName) {
thestig931bf372016-04-26 22:24:30 -0700807 LOGFONTA lfa;
Dan Sinclair1c5d0b42017-04-03 15:05:11 -0400808 memcpy(&lfa, pLogFont, (char*)lfa.lfFaceName - (char*)&lfa);
Ryan Harrison275e2602017-09-18 14:23:18 -0400809 ByteString face = ByteString::FromUnicode(pLogFont->lfFaceName);
thestig931bf372016-04-26 22:24:30 -0700810 if (face.GetLength() >= LF_FACESIZE)
811 return nullptr;
812
Dan Sinclair7e7c6492017-04-03 14:50:05 -0400813 strncpy(lfa.lfFaceName, face.c_str(),
Ryan Harrison275e2602017-09-18 14:23:18 -0400814 (face.GetLength() + 1) * sizeof(ByteString::CharType));
thestig931bf372016-04-26 22:24:30 -0700815 return AddWindowsFont(&lfa, bVert, bTranslateName);
816}
817
818CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont,
tsepez12f3e4a2016-11-02 15:17:29 -0700819 bool bVert,
820 bool bTranslateName) {
thestig931bf372016-04-26 22:24:30 -0700821 pLogFont->lfHeight = -1000;
822 pLogFont->lfWidth = 0;
823 HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
824 HDC hDC = CreateCompatibleDC(nullptr);
825 hFont = SelectObject(hDC, hFont);
826 int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr);
827 if (tm_size == 0) {
828 hFont = SelectObject(hDC, hFont);
829 DeleteObject(hFont);
830 DeleteDC(hDC);
831 return nullptr;
832 }
833
834 LPBYTE tm_buf = FX_Alloc(BYTE, tm_size);
npm01b67ed2016-09-12 13:38:52 -0700835 OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf);
thestig931bf372016-04-26 22:24:30 -0700836 GetOutlineTextMetrics(hDC, tm_size, ptm);
npm01b67ed2016-09-12 13:38:52 -0700837 int flags = CalculateFlags(false, pLogFont->lfItalic != 0,
838 (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH,
839 (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN,
840 (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT,
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400841 pLogFont->lfCharSet == FX_CHARSET_Symbol);
thestig931bf372016-04-26 22:24:30 -0700842
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400843 bool bCJK = pLogFont->lfCharSet == FX_CHARSET_ChineseTraditional ||
844 pLogFont->lfCharSet == FX_CHARSET_ChineseSimplified ||
845 pLogFont->lfCharSet == FX_CHARSET_Hangul ||
846 pLogFont->lfCharSet == FX_CHARSET_ShiftJIS;
Ryan Harrison275e2602017-09-18 14:23:18 -0400847 ByteString basefont;
thestig931bf372016-04-26 22:24:30 -0700848 if (bTranslateName && bCJK)
849 basefont = FPDF_GetPSNameFromTT(hDC);
850
851 if (basefont.IsEmpty())
852 basefont = pLogFont->lfFaceName;
853
npm01b67ed2016-09-12 13:38:52 -0700854 int italicangle = ptm->otmItalicAngle / 10;
855 int ascend = ptm->otmrcFontBox.top;
856 int descend = ptm->otmrcFontBox.bottom;
857 int capheight = ptm->otmsCapEmHeight;
858 int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom,
859 ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
thestig931bf372016-04-26 22:24:30 -0700860 FX_Free(tm_buf);
861 basefont.Replace(" ", "");
tsepez5913a6c2016-11-16 17:31:18 -0800862 CPDF_Dictionary* pBaseDict = NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800863 pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
thestig931bf372016-04-26 22:24:30 -0700864 CPDF_Dictionary* pFontDict = pBaseDict;
865 if (!bCJK) {
Dan Sinclairf51a02a2017-04-19 12:46:53 -0400866 if (pLogFont->lfCharSet == FX_CHARSET_ANSI ||
867 pLogFont->lfCharSet == FX_CHARSET_Default ||
868 pLogFont->lfCharSet == FX_CHARSET_Symbol) {
tsepez0e606b52016-11-18 16:22:41 -0800869 pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
thestig931bf372016-04-26 22:24:30 -0700870 } else {
npm01b67ed2016-09-12 13:38:52 -0700871 CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict);
thestig931bf372016-04-26 22:24:30 -0700872 }
thestig931bf372016-04-26 22:24:30 -0700873 int char_widths[224];
874 GetCharWidth(hDC, 32, 255, char_widths);
tsepez06104a82016-11-21 16:22:10 -0800875 auto pWidths = pdfium::MakeUnique<CPDF_Array>();
weili3cc01f22016-05-16 13:53:42 -0700876 for (size_t i = 0; i < 224; i++)
tsepez8a3aa452016-11-16 12:26:06 -0800877 pWidths->AddNew<CPDF_Number>(char_widths[i]);
npm01b67ed2016-09-12 13:38:52 -0700878 ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM,
tsepez06104a82016-11-21 16:22:10 -0800879 pLogFont->lfItalic != 0, basefont, std::move(pWidths));
thestig931bf372016-04-26 22:24:30 -0700880 } else {
npme9988dd2016-09-16 13:57:22 -0700881 pFontDict =
882 ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont,
Dan Sinclair812e96c2017-03-13 16:43:37 -0400883 [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
npme9988dd2016-09-16 13:57:22 -0700884 InsertWidthArray(hDC, start, end, widthArr);
885 });
thestig931bf372016-04-26 22:24:30 -0700886 }
tsepez06104a82016-11-21 16:22:10 -0800887 auto pBBox = pdfium::MakeUnique<CPDF_Array>();
npm01b67ed2016-09-12 13:38:52 -0700888 for (int i = 0; i < 4; i++)
tsepez8a3aa452016-11-16 12:26:06 -0800889 pBBox->AddNew<CPDF_Number>(bbox[i]);
tsepez70c4afd2016-11-15 11:33:44 -0800890 std::unique_ptr<CPDF_Dictionary> pFontDesc =
tsepez698c5712016-09-28 16:47:07 -0700891 CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend,
tsepez06104a82016-11-21 16:22:10 -0800892 std::move(pBBox), pLogFont->lfWeight / 5);
tsepez0e606b52016-11-18 16:22:41 -0800893 pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight);
894 pFontDict->SetNewFor<CPDF_Reference>(
895 "FontDescriptor", this,
896 AddIndirectObject(std::move(pFontDesc))->GetObjNum());
thestig931bf372016-04-26 22:24:30 -0700897 hFont = SelectObject(hDC, hFont);
898 DeleteObject(hFont);
899 DeleteDC(hDC);
900 return LoadFont(pBaseDict);
901}
Dan Sinclair698aed72017-09-26 16:24:49 -0400902#endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_