5#include "core/fpdfapi/edit/cpdf_pagecontentmanager.h"
16#include "core/fpdfapi/page/cpdf_pageobject.h"
17#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
18#include "core/fpdfapi/parser/cpdf_array.h"
19#include "core/fpdfapi/parser/cpdf_dictionary.h"
20#include "core/fpdfapi/parser/cpdf_document.h"
21#include "core/fpdfapi/parser/cpdf_reference.h"
22#include "core/fpdfapi/parser/cpdf_stream.h"
23#include "core/fpdfapi/parser/object_tree_traversal_util.h"
24#include "third_party/abseil-cpp/absl/types/variant.h"
25#include "third_party/base/check.h"
26#include "third_party/base/containers/adapters.h"
27#include "third_party/base/containers/contains.h"
28#include "third_party/base/numerics/safe_conversions.h"
36 RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict();
38 page_dict->GetMutableObjectFor(
"Contents");
39 RetainPtr<CPDF_Array> contents_array = ToArray(contents_obj);
41 CHECK(contents_array->IsInline());
42 contents_ = std::move(contents_array);
46 RetainPtr<CPDF_Reference> contents_reference = ToReference(contents_obj);
47 if (contents_reference) {
49 contents_reference->GetMutableDirect();
53 contents_array.Reset(indirect_obj->AsMutableArray());
55 if (pdfium::Contains(objects_with_multi_refs_,
56 contents_array->GetObjNum())) {
57 RetainPtr<CPDF_Array> cloned_contents_array =
58 pdfium::WrapRetain(contents_array->Clone()->AsMutableArray());
59 page_dict->SetFor(
"Contents", cloned_contents_array);
60 contents_ = std::move(cloned_contents_array);
62 contents_ = std::move(contents_array);
64 }
else if (indirect_obj->IsStream()) {
65 contents_ = pdfium::WrapRetain(indirect_obj->AsMutableStream());
71 ExecuteScheduledRemovals();
75 size_t stream_index) {
76 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
77 if (contents_stream) {
78 return stream_index == 0 ? contents_stream :
nullptr;
81 RetainPtr<CPDF_Array> contents_array = GetContentsArray();
82 if (!contents_array) {
86 RetainPtr<CPDF_Reference> stream_reference =
87 ToReference(contents_array->GetMutableObjectAt(stream_index));
88 if (!stream_reference)
91 return ToStream(stream_reference->GetMutableDirect());
95 auto new_stream = document_->NewIndirect<CPDF_Stream>();
96 new_stream->SetDataFromStringstream(buf);
100 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
101 if (contents_stream) {
102 auto new_contents_array = document_->NewIndirect<CPDF_Array>();
103 new_contents_array->AppendNew<CPDF_Reference>(document_,
104 contents_stream->GetObjNum());
105 new_contents_array->AppendNew<CPDF_Reference>(document_,
106 new_stream->GetObjNum());
108 RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict();
109 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
110 new_contents_array->GetObjNum());
111 contents_ = std::move(new_contents_array);
116 RetainPtr<CPDF_Array> contents_array = GetContentsArray();
117 if (contents_array) {
118 contents_array->AppendNew<CPDF_Reference>(document_,
119 new_stream->GetObjNum());
120 return contents_array->size() - 1;
125 RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict();
126 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
127 new_stream->GetObjNum());
128 contents_ = std::move(new_stream);
133 fxcrt::ostringstream* buf) {
135 if (buf->tellp() <= 0) {
136 ScheduleRemoveStreamByIndex(stream_index);
140 RetainPtr<CPDF_Stream> existing_stream = GetStreamByIndex(stream_index);
141 CHECK(existing_stream);
142 if (!pdfium::Contains(objects_with_multi_refs_,
143 existing_stream->GetObjNum())) {
144 existing_stream->SetDataFromStringstreamAndRemoveFilter(buf);
148 if (GetContentsStream()) {
149 auto new_stream = document_->NewIndirect<CPDF_Stream>();
150 new_stream->SetDataFromStringstream(buf);
151 RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict();
152 page_dict->SetNewFor<CPDF_Reference>(
"Contents", document_,
153 new_stream->GetObjNum());
156 RetainPtr<CPDF_Array> contents_array = GetContentsArray();
157 if (!contents_array) {
161 RetainPtr<CPDF_Reference> stream_reference =
162 ToReference(contents_array->GetMutableObjectAt(stream_index));
163 if (!stream_reference) {
167 auto new_stream = document_->NewIndirect<CPDF_Stream>();
168 new_stream->SetDataFromStringstream(buf);
169 stream_reference->SetRef(document_, new_stream->GetObjNum());
173 streams_to_remove_.insert(stream_index);
183 DCHECK(!page_obj_holder_->HasDirtyStreams());
185 if (streams_to_remove_.empty()) {
189 RetainPtr<CPDF_Stream> contents_stream = GetContentsStream();
190 if (contents_stream) {
192 if (streams_to_remove_.find(0) != streams_to_remove_.end()) {
193 RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict();
194 page_dict->RemoveFor(
"Contents");
199 RetainPtr<CPDF_Array> contents_array = GetContentsArray();
200 if (!contents_array) {
206 std::vector<size_t> streams_left(contents_array->size());
207 std::iota(streams_left.begin(), streams_left.end(), 0);
211 for (size_t stream_index : pdfium::base::Reversed(streams_to_remove_)) {
212 contents_array->RemoveAt(stream_index);
213 streams_left.erase(streams_left.begin() + stream_index);
218 std::map<size_t, size_t> stream_index_mapping;
219 for (size_t i = 0; i < streams_left.size(); ++i) {
220 stream_index_mapping[streams_left[i]] = i;
224 for (
const auto& obj : *page_obj_holder_) {
225 int32_t old_stream_index = obj->GetContentStream();
226 int32_t new_stream_index = pdfium::base::checked_cast<int32_t>(
227 stream_index_mapping[old_stream_index]);
228 obj->SetContentStream(new_stream_index);
237 if (absl::holds_alternative<RetainPtr<CPDF_Stream>>(contents_)) {
238 return absl::get<RetainPtr<CPDF_Stream>>(contents_);
244 if (absl::holds_alternative<RetainPtr<CPDF_Array>>(contents_)) {
245 return absl::get<RetainPtr<CPDF_Array>>(contents_);
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)