From b4bcf69210719810ca563b9f8c0179719e80d212 Mon Sep 17 00:00:00 2001 From: Henrique Nakashima Date: Wed, 11 Jul 2018 21:19:22 +0000 Subject: Write marked content operators when generating a stream. The marked content operators are BMC, BDC and EMC. In the case of BDC, it is preceded by a direct dict or a property name. Bug: pdfium:1118 Change-Id: I3ee736ff7be3e7d7dde55ef581af3444a325e887 Reviewed-on: https://pdfium-review.googlesource.com/37470 Reviewed-by: Lei Zhang Commit-Queue: Henrique Nakashima --- core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp') 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 #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> streams; std::set empty_streams; + std::unique_ptr empty_content_mark = + pdfium::MakeUnique(); + std::map current_content_mark; for (int32_t dirty_stream : all_dirty_streams) { std::unique_ptr 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 empty_content_mark = + pdfium::MakeUnique(); + 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()) -- cgit v1.2.3