From a4ad01fe03ffdd1806d31a9d7bb820f6a69a0afb Mon Sep 17 00:00:00 2001 From: Nicolas Pena Date: Wed, 15 Feb 2017 16:26:48 -0500 Subject: Move generated graphics and font maps to CPDF_Page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new CPDF_PageContentGenerator is created for every call of FPDFPage_GenerateContent, so having the maps there will cause duplicated resources to be created every time this method is called. Thus it is better to move these to the page. Change-Id: I47804f79790fc5354f8a94b6387d66b65eda5a20 Reviewed-on: https://pdfium-review.googlesource.com/2717 Reviewed-by: Tom Sepez Commit-Queue: Nicolás Peña --- core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 24 +++------- core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 14 ------ core/fpdfapi/page/cpdf_page.cpp | 10 ++++ core/fpdfapi/page/cpdf_page.h | 17 +++++++ fpdfsdk/fpdfedit_embeddertest.cpp | 62 +++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 32 deletions(-) diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index ff8b676de1..b5fe4c0f35 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -222,8 +222,8 @@ void CPDF_PageContentGenerator::ProcessGraphics(CFX_ByteTextBuf* buf, return; CFX_ByteString name; - auto it = m_GraphicsMap.find(graphD); - if (it != m_GraphicsMap.end()) { + auto it = m_pPage->m_GraphicsMap.find(graphD); + if (it != m_pPage->m_GraphicsMap.end()) { name = it->second; } else { auto gsDict = pdfium::MakeUnique(); @@ -232,23 +232,11 @@ void CPDF_PageContentGenerator::ProcessGraphics(CFX_ByteTextBuf* buf, CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(gsDict)); uint32_t dwObjNum = pDict->GetObjNum(); name = RealizeResource(dwObjNum, "ExtGState"); - m_GraphicsMap[graphD] = name; + m_pPage->m_GraphicsMap[graphD] = name; } *buf << "/" << PDF_NameEncode(name) << " gs "; } -bool CPDF_PageContentGenerator::GraphicsData::operator<( - const GraphicsData& other) const { - if (fillAlpha != other.fillAlpha) - return fillAlpha < other.fillAlpha; - return strokeAlpha < other.strokeAlpha; -} - -bool CPDF_PageContentGenerator::FontData::operator<( - const FontData& other) const { - return baseFont < other.baseFont; -} - // This method adds text to the buffer, BT begins the text object, ET ends it. // Tm sets the text matrix (allows positioning and transforming text). // Tf sets the font name (from Font in Resources) and font size. @@ -262,9 +250,9 @@ void CPDF_PageContentGenerator::ProcessText(CFX_ByteTextBuf* buf, pFont = CPDF_Font::GetStockFont(m_pDocument, "Helvetica"); FontData fontD; fontD.baseFont = pFont->GetBaseFont(); - auto it = m_FontsMap.find(fontD); + auto it = m_pPage->m_FontsMap.find(fontD); CFX_ByteString dictName; - if (it != m_FontsMap.end()) { + if (it != m_pPage->m_FontsMap.end()) { dictName = it->second; } else { auto fontDict = pdfium::MakeUnique(); @@ -274,7 +262,7 @@ void CPDF_PageContentGenerator::ProcessText(CFX_ByteTextBuf* buf, CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(fontDict)); uint32_t dwObjNum = pDict->GetObjNum(); dictName = RealizeResource(dwObjNum, "Font"); - m_FontsMap[fontD] = dictName; + m_pPage->m_FontsMap[fontD] = dictName; } *buf << "/" << PDF_NameEncode(dictName) << " " << pTextObj->GetFontSize() << " Tf "; diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index fd80bd8f44..73e75187e4 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -7,7 +7,6 @@ #ifndef CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ #define CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ -#include #include #include "core/fxcrt/fx_basic.h" @@ -37,19 +36,6 @@ class CPDF_PageContentGenerator { CFX_ByteString RealizeResource(uint32_t dwResourceObjNum, const CFX_ByteString& bsType); - struct GraphicsData { - FX_FLOAT fillAlpha; - FX_FLOAT strokeAlpha; - bool operator<(const GraphicsData& other) const; - }; - - struct FontData { - CFX_ByteString baseFont; - bool operator<(const FontData& other) const; - }; - - std::map m_GraphicsMap; - std::map m_FontsMap; CPDF_Page* const m_pPage; CPDF_Document* const m_pDocument; std::vector m_pageObjects; diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp index ba30ce57c3..46123ab42e 100644 --- a/core/fpdfapi/page/cpdf_page.cpp +++ b/core/fpdfapi/page/cpdf_page.cpp @@ -175,3 +175,13 @@ CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos, x0, y0)); return matrix; } + +bool GraphicsData::operator<(const GraphicsData& other) const { + if (fillAlpha != other.fillAlpha) + return fillAlpha < other.fillAlpha; + return strokeAlpha < other.strokeAlpha; +} + +bool FontData::operator<(const FontData& other) const { + return baseFont < other.baseFont; +} diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h index 6d29a8f34e..9e303562c6 100644 --- a/core/fpdfapi/page/cpdf_page.h +++ b/core/fpdfapi/page/cpdf_page.h @@ -7,6 +7,7 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGE_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGE_H_ +#include #include #include "core/fpdfapi/page/cpdf_pageobjectholder.h" @@ -20,6 +21,19 @@ 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 { + FX_FLOAT fillAlpha; + FX_FLOAT strokeAlpha; + bool operator<(const GraphicsData& other) const; +}; + +struct FontData { + CFX_ByteString baseFont; + bool operator<(const FontData& other) const; +}; + class CPDF_Page : public CPDF_PageObjectHolder { public: class View {}; // Caller implements as desired, empty here due to layering. @@ -52,6 +66,9 @@ class CPDF_Page : public CPDF_PageObjectHolder { View* GetView() const { return m_pView; } void SetView(View* pView) { m_pView = pView; } + std::map m_GraphicsMap; + std::map m_FontsMap; + protected: void StartParse(); diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp index fb561967ec..f877617b49 100644 --- a/fpdfsdk/fpdfedit_embeddertest.cpp +++ b/fpdfsdk/fpdfedit_embeddertest.cpp @@ -5,7 +5,10 @@ #include #include +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxcrt/fx_system.h" +#include "fpdfsdk/fsdk_define.h" #include "public/fpdf_edit.h" #include "public/fpdfview.h" #include "testing/embedder_test.h" @@ -378,3 +381,62 @@ TEST_F(FPDFEditEmbeddertest, AddStandardFontText) { FPDF_ClosePage(page); FPDF_CloseDocument(doc); } + +TEST_F(FPDFEditEmbeddertest, DoubleGenerating) { + // Start with a blank page + FPDF_DOCUMENT doc = FPDF_CreateNewDocument(); + FPDF_PAGE page = FPDFPage_New(doc, 0, 612, 792); + + // Add a red rectangle with some non-default alpha + FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100); + EXPECT_TRUE(FPDFPath_SetFillColor(rect, 255, 0, 0, 128)); + EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0)); + FPDFPage_InsertObject(page, rect); + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + + // Check the ExtGState + CPDF_Page* the_page = CPDFPageFromFPDFPage(page); + CPDF_Dictionary* graphics_dict = + the_page->m_pResources->GetDictFor("ExtGState"); + ASSERT_TRUE(graphics_dict); + EXPECT_EQ(1, static_cast(graphics_dict->GetCount())); + + // Check the bitmap + FPDF_BITMAP page_bitmap = RenderPage(page); + CompareBitmap(page_bitmap, 612, 792, "5384da3406d62360ffb5cac4476fff1c"); + FPDFBitmap_Destroy(page_bitmap); + + // Never mind, my new favorite color is blue, increase alpha + EXPECT_TRUE(FPDFPath_SetFillColor(rect, 0, 0, 255, 180)); + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + EXPECT_EQ(2, static_cast(graphics_dict->GetCount())); + + // Check that bitmap displays changed content + page_bitmap = RenderPage(page); + CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c"); + FPDFBitmap_Destroy(page_bitmap); + + // And now generate, without changes + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + EXPECT_EQ(2, static_cast(graphics_dict->GetCount())); + page_bitmap = RenderPage(page); + CompareBitmap(page_bitmap, 612, 792, "2e51656f5073b0bee611d9cd086aa09c"); + FPDFBitmap_Destroy(page_bitmap); + + // Add some text to the page + FPDF_PAGEOBJECT text = FPDFPageObj_NewTextObj(doc, "Arial", 12.0f); + EXPECT_TRUE(FPDFText_SetText(text, "Something something #text# something")); + FPDFPageObj_Transform(text, 1, 0, 0, 1, 300, 300); + FPDFPage_InsertObject(page, text); + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font"); + ASSERT_TRUE(font_dict); + EXPECT_EQ(1, static_cast(font_dict->GetCount())); + + // Generate yet again, check dicts are reasonably sized + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + EXPECT_EQ(2, static_cast(graphics_dict->GetCount())); + EXPECT_EQ(1, static_cast(font_dict->GetCount())); + FPDF_ClosePage(page); + FPDF_CloseDocument(doc); +} -- cgit v1.2.3