summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp38
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator.h8
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp50
-rw-r--r--core/fpdfapi/page/cpdf_page.cpp4
-rw-r--r--core/fpdfapi/page/cpdf_page.h22
-rw-r--r--core/fpdfapi/page/cpdf_pageobjectholder.cpp4
-rw-r--r--core/fpdfapi/page/cpdf_pageobjectholder.h20
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;