summaryrefslogtreecommitdiff
path: root/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp')
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp71
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())