5#include "core/fpdfapi/edit/cpdf_pagecontentmanager.h"
15#include "core/fpdfapi/page/cpdf_pageobject.h"
16#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
17#include "core/fpdfapi/parser/cpdf_array.h"
18#include "core/fpdfapi/parser/cpdf_dictionary.h"
19#include "core/fpdfapi/parser/cpdf_document.h"
20#include "core/fpdfapi/parser/cpdf_reference.h"
21#include "core/fpdfapi/parser/cpdf_stream.h"
22#include "core/fpdfapi/parser/object_tree_traversal_util.h"
23#include "core/fxcrt/check.h"
24#include "core/fxcrt/containers/adapters.h"
25#include "core/fxcrt/containers/contains.h"
26#include "core/fxcrt/numerics/safe_conversions.h"
27#include "third_party/abseil-cpp/absl/types/variant.h"
37 page_dict->GetMutableObjectFor(
"Contents");
40 CHECK(contents_array->IsInline());
41 contents_ = std::move(contents_array);
45 RetainPtr<CPDF_Reference> contents_reference = ToReference(contents_obj);
46 if (contents_reference) {
48 contents_reference->GetMutableDirect();
52 contents_array.Reset(indirect_obj->AsMutableArray());
54 if (pdfium::Contains(objects_with_multi_refs_,
55 contents_array->GetObjNum())) {
57 pdfium::WrapRetain(contents_array->Clone()->AsMutableArray());
58 page_dict->SetFor(
"Contents", cloned_contents_array);
59 contents_ = std::move(cloned_contents_array);
61 contents_ = std::move(contents_array);
63 }
else if (indirect_obj->IsStream()) {
64 contents_ = pdfium::WrapRetain(indirect_obj->AsMutableStream());
70 ExecuteScheduledRemovals();
74 size_t stream_index) {
75 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
76 if (contents_stream) {
77 return stream_index == 0 ? contents_stream :
nullptr;
81 if (!contents_array) {
85 RetainPtr<CPDF_Reference> stream_reference =
86 ToReference(contents_array->GetMutableObjectAt(stream_index));
87 if (!stream_reference)
90 return ToStream(stream_reference->GetMutableDirect());
94 auto new_stream = document_->NewIndirect<CPDF_Stream>(buf);
98 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
99 if (contents_stream) {
100 auto new_contents_array = document_->NewIndirect<CPDF_Array>();
101 new_contents_array->AppendNew<CPDF_Reference>(document_,
102 contents_stream->GetObjNum());
103 new_contents_array->AppendNew<CPDF_Reference>(document_,
104 new_stream->GetObjNum());
107 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
108 new_contents_array->GetObjNum());
109 contents_ = std::move(new_contents_array);
115 if (contents_array) {
116 contents_array->AppendNew<CPDF_Reference>(document_,
117 new_stream->GetObjNum());
118 return contents_array->size() - 1;
124 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
125 new_stream->GetObjNum());
126 contents_ = std::move(new_stream);
131 fxcrt::ostringstream* buf) {
133 if (buf->tellp() <= 0) {
134 ScheduleRemoveStreamByIndex(stream_index);
138 RetainPtr<CPDF_Stream> existing_stream = GetStreamByIndex(stream_index);
139 CHECK(existing_stream);
140 if (!pdfium::Contains(objects_with_multi_refs_,
141 existing_stream->GetObjNum())) {
142 existing_stream->SetDataFromStringstreamAndRemoveFilter(buf);
146 if (GetContentsStream()) {
147 auto new_stream = document_->NewIndirect<CPDF_Stream>(buf);
149 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
150 new_stream->GetObjNum());
154 if (!contents_array) {
158 RetainPtr<CPDF_Reference> stream_reference =
159 ToReference(contents_array->GetMutableObjectAt(stream_index));
160 if (!stream_reference) {
164 auto new_stream = document_->NewIndirect<CPDF_Stream>(buf);
165 stream_reference->SetRef(document_, new_stream->GetObjNum());
169 streams_to_remove_.insert(stream_index);
179 DCHECK(!page_obj_holder_->HasDirtyStreams());
181 if (streams_to_remove_.empty()) {
185 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
186 if (contents_stream) {
188 if (streams_to_remove_.find(0) != streams_to_remove_.end()) {
190 page_dict->RemoveFor(
"Contents");
196 if (!contents_array) {
202 std::vector<size_t> streams_left(contents_array->size());
203 std::iota(streams_left.begin(), streams_left.end(), 0);
207 for (size_t stream_index : pdfium::Reversed(streams_to_remove_)) {
208 contents_array->RemoveAt(stream_index);
209 streams_left.erase(streams_left.begin() + stream_index);
214 std::map<size_t, size_t> stream_index_mapping;
215 for (size_t i = 0; i < streams_left.size(); ++i) {
216 stream_index_mapping[streams_left[i]] = i;
220 for (
const auto& obj : *page_obj_holder_) {
221 int32_t old_stream_index = obj->GetContentStream();
222 int32_t new_stream_index =
223 pdfium::checked_cast<int32_t>(stream_index_mapping[old_stream_index]);
224 obj->SetContentStream(new_stream_index);
233 if (absl::holds_alternative<RetainPtr<CPDF_Stream>>(contents_)) {
234 return absl::get<RetainPtr<CPDF_Stream>>(contents_);
240 if (absl::holds_alternative<RetainPtr<CPDF_Array>>(contents_)) {
241 return absl::get<RetainPtr<CPDF_Array>>(contents_);
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
void UpdateStream(size_t stream_index, fxcrt::ostringstream *buf)
size_t AddStream(fxcrt::ostringstream *buf)
~CPDF_PageContentManager()
CPDF_PageContentManager(CPDF_PageObjectHolder *page_obj_holder, CPDF_Document *document)