Encapsulate more in CPDF_PageContentManager

Right now, CPDF_PageContentManager contains data streams and lets
CPDF_PageContentGenerator access and modify them. Instead, add a new
UpdateStream() to shift more of the work into CPDF_PageContentManager.
Then the interface exposed to CPDF_PageContentGenerator is smaller and
future improvements can all happen within CPDF_PageContentManager.

Change-Id: I198bcd4972603989123b01ff53bd455395f26d5b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/105530
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index 734a717..914bec0 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -160,15 +160,7 @@
       continue;
     }
 
-    RetainPtr<CPDF_Stream> old_stream =
-        page_content_manager.GetStreamByIndex(stream_index);
-    DCHECK(old_stream);
-
-    // If buf is now empty, remove the stream instead of setting the data.
-    if (buf->tellp() <= 0)
-      page_content_manager.ScheduleRemoveStreamByIndex(stream_index);
-    else
-      old_stream->SetDataFromStringstreamAndRemoveFilter(buf);
+    page_content_manager.UpdateStream(stream_index, buf);
   }
 }
 
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
index fbd123e..bf5fefe 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <numeric>
+#include <sstream>
 #include <utility>
 #include <vector>
 
@@ -111,6 +112,18 @@
   return 0;
 }
 
+void CPDF_PageContentManager::UpdateStream(size_t stream_index,
+                                           fxcrt::ostringstream* buf) {
+  // If `buf` is now empty, remove the stream instead of setting the data.
+  if (buf->tellp() <= 0) {
+    ScheduleRemoveStreamByIndex(stream_index);
+    return;
+  }
+
+  RetainPtr<CPDF_Stream> existing_stream = GetStreamByIndex(stream_index);
+  existing_stream->SetDataFromStringstreamAndRemoveFilter(buf);
+}
+
 void CPDF_PageContentManager::ScheduleRemoveStreamByIndex(size_t stream_index) {
   streams_to_remove_.insert(stream_index);
 }
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.h b/core/fpdfapi/edit/cpdf_pagecontentmanager.h
index 1fb2b2f..f1605b4 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentmanager.h
+++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.h
@@ -23,19 +23,23 @@
                           CPDF_Document* document);
   ~CPDF_PageContentManager();
 
-  // Gets the Content stream at a given index. If Contents is a single stream
-  // rather than an array, it is retrievable at index 0.
-  RetainPtr<CPDF_Stream> GetStreamByIndex(size_t stream_index);
-
   // Adds a new Content stream. Its index in the array will be returned, or 0
   // if Contents is not an array, but only a single stream.
   size_t AddStream(fxcrt::ostringstream* buf);
 
+  // Changes the stream at `stream_index` to contain the data in `buf`. If `buf`
+  // is empty, then schedule the removal of the stream instead.
+  void UpdateStream(size_t stream_index, fxcrt::ostringstream* buf);
+
+ private:
+  // Gets the Content stream at a given index. If Contents is a single stream
+  // rather than an array, it is retrievable at index 0.
+  RetainPtr<CPDF_Stream> GetStreamByIndex(size_t stream_index);
+
   // Schedules the removal of the Content stream at a given index. It will be
   // removed upon CPDF_PageContentManager destruction.
   void ScheduleRemoveStreamByIndex(size_t stream_index);
 
- private:
   // Removes all Content streams for which ScheduleRemoveStreamByIndex() was
   // called. Update the content stream of all page objects with the shifted
   // indexes.