diff options
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 38 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 8 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp | 50 | ||||
-rw-r--r-- | core/fpdfapi/page/cpdf_page.cpp | 4 | ||||
-rw-r--r-- | core/fpdfapi/page/cpdf_page.h | 22 | ||||
-rw-r--r-- | core/fpdfapi/page/cpdf_pageobjectholder.cpp | 4 | ||||
-rw-r--r-- | core/fpdfapi/page/cpdf_pageobjectholder.h | 20 |
7 files changed, 105 insertions, 41 deletions
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 8b39a7a136..508581f551 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -49,9 +49,10 @@ bool GetColor(const CPDF_Color* pColor, float* rgb) { } // namespace -CPDF_PageContentGenerator::CPDF_PageContentGenerator(CPDF_Page* pPage) - : m_pPage(pPage), m_pDocument(m_pPage->m_pDocument.Get()) { - for (const auto& pObj : *pPage->GetPageObjectList()) { +CPDF_PageContentGenerator::CPDF_PageContentGenerator( + CPDF_PageObjectHolder* pObjHolder) + : m_pObjHolder(pObjHolder), m_pDocument(pObjHolder->m_pDocument.Get()) { + for (const auto& pObj : *pObjHolder->GetPageObjectList()) { if (pObj) m_pageObjects.emplace_back(pObj.get()); } @@ -60,12 +61,14 @@ CPDF_PageContentGenerator::CPDF_PageContentGenerator(CPDF_Page* pPage) CPDF_PageContentGenerator::~CPDF_PageContentGenerator() {} void CPDF_PageContentGenerator::GenerateContent() { + ASSERT(m_pObjHolder->IsPage()); + CPDF_Document* pDoc = m_pDocument.Get(); std::ostringstream buf; if (!ProcessPageObjects(&buf)) return; - CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict.Get(); + CPDF_Dictionary* pPageDict = m_pObjHolder->m_pFormDict.Get(); CPDF_Object* pContent = pPageDict ? pPageDict->GetObjectFor("Contents") : nullptr; CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>(); @@ -111,14 +114,15 @@ CFX_ByteString CPDF_PageContentGenerator::RealizeResource( uint32_t dwResourceObjNum, const CFX_ByteString& bsType) { ASSERT(dwResourceObjNum); - if (!m_pPage->m_pResources) { - m_pPage->m_pResources = m_pDocument->NewIndirect<CPDF_Dictionary>(); - m_pPage->m_pFormDict->SetNewFor<CPDF_Reference>( - "Resources", m_pDocument.Get(), m_pPage->m_pResources->GetObjNum()); + if (!m_pObjHolder->m_pResources) { + m_pObjHolder->m_pResources = m_pDocument->NewIndirect<CPDF_Dictionary>(); + m_pObjHolder->m_pFormDict->SetNewFor<CPDF_Reference>( + "Resources", m_pDocument.Get(), + m_pObjHolder->m_pResources->GetObjNum()); } - CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDictFor(bsType); + CPDF_Dictionary* pResList = m_pObjHolder->m_pResources->GetDictFor(bsType); if (!pResList) - pResList = m_pPage->m_pResources->SetNewFor<CPDF_Dictionary>(bsType); + pResList = m_pObjHolder->m_pResources->SetNewFor<CPDF_Dictionary>(bsType); CFX_ByteString name; int idnum = 1; @@ -137,7 +141,7 @@ CFX_ByteString CPDF_PageContentGenerator::RealizeResource( bool CPDF_PageContentGenerator::ProcessPageObjects(std::ostringstream* buf) { bool bDirty = false; for (auto& pPageObj : m_pageObjects) { - if (!pPageObj->IsDirty()) + if (m_pObjHolder->IsPage() && !pPageObj->IsDirty()) continue; bDirty = true; if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) @@ -277,8 +281,8 @@ void CPDF_PageContentGenerator::ProcessGraphics(std::ostringstream* buf, } CFX_ByteString name; - auto it = m_pPage->m_GraphicsMap.find(graphD); - if (it != m_pPage->m_GraphicsMap.end()) { + auto it = m_pObjHolder->m_GraphicsMap.find(graphD); + if (it != m_pObjHolder->m_GraphicsMap.end()) { name = it->second; } else { auto gsDict = pdfium::MakeUnique<CPDF_Dictionary>(); @@ -296,7 +300,7 @@ void CPDF_PageContentGenerator::ProcessGraphics(std::ostringstream* buf, CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(gsDict)); uint32_t dwObjNum = pDict->GetObjNum(); name = RealizeResource(dwObjNum, "ExtGState"); - m_pPage->m_GraphicsMap[graphD] = name; + m_pObjHolder->m_GraphicsMap[graphD] = name; } *buf << "/" << PDF_NameEncode(name).c_str() << " gs "; } @@ -321,9 +325,9 @@ void CPDF_PageContentGenerator::ProcessText(std::ostringstream* buf, else return; fontD.baseFont = pFont->GetBaseFont(); - auto it = m_pPage->m_FontsMap.find(fontD); + auto it = m_pObjHolder->m_FontsMap.find(fontD); CFX_ByteString dictName; - if (it != m_pPage->m_FontsMap.end()) { + if (it != m_pObjHolder->m_FontsMap.end()) { dictName = it->second; } else { uint32_t dwObjNum = pFont->GetFontDict()->GetObjNum(); @@ -337,7 +341,7 @@ void CPDF_PageContentGenerator::ProcessText(std::ostringstream* buf, dwObjNum = pDict->GetObjNum(); } dictName = RealizeResource(dwObjNum, "Font"); - m_pPage->m_FontsMap[fontD] = dictName; + m_pObjHolder->m_FontsMap[fontD] = dictName; } *buf << "/" << PDF_NameEncode(dictName).c_str() << " " << pTextObj->GetFontSize() << " Tf "; diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index 19a2faa6bf..2d90eb4465 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -16,22 +16,22 @@ class CPDF_Document; class CPDF_ImageObject; -class CPDF_Page; class CPDF_PageObject; +class CPDF_PageObjectHolder; class CPDF_PathObject; class CPDF_TextObject; class CPDF_PageContentGenerator { public: - explicit CPDF_PageContentGenerator(CPDF_Page* pPage); + explicit CPDF_PageContentGenerator(CPDF_PageObjectHolder* pObjHolder); ~CPDF_PageContentGenerator(); void GenerateContent(); + bool ProcessPageObjects(std::ostringstream* buf); private: friend class CPDF_PageContentGeneratorTest; - bool ProcessPageObjects(std::ostringstream* buf); void ProcessPath(std::ostringstream* buf, CPDF_PathObject* pPathObj); void ProcessImage(std::ostringstream* buf, CPDF_ImageObject* pImageObj); void ProcessGraphics(std::ostringstream* buf, CPDF_PageObject* pPageObj); @@ -39,7 +39,7 @@ class CPDF_PageContentGenerator { CFX_ByteString RealizeResource(uint32_t dwResourceObjNum, const CFX_ByteString& bsType); - CFX_UnownedPtr<CPDF_Page> const m_pPage; + CFX_UnownedPtr<CPDF_PageObjectHolder> const m_pObjHolder; CFX_UnownedPtr<CPDF_Document> const m_pDocument; std::vector<CFX_UnownedPtr<CPDF_PageObject>> m_pageObjects; }; diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp index 91389eef5f..ef186666f1 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp @@ -4,8 +4,12 @@ #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" +#include <memory> +#include <utility> + #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" @@ -34,7 +38,7 @@ class CPDF_PageContentGeneratorTest : public testing::Test { CPDF_Dictionary* TestGetResource(CPDF_PageContentGenerator* pGen, const CFX_ByteString& type, const CFX_ByteString& name) { - return pGen->m_pPage->m_pResources->GetDictFor(type)->GetDictFor(name); + return pGen->m_pObjHolder->m_pResources->GetDictFor(type)->GetDictFor(name); } void TestProcessText(CPDF_PageContentGenerator* pGen, @@ -273,3 +277,47 @@ TEST_F(CPDF_PageContentGeneratorTest, ProcessText) { EXPECT_EQ("FontDescriptor", fontDesc->GetStringFor("Type")); EXPECT_EQ("Helvetica", fontDesc->GetStringFor("FontName")); } + +TEST_F(CPDF_PageContentGeneratorTest, ProcessEmptyForm) { + auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr); + pDoc->CreateNewDoc(); + auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(); + auto pStream = pdfium::MakeUnique<CPDF_Stream>(nullptr, 0, std::move(pDict)); + + // Create an empty form. + auto pTestForm = + pdfium::MakeUnique<CPDF_Form>(pDoc.get(), nullptr, pStream.get()); + pTestForm->ParseContent(nullptr, nullptr, nullptr); + ASSERT_TRUE(pTestForm->IsParsed()); + + // The generated stream for the empty form should be an empty string. + CPDF_PageContentGenerator generator(pTestForm.get()); + std::ostringstream buf; + generator.ProcessPageObjects(&buf); + EXPECT_EQ("", CFX_ByteString(buf)); +} + +TEST_F(CPDF_PageContentGeneratorTest, ProcessFormWithPath) { + auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr); + pDoc->CreateNewDoc(); + auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(); + const char content[] = + "q 3.102 4.67 m 5.45 0.29 l 4.24 3.15 4.65 2.98 3.456 0.24 c 3.102 4.67 " + "l h f Q\n"; + size_t buf_len = FX_ArraySize(content); + std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len)); + memcpy(buf.get(), content, buf_len); + auto pStream = pdfium::MakeUnique<CPDF_Stream>(std::move(buf), buf_len, + std::move(pDict)); + + // Create a form with a non-empty stream. + auto pTestForm = + pdfium::MakeUnique<CPDF_Form>(pDoc.get(), nullptr, pStream.get()); + pTestForm->ParseContent(nullptr, nullptr, nullptr); + ASSERT_TRUE(pTestForm->IsParsed()); + + CPDF_PageContentGenerator generator(pTestForm.get()); + std::ostringstream process_buf; + generator.ProcessPageObjects(&process_buf); + EXPECT_EQ(content, CFX_ByteString(process_buf)); +} diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp index 075aa9023d..dfbd342f13 100644 --- a/core/fpdfapi/page/cpdf_page.cpp +++ b/core/fpdfapi/page/cpdf_page.cpp @@ -74,6 +74,10 @@ CPDF_Page::CPDF_Page(CPDF_Document* pDocument, CPDF_Page::~CPDF_Page() {} +bool CPDF_Page::IsPage() const { + return true; +} + void CPDF_Page::StartParse() { if (m_ParseState == CONTENT_PARSED || m_ParseState == CONTENT_PARSING) return; diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h index 0a080a58ae..82df60ce9f 100644 --- a/core/fpdfapi/page/cpdf_page.h +++ b/core/fpdfapi/page/cpdf_page.h @@ -7,7 +7,6 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGE_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGE_H_ -#include <map> #include <memory> #include "core/fpdfapi/page/cpdf_pageobjectholder.h" @@ -21,21 +20,6 @@ class CPDF_Object; class CPDF_PageRenderCache; class CPDF_PageRenderContext; -// These structs are used to keep track of resources that have already been -// generated in the page. -struct GraphicsData { - float fillAlpha; - float strokeAlpha; - int blendType; - bool operator<(const GraphicsData& other) const; -}; - -struct FontData { - CFX_ByteString baseFont; - CFX_ByteString type; - bool operator<(const FontData& other) const; -}; - class CPDF_Page : public CPDF_PageObjectHolder { public: class View {}; // Caller implements as desired, empty here due to layering. @@ -45,6 +29,9 @@ class CPDF_Page : public CPDF_PageObjectHolder { bool bPageCache); ~CPDF_Page() override; + // CPDF_PageObjectHolder + bool IsPage() const override; + void ParseContent(); CFX_Matrix GetDisplayMatrix(int xPos, @@ -68,9 +55,6 @@ class CPDF_Page : public CPDF_PageObjectHolder { View* GetView() const { return m_pView; } void SetView(View* pView) { m_pView = pView; } - std::map<GraphicsData, CFX_ByteString> m_GraphicsMap; - std::map<FontData, CFX_ByteString> m_FontsMap; - private: void StartParse(); diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.cpp b/core/fpdfapi/page/cpdf_pageobjectholder.cpp index 53dfd75d5d..50ef780396 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder.cpp +++ b/core/fpdfapi/page/cpdf_pageobjectholder.cpp @@ -25,6 +25,10 @@ CPDF_PageObjectHolder::CPDF_PageObjectHolder(CPDF_Document* pDoc, CPDF_PageObjectHolder::~CPDF_PageObjectHolder() {} +bool CPDF_PageObjectHolder::IsPage() const { + return false; +} + void CPDF_PageObjectHolder::ContinueParse(IFX_Pause* pPause) { if (!m_pParser) return; diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.h b/core/fpdfapi/page/cpdf_pageobjectholder.h index c95ae50520..4733e06b2c 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder.h +++ b/core/fpdfapi/page/cpdf_pageobjectholder.h @@ -7,6 +7,7 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECTHOLDER_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECTHOLDER_H_ +#include <map> #include <memory> #include <vector> @@ -25,11 +26,28 @@ class CPDF_ContentParser; #define PDFTRANS_ISOLATED 0x0200 #define PDFTRANS_KNOCKOUT 0x0400 +// These structs are used to keep track of resources that have already been +// generated in the page object holder. +struct GraphicsData { + float fillAlpha; + float strokeAlpha; + int blendType; + bool operator<(const GraphicsData& other) const; +}; + +struct FontData { + CFX_ByteString baseFont; + CFX_ByteString type; + bool operator<(const FontData& other) const; +}; + class CPDF_PageObjectHolder { public: CPDF_PageObjectHolder(CPDF_Document* pDoc, CPDF_Dictionary* pFormDict); virtual ~CPDF_PageObjectHolder(); + virtual bool IsPage() const; + void ContinueParse(IFX_Pause* pPause); bool IsParsed() const { return m_ParseState == CONTENT_PARSED; } @@ -56,6 +74,8 @@ class CPDF_PageObjectHolder { CFX_UnownedPtr<CPDF_Document> m_pDocument; CFX_UnownedPtr<CPDF_Dictionary> m_pPageResources; CFX_UnownedPtr<CPDF_Dictionary> m_pResources; + std::map<GraphicsData, CFX_ByteString> m_GraphicsMap; + std::map<FontData, CFX_ByteString> m_FontsMap; CFX_FloatRect m_BBox; int m_Transparency; |