Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: core/fpdfapi/parser/cpdf_document.cpp

Issue 2470803003: Traverse PDF page tree only once in CPDF_Document Try 3 (Closed)
Patch Set: Rebase, nits Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 PDFium Authors. All rights reserved. 1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 6
7 #include "core/fpdfapi/parser/cpdf_document.h" 7 #include "core/fpdfapi/parser/cpdf_document.h"
8 8
9 #include <memory> 9 #include <memory>
10 #include <set> 10 #include <set>
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 return pFontDesc; 329 return pFontDesc;
330 } 330 }
331 331
332 } // namespace 332 } // namespace
333 333
334 CPDF_Document::CPDF_Document(std::unique_ptr<CPDF_Parser> pParser) 334 CPDF_Document::CPDF_Document(std::unique_ptr<CPDF_Parser> pParser)
335 : CPDF_IndirectObjectHolder(), 335 : CPDF_IndirectObjectHolder(),
336 m_pParser(std::move(pParser)), 336 m_pParser(std::move(pParser)),
337 m_pRootDict(nullptr), 337 m_pRootDict(nullptr),
338 m_pInfoDict(nullptr), 338 m_pInfoDict(nullptr),
339 m_iNextPageToTraverse(0),
339 m_bLinearized(false), 340 m_bLinearized(false),
340 m_iFirstPageNo(0), 341 m_iFirstPageNo(0),
341 m_dwFirstPageObjNum(0), 342 m_dwFirstPageObjNum(0),
342 m_pDocPage(new CPDF_DocPageData(this)), 343 m_pDocPage(new CPDF_DocPageData(this)),
343 m_pDocRender(new CPDF_DocRenderData(this)), 344 m_pDocRender(new CPDF_DocRenderData(this)),
344 m_pByteStringPool(pdfium::MakeUnique<CFX_ByteStringPool>()) { 345 m_pByteStringPool(pdfium::MakeUnique<CFX_ByteStringPool>()) {
345 if (pParser) 346 if (pParser)
346 SetLastObjNum(m_pParser->GetLastObjNum()); 347 SetLastObjNum(m_pParser->GetLastObjNum());
347 } 348 }
348 349
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 394
394 CPDF_Object* pObjNum = pLinearizationParams->GetObjectFor("O"); 395 CPDF_Object* pObjNum = pLinearizationParams->GetObjectFor("O");
395 if (ToNumber(pObjNum)) 396 if (ToNumber(pObjNum))
396 m_dwFirstPageObjNum = pObjNum->GetInteger(); 397 m_dwFirstPageObjNum = pObjNum->GetInteger();
397 } 398 }
398 399
399 void CPDF_Document::LoadPages() { 400 void CPDF_Document::LoadPages() {
400 m_PageList.SetSize(RetrievePageCount()); 401 m_PageList.SetSize(RetrievePageCount());
401 } 402 }
402 403
403 CPDF_Dictionary* CPDF_Document::FindPDFPage(CPDF_Dictionary* pPages, 404 // When this is called, m_pTreeTraversal[level] exists
Lei Zhang 2016/11/04 01:38:52 Move documentation to the header, or make it an AS
npm 2016/11/04 19:33:33 Done.
404 int iPage, 405 CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage,
405 int nPagesToGo, 406 int& nPagesToGo,
406 int level) { 407 int level) {
408 if (nPagesToGo < 0)
409 return nullptr;
410 CPDF_Dictionary* pPages = m_pTreeTraversal[level].first;
407 CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); 411 CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
408 if (!pKidList) 412 if (!pKidList) {
409 return nPagesToGo == 0 ? pPages : nullptr; 413 if (nPagesToGo != 1)
414 return nullptr;
415 m_PageList.SetAt(iPage, pPages->GetObjNum());
416 return pPages;
417 }
410 418
411 if (level >= FX_MAX_PAGE_LEVEL) 419 if (level >= FX_MAX_PAGE_LEVEL) {
420 m_pTreeTraversal.pop_back();
412 return nullptr; 421 return nullptr;
422 }
413 423
414 for (size_t i = 0; i < pKidList->GetCount(); i++) { 424 CPDF_Dictionary* page = nullptr;
425 for (size_t i = m_pTreeTraversal[level].second; i < pKidList->GetCount();
426 i++) {
427 if (nPagesToGo == 0)
428 break;
415 CPDF_Dictionary* pKid = pKidList->GetDictAt(i); 429 CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
416 if (!pKid) { 430 if (!pKid) {
417 nPagesToGo--; 431 nPagesToGo--;
432 m_pTreeTraversal[level].second++;
418 continue; 433 continue;
419 } 434 }
420 if (pKid == pPages) 435 if (pKid == pPages) {
436 m_pTreeTraversal[level].second++;
421 continue; 437 continue;
438 }
422 if (!pKid->KeyExist("Kids")) { 439 if (!pKid->KeyExist("Kids")) {
423 if (nPagesToGo == 0) 440 m_PageList.SetAt(iPage - nPagesToGo + 1, pKid->GetObjNum());
424 return pKid;
425
426 m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
427 nPagesToGo--; 441 nPagesToGo--;
442 m_pTreeTraversal[level].second++;
443 if (nPagesToGo == 0) {
444 page = pKid;
445 break;
446 }
428 } else { 447 } else {
429 int nPages = pKid->GetIntegerFor("Count"); 448 // If the vector has size level+1, the child is not in yet
430 if (nPagesToGo < nPages) 449 if (static_cast<int>(m_pTreeTraversal.size()) == level + 1)
Lei Zhang 2016/11/04 01:38:52 Should |level| be a size_t since it's an index int
npm 2016/11/04 19:33:33 Yes, I remember I tried this and failed, maybe for
431 return FindPDFPage(pKid, iPage, nPagesToGo, level + 1); 450 m_pTreeTraversal.push_back(std::make_pair(pKid, 0));
432 451 // Now m_pTreeTraversal[level+1] should exist and be equal to pKid.
433 nPagesToGo -= nPages; 452 CPDF_Dictionary* pageKid = TraversePDFPages(iPage, nPagesToGo, level + 1);
453 // Check if child was completely processed, i.e. it popped itself out
454 if (static_cast<int>(m_pTreeTraversal.size()) == level + 1)
455 m_pTreeTraversal[level].second++;
456 // If child did not finish or if no pages to go, we are done
457 if (static_cast<int>(m_pTreeTraversal.size()) != level + 1 ||
npm 2016/11/03 22:37:57 Just noticed this 'if' might be causing confusion.
458 nPagesToGo == 0) {
459 page = pageKid;
460 break;
461 }
434 } 462 }
435 } 463 }
436 return nullptr; 464 if (m_pTreeTraversal[level].second ==
465 static_cast<int>(pKidList->GetCount())) {
466 m_pTreeTraversal.pop_back();
467 }
468 return page;
437 } 469 }
438 470
439 CPDF_Dictionary* CPDF_Document::GetPagesDict() const { 471 CPDF_Dictionary* CPDF_Document::GetPagesDict() const {
440 CPDF_Dictionary* pRoot = GetRoot(); 472 CPDF_Dictionary* pRoot = GetRoot();
441 return pRoot ? pRoot->GetDictFor("Pages") : nullptr; 473 return pRoot ? pRoot->GetDictFor("Pages") : nullptr;
442 } 474 }
443 475
444 bool CPDF_Document::IsPageLoaded(int iPage) const { 476 bool CPDF_Document::IsPageLoaded(int iPage) const {
445 return !!m_PageList.GetAt(iPage); 477 return !!m_PageList.GetAt(iPage);
446 } 478 }
447 479
448 CPDF_Dictionary* CPDF_Document::GetPage(int iPage) { 480 CPDF_Dictionary* CPDF_Document::GetPage(int iPage) {
449 if (iPage < 0 || iPage >= m_PageList.GetSize()) 481 if (iPage < 0 || iPage >= m_PageList.GetSize())
450 return nullptr; 482 return nullptr;
451 483
452 if (m_bLinearized && (iPage == m_iFirstPageNo)) { 484 if (m_bLinearized && (iPage == m_iFirstPageNo)) {
453 if (CPDF_Dictionary* pDict = 485 if (CPDF_Dictionary* pDict =
454 ToDictionary(GetOrParseIndirectObject(m_dwFirstPageObjNum))) { 486 ToDictionary(GetOrParseIndirectObject(m_dwFirstPageObjNum))) {
455 return pDict; 487 return pDict;
456 } 488 }
457 } 489 }
458 490
459 int objnum = m_PageList.GetAt(iPage); 491 int objnum = m_PageList.GetAt(iPage);
460 if (objnum) { 492 if (objnum) {
461 if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum))) 493 if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum)))
462 return pDict; 494 return pDict;
495 return nullptr;
463 } 496 }
464 497
465 CPDF_Dictionary* pPages = GetPagesDict(); 498 CPDF_Dictionary* pPages = GetPagesDict();
466 if (!pPages) 499 if (!pPages)
467 return nullptr; 500 return nullptr;
468 501
469 CPDF_Dictionary* pPage = FindPDFPage(pPages, iPage, iPage, 0); 502 if (m_pTreeTraversal.empty())
470 if (!pPage) 503 m_pTreeTraversal.push_back(std::make_pair(pPages, 0));
471 return nullptr; 504 int nPagesToGo = iPage - m_iNextPageToTraverse + 1;
472 505 CPDF_Dictionary* pPage = TraversePDFPages(iPage, nPagesToGo, 0);
473 m_PageList.SetAt(iPage, pPage->GetObjNum()); 506 m_iNextPageToTraverse = iPage + 1;
474 return pPage; 507 return pPage;
475 } 508 }
476 509
477 void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) { 510 void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) {
478 m_PageList.SetAt(iPage, objNum); 511 m_PageList.SetAt(iPage, objNum);
479 } 512 }
480 513
481 int CPDF_Document::FindPageIndex(CPDF_Dictionary* pNode, 514 int CPDF_Document::FindPageIndex(CPDF_Dictionary* pNode,
482 uint32_t& skip_count, 515 uint32_t& skip_count,
483 uint32_t objnum, 516 uint32_t objnum,
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 continue; 690 continue;
658 } 691 }
659 if (bInsert) { 692 if (bInsert) {
660 pKidList->InsertAt(i, new CPDF_Reference(this, pPageDict->GetObjNum())); 693 pKidList->InsertAt(i, new CPDF_Reference(this, pPageDict->GetObjNum()));
661 pPageDict->SetReferenceFor("Parent", this, pPages->GetObjNum()); 694 pPageDict->SetReferenceFor("Parent", this, pPages->GetObjNum());
662 } else { 695 } else {
663 pKidList->RemoveAt(i); 696 pKidList->RemoveAt(i);
664 } 697 }
665 pPages->SetIntegerFor( 698 pPages->SetIntegerFor(
666 "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); 699 "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
700 // Tree will change, so reset tree transversal variables
Tom Sepez 2016/11/03 22:31:00 nit: maybe a ResetTraversal() helper method that d
npm 2016/11/04 19:33:33 Done.
701 m_iNextPageToTraverse = 0;
702 m_pTreeTraversal.clear();
667 break; 703 break;
668 } 704 }
669 int nPages = pKid->GetIntegerFor("Count"); 705 int nPages = pKid->GetIntegerFor("Count");
670 if (nPagesToGo >= nPages) { 706 if (nPagesToGo >= nPages) {
671 nPagesToGo -= nPages; 707 nPagesToGo -= nPages;
672 continue; 708 continue;
673 } 709 }
674 if (pdfium::ContainsKey(*pVisited, pKid)) 710 if (pdfium::ContainsKey(*pVisited, pKid))
675 return false; 711 return false;
676 712
(...skipping 20 matching lines...) Expand all
697 733
698 if (iPage == nPages) { 734 if (iPage == nPages) {
699 CPDF_Array* pPagesList = pPages->GetArrayFor("Kids"); 735 CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
700 if (!pPagesList) { 736 if (!pPagesList) {
701 pPagesList = new CPDF_Array; 737 pPagesList = new CPDF_Array;
702 pPages->SetFor("Kids", pPagesList); 738 pPages->SetFor("Kids", pPagesList);
703 } 739 }
704 pPagesList->Add(new CPDF_Reference(this, pPageDict->GetObjNum())); 740 pPagesList->Add(new CPDF_Reference(this, pPageDict->GetObjNum()));
705 pPages->SetIntegerFor("Count", nPages + 1); 741 pPages->SetIntegerFor("Count", nPages + 1);
706 pPageDict->SetReferenceFor("Parent", this, pPages->GetObjNum()); 742 pPageDict->SetReferenceFor("Parent", this, pPages->GetObjNum());
743 // Reset tree transversal variables
744 m_iNextPageToTraverse = 0;
745 m_pTreeTraversal.clear();
707 } else { 746 } else {
708 std::set<CPDF_Dictionary*> stack = {pPages}; 747 std::set<CPDF_Dictionary*> stack = {pPages};
709 if (!InsertDeletePDFPage(pPages, iPage, pPageDict, true, &stack)) 748 if (!InsertDeletePDFPage(pPages, iPage, pPageDict, true, &stack))
710 return false; 749 return false;
711 } 750 }
712 m_PageList.InsertAt(iPage, pPageDict->GetObjNum()); 751 m_PageList.InsertAt(iPage, pPageDict->GetObjNum());
713 return true; 752 return true;
714 } 753 }
715 754
716 void CPDF_Document::DeletePage(int iPage) { 755 void CPDF_Document::DeletePage(int iPage) {
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
1009 pBBox, pLogFont->lfWeight / 5); 1048 pBBox, pLogFont->lfWeight / 5);
1010 pFontDesc->SetIntegerFor("CapHeight", capheight); 1049 pFontDesc->SetIntegerFor("CapHeight", capheight);
1011 pFontDict->SetReferenceFor("FontDescriptor", this, 1050 pFontDict->SetReferenceFor("FontDescriptor", this,
1012 AddIndirectObject(pFontDesc)); 1051 AddIndirectObject(pFontDesc));
1013 hFont = SelectObject(hDC, hFont); 1052 hFont = SelectObject(hDC, hFont);
1014 DeleteObject(hFont); 1053 DeleteObject(hFont);
1015 DeleteDC(hDC); 1054 DeleteDC(hDC);
1016 return LoadFont(pBaseDict); 1055 return LoadFont(pBaseDict);
1017 } 1056 }
1018 #endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ 1057 #endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698