From 27cf78d88fdb44bd246cd17bcc712225388e9134 Mon Sep 17 00:00:00 2001 From: Henrique Nakashima Date: Thu, 14 Jun 2018 16:22:30 +0000 Subject: Rewrite content stream regeneration. Loop through the dirty page objects and streams and regenerate all streams that are dirty. Bug: pdfium:1051 Change-Id: I837b5a7cd9542b7777e7c7ae7ac9cc75f69f30b5 Reviewed-on: https://pdfium-review.googlesource.com/34330 Commit-Queue: Henrique Nakashima Reviewed-by: dsinclair --- core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 105 +++++++++++++++++------- core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 4 +- core/fpdfapi/page/cpdf_pageobject.h | 6 +- 3 files changed, 82 insertions(+), 33 deletions(-) (limited to 'core') diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 19994fa57f..ba8d03d7f9 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -6,6 +6,9 @@ #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" +#include +#include +#include #include #include @@ -73,33 +76,67 @@ void CPDF_PageContentGenerator::GenerateContent() { std::map> CPDF_PageContentGenerator::GenerateModifiedStreams() { - auto buf = pdfium::MakeUnique(); + // Make sure default graphics are created. + (void)GetOrCreateDefaultGraphics(); + // Figure out which streams are dirty. + std::set all_dirty_streams; + for (auto& pPageObj : m_pageObjects) { + if (pPageObj->IsDirty()) + all_dirty_streams.insert(pPageObj->GetContentStream()); + } + const std::set* marked_dirty_streams = + m_pObjHolder->GetDirtyStreams(); + all_dirty_streams.insert(marked_dirty_streams->begin(), + marked_dirty_streams->end()); + + // Start regenerating dirty streams. std::map> streams; - if (GenerateStreamWithNewObjects(buf.get())) - streams[CPDF_PageObject::kNoContentStream] = std::move(buf); + std::map stream_is_empty; - // TODO(pdfium:1051): Generate other streams and add to |streams|. + for (int32_t dirty_stream : all_dirty_streams) { + std::unique_ptr buf = + pdfium::MakeUnique(); - return streams; -} + // Set the default graphic state values + *buf << "q\n"; + if (!m_pObjHolder->GetLastCTM().IsIdentity()) + *buf << m_pObjHolder->GetLastCTM().GetInverse() << " cm\n"; -bool CPDF_PageContentGenerator::GenerateStreamWithNewObjects( - std::ostringstream* buf) { - // Set the default graphic state values - *buf << "q\n"; - if (!m_pObjHolder->GetLastCTM().IsIdentity()) - *buf << m_pObjHolder->GetLastCTM().GetInverse() << " cm\n"; - ProcessDefaultGraphics(buf); - - // Process the page objects - if (!ProcessPageObjects(buf)) - return false; + ProcessDefaultGraphics(buf.get()); - // Return graphics to original state - *buf << "Q\n"; + streams[dirty_stream] = std::move(buf); + stream_is_empty[dirty_stream] = true; + } - return true; + // Process the page objects, write into each dirty stream. + for (auto& pPageObj : m_pageObjects) { + int stream_index = pPageObj->GetContentStream(); + auto it = streams.find(stream_index); + if (it == streams.end()) + continue; + + std::ostringstream* buf = it->second.get(); + stream_is_empty[stream_index] = false; + ProcessPageObject(buf, pPageObj.Get()); + } + + // Finish dirty streams. + for (int32_t dirty_stream : all_dirty_streams) { + std::ostringstream* buf = streams[dirty_stream].get(); + if (stream_is_empty[dirty_stream]) { + // Clear to show that this stream needs to be deleted. + buf->str(""); + } else { + // Return graphics to original state + *buf << "Q\n"; + } + } + + // Clear dirty streams in m_pObjHolder + m_pObjHolder->ClearDirtyStreams(); + + return streams; } void CPDF_PageContentGenerator::UpdateContentStreams( @@ -124,6 +161,9 @@ void CPDF_PageContentGenerator::UpdateContentStreams( page_content_manager.GetStreamByIndex(stream_index); ASSERT(old_stream); + // TODO(pdfium:1051): Remove streams that are now empty. If buf is empty, + // remove this instead of setting the data. + old_stream->SetData(buf); } } @@ -162,21 +202,28 @@ bool CPDF_PageContentGenerator::ProcessPageObjects(std::ostringstream* buf) { continue; bDirty = true; - if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) - ProcessImage(buf, pImageObject); - else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) - ProcessPath(buf, pPathObj); - else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) - ProcessText(buf, pTextObj); - pPageObj->SetDirty(false); + ProcessPageObject(buf, pPageObj.Get()); } return bDirty; } void CPDF_PageContentGenerator::UpdateStreamlessPageObjects( int new_content_stream_index) { - // TODO(pdfium:1051): Mark page objects that did not have a content stream - // with the new content stream index. + for (auto& pPageObj : m_pageObjects) { + if (pPageObj->GetContentStream() == CPDF_PageObject::kNoContentStream) + pPageObj->SetContentStream(new_content_stream_index); + } +} + +void CPDF_PageContentGenerator::ProcessPageObject(std::ostringstream* buf, + CPDF_PageObject* pPageObj) { + if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) + ProcessImage(buf, pImageObject); + else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) + ProcessPath(buf, pPathObj); + else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) + ProcessText(buf, pTextObj); + pPageObj->SetDirty(false); } void CPDF_PageContentGenerator::ProcessImage(std::ostringstream* buf, diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index 04adf1c1d2..13b8431f18 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -35,6 +35,7 @@ class CPDF_PageContentGenerator { private: friend class CPDF_PageContentGeneratorTest; + void ProcessPageObject(std::ostringstream* buf, CPDF_PageObject* pPageObj); void ProcessPath(std::ostringstream* buf, CPDF_PathObject* pPathObj); void ProcessImage(std::ostringstream* buf, CPDF_ImageObject* pImageObj); void ProcessGraphics(std::ostringstream* buf, CPDF_PageObject* pPageObj); @@ -49,9 +50,6 @@ class CPDF_PageContentGenerator { std::map> GenerateModifiedStreams(); - // Generate new stream data with all dirty page objects. - bool GenerateStreamWithNewObjects(std::ostringstream* buf); - // Add buffer as a stream in page's 'Contents' void UpdateContentStreams( std::map>* buf); diff --git a/core/fpdfapi/page/cpdf_pageobject.h b/core/fpdfapi/page/cpdf_pageobject.h index 39e7629541..3fc35aa063 100644 --- a/core/fpdfapi/page/cpdf_pageobject.h +++ b/core/fpdfapi/page/cpdf_pageobject.h @@ -65,10 +65,14 @@ class CPDF_PageObject : public CPDF_GraphicStates { // Get what content stream the object was parsed from in its page. This number // is the index of the content stream in the "Contents" array, or 0 if there // is a single content stream. If the object is newly created, - // kNoContentStream is returned. + // |kNoContentStream| is returned. + // // If the object is spread among more than one content stream, this is the // index of the last stream. int32_t GetContentStream() const { return m_ContentStream; } + void SetContentStream(int32_t new_content_stream) { + m_ContentStream = new_content_stream; + } float m_Left; float m_Right; -- cgit v1.2.3