OLD | NEW |
| (Empty) |
1 // 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. | |
4 | |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
6 | |
7 #include "core/fpdfapi/fpdf_page/pageint.h" | |
8 | |
9 #include <algorithm> | |
10 #include <set> | |
11 | |
12 #include "core/fdrm/crypto/fx_crypt.h" | |
13 #include "core/fpdfapi/cpdf_modulemgr.h" | |
14 #include "core/fpdfapi/font/cpdf_type1font.h" | |
15 #include "core/fpdfapi/font/font_int.h" | |
16 #include "core/fpdfapi/fpdf_page/cpdf_image.h" | |
17 #include "core/fpdfapi/fpdf_page/cpdf_pagemodule.h" | |
18 #include "core/fpdfapi/fpdf_page/cpdf_pattern.h" | |
19 #include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h" | |
20 #include "core/fpdfapi/fpdf_page/cpdf_tilingpattern.h" | |
21 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | |
22 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" | |
23 #include "core/fpdfapi/fpdf_parser/cpdf_document.h" | |
24 #include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" | |
25 #include "third_party/base/stl_util.h" | |
26 | |
27 void CPDF_ModuleMgr::InitPageModule() { | |
28 m_pPageModule.reset(new CPDF_PageModule); | |
29 } | |
30 | |
31 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc) | |
32 : m_pPDFDoc(pPDFDoc), m_bForceClear(FALSE) {} | |
33 | |
34 CPDF_DocPageData::~CPDF_DocPageData() { | |
35 Clear(FALSE); | |
36 Clear(TRUE); | |
37 | |
38 for (auto& it : m_PatternMap) | |
39 delete it.second; | |
40 m_PatternMap.clear(); | |
41 | |
42 for (auto& it : m_FontMap) | |
43 delete it.second; | |
44 m_FontMap.clear(); | |
45 | |
46 for (auto& it : m_ColorSpaceMap) | |
47 delete it.second; | |
48 m_ColorSpaceMap.clear(); | |
49 } | |
50 | |
51 void CPDF_DocPageData::Clear(FX_BOOL bForceRelease) { | |
52 m_bForceClear = bForceRelease; | |
53 | |
54 for (auto& it : m_PatternMap) { | |
55 CPDF_CountedPattern* ptData = it.second; | |
56 if (!ptData->get()) | |
57 continue; | |
58 | |
59 if (bForceRelease || ptData->use_count() < 2) | |
60 ptData->clear(); | |
61 } | |
62 | |
63 for (auto& it : m_FontMap) { | |
64 CPDF_CountedFont* fontData = it.second; | |
65 if (!fontData->get()) | |
66 continue; | |
67 | |
68 if (bForceRelease || fontData->use_count() < 2) { | |
69 fontData->clear(); | |
70 } | |
71 } | |
72 | |
73 for (auto& it : m_ColorSpaceMap) { | |
74 CPDF_CountedColorSpace* csData = it.second; | |
75 if (!csData->get()) | |
76 continue; | |
77 | |
78 if (bForceRelease || csData->use_count() < 2) { | |
79 csData->get()->Release(); | |
80 csData->reset(nullptr); | |
81 } | |
82 } | |
83 | |
84 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) { | |
85 auto curr_it = it++; | |
86 CPDF_CountedIccProfile* ipData = curr_it->second; | |
87 if (!ipData->get()) | |
88 continue; | |
89 | |
90 if (bForceRelease || ipData->use_count() < 2) { | |
91 for (auto hash_it = m_HashProfileMap.begin(); | |
92 hash_it != m_HashProfileMap.end(); ++hash_it) { | |
93 if (curr_it->first == hash_it->second) { | |
94 m_HashProfileMap.erase(hash_it); | |
95 break; | |
96 } | |
97 } | |
98 delete ipData->get(); | |
99 delete ipData; | |
100 m_IccProfileMap.erase(curr_it); | |
101 } | |
102 } | |
103 | |
104 for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) { | |
105 auto curr_it = it++; | |
106 CPDF_CountedStreamAcc* pCountedFont = curr_it->second; | |
107 if (!pCountedFont->get()) | |
108 continue; | |
109 | |
110 if (bForceRelease || pCountedFont->use_count() < 2) { | |
111 delete pCountedFont->get(); | |
112 delete pCountedFont; | |
113 m_FontFileMap.erase(curr_it); | |
114 } | |
115 } | |
116 | |
117 for (auto it = m_ImageMap.begin(); it != m_ImageMap.end();) { | |
118 auto curr_it = it++; | |
119 CPDF_CountedImage* pCountedImage = curr_it->second; | |
120 if (!pCountedImage->get()) | |
121 continue; | |
122 | |
123 if (bForceRelease || pCountedImage->use_count() < 2) { | |
124 delete pCountedImage->get(); | |
125 delete pCountedImage; | |
126 m_ImageMap.erase(curr_it); | |
127 } | |
128 } | |
129 } | |
130 | |
131 CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict, | |
132 FX_BOOL findOnly) { | |
133 if (!pFontDict) | |
134 return nullptr; | |
135 | |
136 CPDF_CountedFont* pFontData = nullptr; | |
137 auto it = m_FontMap.find(pFontDict); | |
138 if (it != m_FontMap.end()) { | |
139 pFontData = it->second; | |
140 if (pFontData->get()) { | |
141 return pFontData->AddRef(); | |
142 } | |
143 } | |
144 | |
145 if (findOnly) | |
146 return nullptr; | |
147 | |
148 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pFontDict); | |
149 if (!pFont) | |
150 return nullptr; | |
151 | |
152 if (pFontData) { | |
153 pFontData->reset(pFont.release()); | |
154 } else { | |
155 pFontData = new CPDF_CountedFont(pFont.release()); | |
156 m_FontMap[pFontDict] = pFontData; | |
157 } | |
158 return pFontData->AddRef(); | |
159 } | |
160 | |
161 CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteString& fontName, | |
162 CPDF_FontEncoding* pEncoding) { | |
163 if (fontName.IsEmpty()) | |
164 return nullptr; | |
165 | |
166 for (auto& it : m_FontMap) { | |
167 CPDF_CountedFont* fontData = it.second; | |
168 CPDF_Font* pFont = fontData->get(); | |
169 if (!pFont) | |
170 continue; | |
171 if (pFont->GetBaseFont() != fontName) | |
172 continue; | |
173 if (pFont->IsEmbedded()) | |
174 continue; | |
175 if (!pFont->IsType1Font()) | |
176 continue; | |
177 if (pFont->GetFontDict()->KeyExist("Widths")) | |
178 continue; | |
179 | |
180 CPDF_Type1Font* pT1Font = pFont->AsType1Font(); | |
181 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) | |
182 continue; | |
183 | |
184 return fontData->AddRef(); | |
185 } | |
186 | |
187 CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pPDFDoc->GetByteStringPool()); | |
188 pDict->SetNameFor("Type", "Font"); | |
189 pDict->SetNameFor("Subtype", "Type1"); | |
190 pDict->SetNameFor("BaseFont", fontName); | |
191 if (pEncoding) { | |
192 pDict->SetFor("Encoding", | |
193 pEncoding->Realize(m_pPDFDoc->GetByteStringPool())); | |
194 } | |
195 m_pPDFDoc->AddIndirectObject(pDict); | |
196 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pDict); | |
197 if (!pFont) | |
198 return nullptr; | |
199 | |
200 CPDF_CountedFont* fontData = new CPDF_CountedFont(pFont.release()); | |
201 m_FontMap[pDict] = fontData; | |
202 return fontData->AddRef(); | |
203 } | |
204 | |
205 void CPDF_DocPageData::ReleaseFont(const CPDF_Dictionary* pFontDict) { | |
206 if (!pFontDict) | |
207 return; | |
208 | |
209 auto it = m_FontMap.find(pFontDict); | |
210 if (it == m_FontMap.end()) | |
211 return; | |
212 | |
213 CPDF_CountedFont* pFontData = it->second; | |
214 if (!pFontData->get()) | |
215 return; | |
216 | |
217 pFontData->RemoveRef(); | |
218 if (pFontData->use_count() > 1) | |
219 return; | |
220 | |
221 // We have font data only in m_FontMap cache. Clean it. | |
222 pFontData->clear(); | |
223 } | |
224 | |
225 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace( | |
226 CPDF_Object* pCSObj, | |
227 const CPDF_Dictionary* pResources) { | |
228 std::set<CPDF_Object*> visited; | |
229 return GetColorSpaceImpl(pCSObj, pResources, &visited); | |
230 } | |
231 | |
232 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpaceImpl( | |
233 CPDF_Object* pCSObj, | |
234 const CPDF_Dictionary* pResources, | |
235 std::set<CPDF_Object*>* pVisited) { | |
236 if (!pCSObj) | |
237 return nullptr; | |
238 | |
239 if (pdfium::ContainsKey(*pVisited, pCSObj)) | |
240 return nullptr; | |
241 | |
242 if (pCSObj->IsName()) { | |
243 CFX_ByteString name = pCSObj->GetString(); | |
244 CPDF_ColorSpace* pCS = CPDF_ColorSpace::ColorspaceFromName(name); | |
245 if (!pCS && pResources) { | |
246 CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace"); | |
247 if (pList) { | |
248 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
249 return GetColorSpaceImpl(pList->GetDirectObjectFor(name), nullptr, | |
250 pVisited); | |
251 } | |
252 } | |
253 if (!pCS || !pResources) | |
254 return pCS; | |
255 | |
256 CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace"); | |
257 if (!pColorSpaces) | |
258 return pCS; | |
259 | |
260 CPDF_Object* pDefaultCS = nullptr; | |
261 switch (pCS->GetFamily()) { | |
262 case PDFCS_DEVICERGB: | |
263 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); | |
264 break; | |
265 case PDFCS_DEVICEGRAY: | |
266 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); | |
267 break; | |
268 case PDFCS_DEVICECMYK: | |
269 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); | |
270 break; | |
271 } | |
272 if (!pDefaultCS) | |
273 return pCS; | |
274 | |
275 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
276 return GetColorSpaceImpl(pDefaultCS, nullptr, pVisited); | |
277 } | |
278 | |
279 CPDF_Array* pArray = pCSObj->AsArray(); | |
280 if (!pArray || pArray->IsEmpty()) | |
281 return nullptr; | |
282 | |
283 if (pArray->GetCount() == 1) { | |
284 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
285 return GetColorSpaceImpl(pArray->GetDirectObjectAt(0), pResources, | |
286 pVisited); | |
287 } | |
288 | |
289 CPDF_CountedColorSpace* csData = nullptr; | |
290 auto it = m_ColorSpaceMap.find(pCSObj); | |
291 if (it != m_ColorSpaceMap.end()) { | |
292 csData = it->second; | |
293 if (csData->get()) { | |
294 return csData->AddRef(); | |
295 } | |
296 } | |
297 | |
298 std::unique_ptr<CPDF_ColorSpace> pCS = | |
299 CPDF_ColorSpace::Load(m_pPDFDoc, pArray); | |
300 if (!pCS) | |
301 return nullptr; | |
302 | |
303 if (!csData) { | |
304 csData = new CPDF_CountedColorSpace(pCS.release()); | |
305 m_ColorSpaceMap[pCSObj] = csData; | |
306 } else { | |
307 csData->reset(pCS.release()); | |
308 } | |
309 return csData->AddRef(); | |
310 } | |
311 | |
312 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) { | |
313 if (!pCSObj) | |
314 return nullptr; | |
315 | |
316 auto it = m_ColorSpaceMap.find(pCSObj); | |
317 if (it != m_ColorSpaceMap.end()) | |
318 return it->second->AddRef(); | |
319 | |
320 return nullptr; | |
321 } | |
322 | |
323 void CPDF_DocPageData::ReleaseColorSpace(const CPDF_Object* pColorSpace) { | |
324 if (!pColorSpace) | |
325 return; | |
326 | |
327 auto it = m_ColorSpaceMap.find(pColorSpace); | |
328 if (it == m_ColorSpaceMap.end()) | |
329 return; | |
330 | |
331 CPDF_CountedColorSpace* pCountedColorSpace = it->second; | |
332 if (!pCountedColorSpace->get()) | |
333 return; | |
334 | |
335 pCountedColorSpace->RemoveRef(); | |
336 if (pCountedColorSpace->use_count() > 1) | |
337 return; | |
338 | |
339 // We have item only in m_ColorSpaceMap cache. Clean it. | |
340 pCountedColorSpace->get()->Release(); | |
341 pCountedColorSpace->reset(nullptr); | |
342 } | |
343 | |
344 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, | |
345 FX_BOOL bShading, | |
346 const CFX_Matrix& matrix) { | |
347 if (!pPatternObj) | |
348 return nullptr; | |
349 | |
350 CPDF_CountedPattern* ptData = nullptr; | |
351 auto it = m_PatternMap.find(pPatternObj); | |
352 if (it != m_PatternMap.end()) { | |
353 ptData = it->second; | |
354 if (ptData->get()) { | |
355 return ptData->AddRef(); | |
356 } | |
357 } | |
358 CPDF_Pattern* pPattern = nullptr; | |
359 if (bShading) { | |
360 pPattern = new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, TRUE, matrix); | |
361 } else { | |
362 CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr; | |
363 if (pDict) { | |
364 int type = pDict->GetIntegerFor("PatternType"); | |
365 if (type == CPDF_Pattern::TILING) { | |
366 pPattern = new CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix); | |
367 } else if (type == CPDF_Pattern::SHADING) { | |
368 pPattern = | |
369 new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, FALSE, matrix); | |
370 } | |
371 } | |
372 } | |
373 if (!pPattern) | |
374 return nullptr; | |
375 | |
376 if (!ptData) { | |
377 ptData = new CPDF_CountedPattern(pPattern); | |
378 m_PatternMap[pPatternObj] = ptData; | |
379 } else { | |
380 ptData->reset(pPattern); | |
381 } | |
382 return ptData->AddRef(); | |
383 } | |
384 | |
385 void CPDF_DocPageData::ReleasePattern(const CPDF_Object* pPatternObj) { | |
386 if (!pPatternObj) | |
387 return; | |
388 | |
389 auto it = m_PatternMap.find(pPatternObj); | |
390 if (it == m_PatternMap.end()) | |
391 return; | |
392 | |
393 CPDF_CountedPattern* pPattern = it->second; | |
394 if (!pPattern->get()) | |
395 return; | |
396 | |
397 pPattern->RemoveRef(); | |
398 if (pPattern->use_count() > 1) | |
399 return; | |
400 | |
401 // We have item only in m_PatternMap cache. Clean it. | |
402 pPattern->clear(); | |
403 } | |
404 | |
405 CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream) { | |
406 if (!pImageStream) | |
407 return nullptr; | |
408 | |
409 const uint32_t dwImageObjNum = pImageStream->GetObjNum(); | |
410 auto it = m_ImageMap.find(dwImageObjNum); | |
411 if (it != m_ImageMap.end()) | |
412 return it->second->AddRef(); | |
413 | |
414 CPDF_CountedImage* pCountedImage = new CPDF_CountedImage( | |
415 new CPDF_Image(m_pPDFDoc, pImageStream->AsStream(), false)); | |
416 m_ImageMap[dwImageObjNum] = pCountedImage; | |
417 return pCountedImage->AddRef(); | |
418 } | |
419 | |
420 void CPDF_DocPageData::ReleaseImage(const CPDF_Object* pImageStream) { | |
421 if (!pImageStream) | |
422 return; | |
423 | |
424 uint32_t dwObjNum = pImageStream->GetObjNum(); | |
425 if (!dwObjNum) | |
426 return; | |
427 | |
428 auto it = m_ImageMap.find(dwObjNum); | |
429 if (it == m_ImageMap.end()) | |
430 return; | |
431 | |
432 CPDF_CountedImage* pCountedImage = it->second; | |
433 if (!pCountedImage) | |
434 return; | |
435 | |
436 pCountedImage->RemoveRef(); | |
437 if (pCountedImage->use_count() > 1) | |
438 return; | |
439 | |
440 // We have item only in m_ImageMap cache. Clean it. | |
441 delete pCountedImage->get(); | |
442 delete pCountedImage; | |
443 m_ImageMap.erase(it); | |
444 } | |
445 | |
446 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile( | |
447 CPDF_Stream* pIccProfileStream) { | |
448 if (!pIccProfileStream) | |
449 return nullptr; | |
450 | |
451 auto it = m_IccProfileMap.find(pIccProfileStream); | |
452 if (it != m_IccProfileMap.end()) | |
453 return it->second->AddRef(); | |
454 | |
455 CPDF_StreamAcc stream; | |
456 stream.LoadAllData(pIccProfileStream, FALSE); | |
457 uint8_t digest[20]; | |
458 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest); | |
459 CFX_ByteString bsDigest(digest, 20); | |
460 auto hash_it = m_HashProfileMap.find(bsDigest); | |
461 if (hash_it != m_HashProfileMap.end()) { | |
462 auto it_copied_stream = m_IccProfileMap.find(hash_it->second); | |
463 if (it_copied_stream != m_IccProfileMap.end()) | |
464 return it_copied_stream->second->AddRef(); | |
465 } | |
466 CPDF_IccProfile* pProfile = | |
467 new CPDF_IccProfile(stream.GetData(), stream.GetSize()); | |
468 CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile(pProfile); | |
469 m_IccProfileMap[pIccProfileStream] = ipData; | |
470 m_HashProfileMap[bsDigest] = pIccProfileStream; | |
471 return ipData->AddRef(); | |
472 } | |
473 | |
474 void CPDF_DocPageData::ReleaseIccProfile(const CPDF_IccProfile* pIccProfile) { | |
475 ASSERT(pIccProfile); | |
476 | |
477 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) { | |
478 CPDF_CountedIccProfile* profile = it->second; | |
479 if (profile->get() != pIccProfile) | |
480 continue; | |
481 | |
482 profile->RemoveRef(); | |
483 if (profile->use_count() > 1) | |
484 continue; | |
485 // We have item only in m_IccProfileMap cache. Clean it. | |
486 delete profile->get(); | |
487 delete profile; | |
488 m_IccProfileMap.erase(it); | |
489 return; | |
490 } | |
491 } | |
492 | |
493 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc( | |
494 CPDF_Stream* pFontStream) { | |
495 ASSERT(pFontStream); | |
496 | |
497 auto it = m_FontFileMap.find(pFontStream); | |
498 if (it != m_FontFileMap.end()) | |
499 return it->second->AddRef(); | |
500 | |
501 CPDF_Dictionary* pFontDict = pFontStream->GetDict(); | |
502 int32_t org_size = pFontDict->GetIntegerFor("Length1") + | |
503 pFontDict->GetIntegerFor("Length2") + | |
504 pFontDict->GetIntegerFor("Length3"); | |
505 org_size = std::max(org_size, 0); | |
506 | |
507 CPDF_StreamAcc* pFontFile = new CPDF_StreamAcc; | |
508 pFontFile->LoadAllData(pFontStream, FALSE, org_size); | |
509 | |
510 CPDF_CountedStreamAcc* pCountedFont = new CPDF_CountedStreamAcc(pFontFile); | |
511 m_FontFileMap[pFontStream] = pCountedFont; | |
512 return pCountedFont->AddRef(); | |
513 } | |
514 | |
515 void CPDF_DocPageData::ReleaseFontFileStreamAcc( | |
516 const CPDF_Stream* pFontStream) { | |
517 if (!pFontStream) | |
518 return; | |
519 | |
520 auto it = m_FontFileMap.find(pFontStream); | |
521 if (it == m_FontFileMap.end()) | |
522 return; | |
523 | |
524 CPDF_CountedStreamAcc* pCountedStream = it->second; | |
525 if (!pCountedStream) | |
526 return; | |
527 | |
528 pCountedStream->RemoveRef(); | |
529 if (pCountedStream->use_count() > 1) | |
530 return; | |
531 | |
532 // We have item only in m_FontFileMap cache. Clean it. | |
533 delete pCountedStream->get(); | |
534 delete pCountedStream; | |
535 m_FontFileMap.erase(it); | |
536 } | |
537 | |
538 CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr( | |
539 CPDF_Object* pCSObj) const { | |
540 if (!pCSObj) | |
541 return nullptr; | |
542 | |
543 auto it = m_ColorSpaceMap.find(pCSObj); | |
544 return it != m_ColorSpaceMap.end() ? it->second : nullptr; | |
545 } | |
546 | |
547 CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr( | |
548 CPDF_Object* pPatternObj) const { | |
549 if (!pPatternObj) | |
550 return nullptr; | |
551 | |
552 auto it = m_PatternMap.find(pPatternObj); | |
553 return it != m_PatternMap.end() ? it->second : nullptr; | |
554 } | |
OLD | NEW |