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/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/page/cpdf_image.h" | |
17 #include "core/fpdfapi/page/cpdf_pagemodule.h" | |
18 #include "core/fpdfapi/page/cpdf_pattern.h" | |
19 #include "core/fpdfapi/page/cpdf_shadingpattern.h" | |
20 #include "core/fpdfapi/page/cpdf_tilingpattern.h" | |
21 #include "core/fpdfapi/parser/cpdf_array.h" | |
22 #include "core/fpdfapi/parser/cpdf_dictionary.h" | |
23 #include "core/fpdfapi/parser/cpdf_document.h" | |
24 #include "core/fpdfapi/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(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 if (!pFontDict) | |
133 return nullptr; | |
134 | |
135 CPDF_CountedFont* pFontData = nullptr; | |
136 auto it = m_FontMap.find(pFontDict); | |
137 if (it != m_FontMap.end()) { | |
138 pFontData = it->second; | |
139 if (pFontData->get()) { | |
140 return pFontData->AddRef(); | |
141 } | |
142 } | |
143 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pFontDict); | |
144 if (!pFont) | |
145 return nullptr; | |
146 | |
147 if (pFontData) { | |
148 pFontData->reset(pFont.release()); | |
149 } else { | |
150 pFontData = new CPDF_CountedFont(pFont.release()); | |
151 m_FontMap[pFontDict] = pFontData; | |
152 } | |
153 return pFontData->AddRef(); | |
154 } | |
155 | |
156 CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteString& fontName, | |
157 CPDF_FontEncoding* pEncoding) { | |
158 if (fontName.IsEmpty()) | |
159 return nullptr; | |
160 | |
161 for (auto& it : m_FontMap) { | |
162 CPDF_CountedFont* fontData = it.second; | |
163 CPDF_Font* pFont = fontData->get(); | |
164 if (!pFont) | |
165 continue; | |
166 if (pFont->GetBaseFont() != fontName) | |
167 continue; | |
168 if (pFont->IsEmbedded()) | |
169 continue; | |
170 if (!pFont->IsType1Font()) | |
171 continue; | |
172 if (pFont->GetFontDict()->KeyExist("Widths")) | |
173 continue; | |
174 | |
175 CPDF_Type1Font* pT1Font = pFont->AsType1Font(); | |
176 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding)) | |
177 continue; | |
178 | |
179 return fontData->AddRef(); | |
180 } | |
181 | |
182 CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pPDFDoc->GetByteStringPool()); | |
183 pDict->SetNameFor("Type", "Font"); | |
184 pDict->SetNameFor("Subtype", "Type1"); | |
185 pDict->SetNameFor("BaseFont", fontName); | |
186 if (pEncoding) { | |
187 pDict->SetFor("Encoding", | |
188 pEncoding->Realize(m_pPDFDoc->GetByteStringPool())); | |
189 } | |
190 m_pPDFDoc->AddIndirectObject(pDict); | |
191 std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pDict); | |
192 if (!pFont) | |
193 return nullptr; | |
194 | |
195 CPDF_CountedFont* fontData = new CPDF_CountedFont(pFont.release()); | |
196 m_FontMap[pDict] = fontData; | |
197 return fontData->AddRef(); | |
198 } | |
199 | |
200 void CPDF_DocPageData::ReleaseFont(const CPDF_Dictionary* pFontDict) { | |
201 if (!pFontDict) | |
202 return; | |
203 | |
204 auto it = m_FontMap.find(pFontDict); | |
205 if (it == m_FontMap.end()) | |
206 return; | |
207 | |
208 CPDF_CountedFont* pFontData = it->second; | |
209 if (!pFontData->get()) | |
210 return; | |
211 | |
212 pFontData->RemoveRef(); | |
213 if (pFontData->use_count() > 1) | |
214 return; | |
215 | |
216 // We have font data only in m_FontMap cache. Clean it. | |
217 pFontData->clear(); | |
218 } | |
219 | |
220 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace( | |
221 CPDF_Object* pCSObj, | |
222 const CPDF_Dictionary* pResources) { | |
223 std::set<CPDF_Object*> visited; | |
224 return GetColorSpaceImpl(pCSObj, pResources, &visited); | |
225 } | |
226 | |
227 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpaceImpl( | |
228 CPDF_Object* pCSObj, | |
229 const CPDF_Dictionary* pResources, | |
230 std::set<CPDF_Object*>* pVisited) { | |
231 if (!pCSObj) | |
232 return nullptr; | |
233 | |
234 if (pdfium::ContainsKey(*pVisited, pCSObj)) | |
235 return nullptr; | |
236 | |
237 if (pCSObj->IsName()) { | |
238 CFX_ByteString name = pCSObj->GetString(); | |
239 CPDF_ColorSpace* pCS = CPDF_ColorSpace::ColorspaceFromName(name); | |
240 if (!pCS && pResources) { | |
241 CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace"); | |
242 if (pList) { | |
243 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
244 return GetColorSpaceImpl(pList->GetDirectObjectFor(name), nullptr, | |
245 pVisited); | |
246 } | |
247 } | |
248 if (!pCS || !pResources) | |
249 return pCS; | |
250 | |
251 CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace"); | |
252 if (!pColorSpaces) | |
253 return pCS; | |
254 | |
255 CPDF_Object* pDefaultCS = nullptr; | |
256 switch (pCS->GetFamily()) { | |
257 case PDFCS_DEVICERGB: | |
258 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); | |
259 break; | |
260 case PDFCS_DEVICEGRAY: | |
261 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); | |
262 break; | |
263 case PDFCS_DEVICECMYK: | |
264 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); | |
265 break; | |
266 } | |
267 if (!pDefaultCS) | |
268 return pCS; | |
269 | |
270 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
271 return GetColorSpaceImpl(pDefaultCS, nullptr, pVisited); | |
272 } | |
273 | |
274 CPDF_Array* pArray = pCSObj->AsArray(); | |
275 if (!pArray || pArray->IsEmpty()) | |
276 return nullptr; | |
277 | |
278 if (pArray->GetCount() == 1) { | |
279 pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj); | |
280 return GetColorSpaceImpl(pArray->GetDirectObjectAt(0), pResources, | |
281 pVisited); | |
282 } | |
283 | |
284 CPDF_CountedColorSpace* csData = nullptr; | |
285 auto it = m_ColorSpaceMap.find(pCSObj); | |
286 if (it != m_ColorSpaceMap.end()) { | |
287 csData = it->second; | |
288 if (csData->get()) { | |
289 return csData->AddRef(); | |
290 } | |
291 } | |
292 | |
293 std::unique_ptr<CPDF_ColorSpace> pCS = | |
294 CPDF_ColorSpace::Load(m_pPDFDoc, pArray); | |
295 if (!pCS) | |
296 return nullptr; | |
297 | |
298 if (!csData) { | |
299 csData = new CPDF_CountedColorSpace(pCS.release()); | |
300 m_ColorSpaceMap[pCSObj] = csData; | |
301 } else { | |
302 csData->reset(pCS.release()); | |
303 } | |
304 return csData->AddRef(); | |
305 } | |
306 | |
307 CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) { | |
308 if (!pCSObj) | |
309 return nullptr; | |
310 | |
311 auto it = m_ColorSpaceMap.find(pCSObj); | |
312 if (it != m_ColorSpaceMap.end()) | |
313 return it->second->AddRef(); | |
314 | |
315 return nullptr; | |
316 } | |
317 | |
318 void CPDF_DocPageData::ReleaseColorSpace(const CPDF_Object* pColorSpace) { | |
319 if (!pColorSpace) | |
320 return; | |
321 | |
322 auto it = m_ColorSpaceMap.find(pColorSpace); | |
323 if (it == m_ColorSpaceMap.end()) | |
324 return; | |
325 | |
326 CPDF_CountedColorSpace* pCountedColorSpace = it->second; | |
327 if (!pCountedColorSpace->get()) | |
328 return; | |
329 | |
330 pCountedColorSpace->RemoveRef(); | |
331 if (pCountedColorSpace->use_count() > 1) | |
332 return; | |
333 | |
334 // We have item only in m_ColorSpaceMap cache. Clean it. | |
335 pCountedColorSpace->get()->Release(); | |
336 pCountedColorSpace->reset(nullptr); | |
337 } | |
338 | |
339 CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, | |
340 bool bShading, | |
341 const CFX_Matrix& matrix) { | |
342 if (!pPatternObj) | |
343 return nullptr; | |
344 | |
345 CPDF_CountedPattern* ptData = nullptr; | |
346 auto it = m_PatternMap.find(pPatternObj); | |
347 if (it != m_PatternMap.end()) { | |
348 ptData = it->second; | |
349 if (ptData->get()) { | |
350 return ptData->AddRef(); | |
351 } | |
352 } | |
353 CPDF_Pattern* pPattern = nullptr; | |
354 if (bShading) { | |
355 pPattern = new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, true, matrix); | |
356 } else { | |
357 CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr; | |
358 if (pDict) { | |
359 int type = pDict->GetIntegerFor("PatternType"); | |
360 if (type == CPDF_Pattern::TILING) { | |
361 pPattern = new CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix); | |
362 } else if (type == CPDF_Pattern::SHADING) { | |
363 pPattern = | |
364 new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, false, matrix); | |
365 } | |
366 } | |
367 } | |
368 if (!pPattern) | |
369 return nullptr; | |
370 | |
371 if (!ptData) { | |
372 ptData = new CPDF_CountedPattern(pPattern); | |
373 m_PatternMap[pPatternObj] = ptData; | |
374 } else { | |
375 ptData->reset(pPattern); | |
376 } | |
377 return ptData->AddRef(); | |
378 } | |
379 | |
380 void CPDF_DocPageData::ReleasePattern(const CPDF_Object* pPatternObj) { | |
381 if (!pPatternObj) | |
382 return; | |
383 | |
384 auto it = m_PatternMap.find(pPatternObj); | |
385 if (it == m_PatternMap.end()) | |
386 return; | |
387 | |
388 CPDF_CountedPattern* pPattern = it->second; | |
389 if (!pPattern->get()) | |
390 return; | |
391 | |
392 pPattern->RemoveRef(); | |
393 if (pPattern->use_count() > 1) | |
394 return; | |
395 | |
396 // We have item only in m_PatternMap cache. Clean it. | |
397 pPattern->clear(); | |
398 } | |
399 | |
400 CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream) { | |
401 if (!pImageStream) | |
402 return nullptr; | |
403 | |
404 const uint32_t dwImageObjNum = pImageStream->GetObjNum(); | |
405 auto it = m_ImageMap.find(dwImageObjNum); | |
406 if (it != m_ImageMap.end()) | |
407 return it->second->AddRef(); | |
408 | |
409 CPDF_CountedImage* pCountedImage = new CPDF_CountedImage( | |
410 new CPDF_Image(m_pPDFDoc, pImageStream->AsStream(), false)); | |
411 m_ImageMap[dwImageObjNum] = pCountedImage; | |
412 return pCountedImage->AddRef(); | |
413 } | |
414 | |
415 void CPDF_DocPageData::ReleaseImage(const CPDF_Object* pImageStream) { | |
416 if (!pImageStream) | |
417 return; | |
418 | |
419 uint32_t dwObjNum = pImageStream->GetObjNum(); | |
420 if (!dwObjNum) | |
421 return; | |
422 | |
423 auto it = m_ImageMap.find(dwObjNum); | |
424 if (it == m_ImageMap.end()) | |
425 return; | |
426 | |
427 CPDF_CountedImage* pCountedImage = it->second; | |
428 if (!pCountedImage) | |
429 return; | |
430 | |
431 pCountedImage->RemoveRef(); | |
432 if (pCountedImage->use_count() > 1) | |
433 return; | |
434 | |
435 // We have item only in m_ImageMap cache. Clean it. | |
436 delete pCountedImage->get(); | |
437 delete pCountedImage; | |
438 m_ImageMap.erase(it); | |
439 } | |
440 | |
441 CPDF_IccProfile* CPDF_DocPageData::GetIccProfile( | |
442 CPDF_Stream* pIccProfileStream) { | |
443 if (!pIccProfileStream) | |
444 return nullptr; | |
445 | |
446 auto it = m_IccProfileMap.find(pIccProfileStream); | |
447 if (it != m_IccProfileMap.end()) | |
448 return it->second->AddRef(); | |
449 | |
450 CPDF_StreamAcc stream; | |
451 stream.LoadAllData(pIccProfileStream, FALSE); | |
452 uint8_t digest[20]; | |
453 CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest); | |
454 CFX_ByteString bsDigest(digest, 20); | |
455 auto hash_it = m_HashProfileMap.find(bsDigest); | |
456 if (hash_it != m_HashProfileMap.end()) { | |
457 auto it_copied_stream = m_IccProfileMap.find(hash_it->second); | |
458 if (it_copied_stream != m_IccProfileMap.end()) | |
459 return it_copied_stream->second->AddRef(); | |
460 } | |
461 CPDF_IccProfile* pProfile = | |
462 new CPDF_IccProfile(stream.GetData(), stream.GetSize()); | |
463 CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile(pProfile); | |
464 m_IccProfileMap[pIccProfileStream] = ipData; | |
465 m_HashProfileMap[bsDigest] = pIccProfileStream; | |
466 return ipData->AddRef(); | |
467 } | |
468 | |
469 void CPDF_DocPageData::ReleaseIccProfile(const CPDF_IccProfile* pIccProfile) { | |
470 ASSERT(pIccProfile); | |
471 | |
472 for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) { | |
473 CPDF_CountedIccProfile* profile = it->second; | |
474 if (profile->get() != pIccProfile) | |
475 continue; | |
476 | |
477 profile->RemoveRef(); | |
478 if (profile->use_count() > 1) | |
479 continue; | |
480 // We have item only in m_IccProfileMap cache. Clean it. | |
481 delete profile->get(); | |
482 delete profile; | |
483 m_IccProfileMap.erase(it); | |
484 return; | |
485 } | |
486 } | |
487 | |
488 CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc( | |
489 CPDF_Stream* pFontStream) { | |
490 ASSERT(pFontStream); | |
491 | |
492 auto it = m_FontFileMap.find(pFontStream); | |
493 if (it != m_FontFileMap.end()) | |
494 return it->second->AddRef(); | |
495 | |
496 CPDF_Dictionary* pFontDict = pFontStream->GetDict(); | |
497 int32_t org_size = pFontDict->GetIntegerFor("Length1") + | |
498 pFontDict->GetIntegerFor("Length2") + | |
499 pFontDict->GetIntegerFor("Length3"); | |
500 org_size = std::max(org_size, 0); | |
501 | |
502 CPDF_StreamAcc* pFontFile = new CPDF_StreamAcc; | |
503 pFontFile->LoadAllData(pFontStream, FALSE, org_size); | |
504 | |
505 CPDF_CountedStreamAcc* pCountedFont = new CPDF_CountedStreamAcc(pFontFile); | |
506 m_FontFileMap[pFontStream] = pCountedFont; | |
507 return pCountedFont->AddRef(); | |
508 } | |
509 | |
510 void CPDF_DocPageData::ReleaseFontFileStreamAcc( | |
511 const CPDF_Stream* pFontStream) { | |
512 if (!pFontStream) | |
513 return; | |
514 | |
515 auto it = m_FontFileMap.find(pFontStream); | |
516 if (it == m_FontFileMap.end()) | |
517 return; | |
518 | |
519 CPDF_CountedStreamAcc* pCountedStream = it->second; | |
520 if (!pCountedStream) | |
521 return; | |
522 | |
523 pCountedStream->RemoveRef(); | |
524 if (pCountedStream->use_count() > 1) | |
525 return; | |
526 | |
527 // We have item only in m_FontFileMap cache. Clean it. | |
528 delete pCountedStream->get(); | |
529 delete pCountedStream; | |
530 m_FontFileMap.erase(it); | |
531 } | |
532 | |
533 CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr( | |
534 CPDF_Object* pCSObj) const { | |
535 if (!pCSObj) | |
536 return nullptr; | |
537 | |
538 auto it = m_ColorSpaceMap.find(pCSObj); | |
539 return it != m_ColorSpaceMap.end() ? it->second : nullptr; | |
540 } | |
541 | |
542 CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr( | |
543 CPDF_Object* pPatternObj) const { | |
544 if (!pPatternObj) | |
545 return nullptr; | |
546 | |
547 auto it = m_PatternMap.find(pPatternObj); | |
548 return it != m_PatternMap.end() ? it->second : nullptr; | |
549 } | |
OLD | NEW |