diff options
Diffstat (limited to 'core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp')
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 88f14b2ce4..f6a941d200 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -13,7 +13,9 @@ #include <utility> #include "core/fpdfapi/edit/cpdf_pagecontentmanager.h" +#include "core/fpdfapi/edit/cpdf_stringarchivestream.h" #include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/page/cpdf_contentmark.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" @@ -94,6 +96,9 @@ CPDF_PageContentGenerator::GenerateModifiedStreams() { // Start regenerating dirty streams. std::map<int32_t, std::unique_ptr<std::ostringstream>> streams; std::set<int32_t> empty_streams; + std::unique_ptr<const CPDF_ContentMark> empty_content_mark = + pdfium::MakeUnique<CPDF_ContentMark>(); + std::map<int32_t, const CPDF_ContentMark*> current_content_mark; for (int32_t dirty_stream : all_dirty_streams) { std::unique_ptr<std::ostringstream> buf = @@ -108,6 +113,7 @@ CPDF_PageContentGenerator::GenerateModifiedStreams() { streams[dirty_stream] = std::move(buf); empty_streams.insert(dirty_stream); + current_content_mark[dirty_stream] = empty_content_mark.get(); } // Process the page objects, write into each dirty stream. @@ -119,6 +125,8 @@ CPDF_PageContentGenerator::GenerateModifiedStreams() { std::ostringstream* buf = it->second.get(); empty_streams.erase(stream_index); + current_content_mark[stream_index] = ProcessContentMarks( + buf, pPageObj.Get(), current_content_mark[stream_index]); ProcessPageObject(buf, pPageObj.Get()); } @@ -129,6 +137,8 @@ CPDF_PageContentGenerator::GenerateModifiedStreams() { // Clear to show that this stream needs to be deleted. buf->str(""); } else { + FinishMarks(buf, current_content_mark[dirty_stream]); + // Return graphics to original state *buf << "Q\n"; } @@ -201,13 +211,19 @@ ByteString CPDF_PageContentGenerator::RealizeResource( bool CPDF_PageContentGenerator::ProcessPageObjects(std::ostringstream* buf) { bool bDirty = false; + std::unique_ptr<const CPDF_ContentMark> empty_content_mark = + pdfium::MakeUnique<CPDF_ContentMark>(); + const CPDF_ContentMark* content_mark = empty_content_mark.get(); + for (auto& pPageObj : m_pageObjects) { if (m_pObjHolder->IsPage() && !pPageObj->IsDirty()) continue; bDirty = true; + content_mark = ProcessContentMarks(buf, pPageObj.Get(), content_mark); ProcessPageObject(buf, pPageObj.Get()); } + FinishMarks(buf, content_mark); return bDirty; } @@ -219,6 +235,61 @@ void CPDF_PageContentGenerator::UpdateStreamlessPageObjects( } } +const CPDF_ContentMark* CPDF_PageContentGenerator::ProcessContentMarks( + std::ostringstream* buf, + const CPDF_PageObject* pPageObj, + const CPDF_ContentMark* pPrev) { + const CPDF_ContentMark* pNext = &pPageObj->m_ContentMark; + + size_t first_different = pPrev->FindFirstDifference(pNext); + + // Close all marks that are in prev but not in next. + // Technically we should iterate backwards to close from the top to the + // bottom, but since the EMC operators do not identify which mark they are + // closing, it does not matter. + for (size_t i = first_different; i < pPrev->CountItems(); ++i) + *buf << "EMC\n"; + + // Open all marks that are in next but not in prev. + for (size_t i = first_different; i < pNext->CountItems(); ++i) { + const CPDF_ContentMarkItem* item = pNext->GetItem(i); + + // Write mark tag. + *buf << "/" << item->GetName() << " "; + + // If there are no parameters, write a BMC (begin marked content) operator. + if (item->GetParamType() == CPDF_ContentMarkItem::None) { + *buf << "BMC\n"; + continue; + } + + // If there are parameters, write properties, direct or indirect. + if (item->GetParamType() == CPDF_ContentMarkItem::DirectDict) { + CPDF_StringArchiveStream archive_stream(buf); + item->GetParam()->WriteTo(&archive_stream); + *buf << " "; + } else { + ASSERT(item->GetParamType() == CPDF_ContentMarkItem::PropertiesDict); + *buf << "/" << item->GetPropertyName() << " "; + } + + // Write BDC (begin dictionary content) operator. + *buf << "BDC\n"; + } + + return pNext; +} + +void CPDF_PageContentGenerator::FinishMarks( + std::ostringstream* buf, + const CPDF_ContentMark* pContentMark) { + // Technically we should iterate backwards to close from the top to the + // bottom, but since the EMC operators do not identify which mark they are + // closing, it does not matter. + for (size_t i = 0; i < pContentMark->CountItems(); ++i) + *buf << "EMC\n"; +} + void CPDF_PageContentGenerator::ProcessPageObject(std::ostringstream* buf, CPDF_PageObject* pPageObj) { if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) |