Update CPDF_IndirectObjectHolder APIs for unique objects.

Doing so highlights a few places where ownership is dubious.
Add convenience functions to return an unowned reference to
a newly-created indirect object.

Review-Url: https://codereview.chromium.org/2419173002
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index ad1ffaf..654b69e 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -52,10 +52,9 @@
   if (pContent)
     pPageDict->RemoveFor("Contents");
 
-  CPDF_Stream* pStream = new CPDF_Stream;
+  CPDF_Stream* pStream = m_pDocument->AddIndirectStream();
   pStream->SetData(buf.GetBuffer(), buf.GetLength());
-  pPageDict->SetReferenceFor("Contents", m_pDocument,
-                             m_pDocument->AddIndirectObject(pStream));
+  pPageDict->SetReferenceFor("Contents", m_pDocument, pStream);
 }
 
 CFX_ByteString CPDF_PageContentGenerator::RealizeResource(
@@ -63,10 +62,9 @@
     const CFX_ByteString& bsType) {
   if (!m_pPage->m_pResources) {
     m_pPage->m_pResources =
-        new CPDF_Dictionary(m_pDocument->GetByteStringPool());
-    m_pPage->m_pFormDict->SetReferenceFor(
-        "Resources", m_pDocument,
-        m_pDocument->AddIndirectObject(m_pPage->m_pResources));
+        m_pDocument->AddIndirectDictionary(m_pDocument->GetByteStringPool());
+    m_pPage->m_pFormDict->SetReferenceFor("Resources", m_pDocument,
+                                          m_pPage->m_pResources);
   }
   CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDictFor(bsType);
   if (!pResList) {
@@ -82,8 +80,9 @@
     }
     idnum++;
   }
-  pResList->SetReferenceFor(name, m_pDocument,
-                            m_pDocument->AddIndirectObject(pResourceObj));
+  // TODO(tsepez): check |pResourceObj| ownership.
+  pResList->SetReferenceFor(name, m_pDocument, m_pDocument->AddIndirectObject(
+                                                   UniqueObject(pResourceObj)));
   return name;
 }
 
@@ -170,8 +169,7 @@
     contentStream.LoadAllData(pStream);
     ProcessForm(buf, contentStream.GetData(), contentStream.GetSize(), matrix);
   }
-  CPDF_Stream* pStream = new CPDF_Stream;
+  CPDF_Stream* pStream = m_pDocument->AddIndirectStream();
   pStream->SetData(buf.GetBuffer(), buf.GetLength());
-  m_pPage->m_pFormDict->SetReferenceFor(
-      "Contents", m_pDocument, m_pDocument->AddIndirectObject(pStream));
+  m_pPage->m_pFormDict->SetReferenceFor("Contents", m_pDocument, pStream);
 }
diff --git a/core/fpdfapi/edit/fpdf_edit_create.cpp b/core/fpdfapi/edit/fpdf_edit_create.cpp
index fae2b14..5622b1d 100644
--- a/core/fpdfapi/edit/fpdf_edit_create.cpp
+++ b/core/fpdfapi/edit/fpdf_edit_create.cpp
@@ -1244,12 +1244,10 @@
       m_ObjectOffset[objnum] = 0;
       return 0;
     }
-    if (WriteIndirectObj(pObj)) {
+    if (WriteIndirectObj(pObj))
       return -1;
-    }
-    if (!bExistInMap) {
-      m_pDocument->ReleaseIndirectObject(objnum);
-    }
+    if (!bExistInMap)
+      m_pDocument->DeleteIndirectObject(objnum);
   } else {
     uint8_t* pBuffer;
     uint32_t size;
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp
index 5f1f561..0114c68 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.cpp
+++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -175,7 +175,8 @@
     return fontData->AddRef();
   }
 
-  CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pPDFDoc->GetByteStringPool());
+  CPDF_Dictionary* pDict =
+      m_pPDFDoc->AddIndirectDictionary(m_pPDFDoc->GetByteStringPool());
   pDict->SetNameFor("Type", "Font");
   pDict->SetNameFor("Subtype", "Type1");
   pDict->SetNameFor("BaseFont", fontName);
@@ -183,7 +184,6 @@
     pDict->SetFor("Encoding",
                   pEncoding->Realize(m_pPDFDoc->GetByteStringPool()));
   }
-  m_pPDFDoc->AddIndirectObject(pDict);
   std::unique_ptr<CPDF_Font> pFont = CPDF_Font::Create(m_pPDFDoc, pDict);
   if (!pFont)
     return nullptr;
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp
index 50768c5..2755381 100644
--- a/core/fpdfapi/page/cpdf_image.cpp
+++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -204,7 +204,7 @@
   } else if (bpp == 8) {
     int32_t iPalette = pBitmap->GetPaletteSize();
     if (iPalette > 0) {
-      CPDF_Array* pCS = new CPDF_Array;
+      UniqueArray pCS(new CPDF_Array);
       pCS->AddName("Indexed");
       pCS->AddName("DeviceRGB");
       pCS->AddInteger(iPalette - 1);
@@ -217,12 +217,12 @@
         ptr[2] = (uint8_t)argb;
         ptr += 3;
       }
-      CPDF_Stream* pCTS = new CPDF_Stream(
+      CPDF_Stream* pCTS = m_pDocument->AddIndirectStream(
           pColorTable, iPalette * 3,
           new CPDF_Dictionary(m_pDocument->GetByteStringPool()));
-      pCS->AddReference(m_pDocument, m_pDocument->AddIndirectObject(pCTS));
+      pCS->AddReference(m_pDocument, pCTS->GetObjNum());
       pDict->SetReferenceFor("ColorSpace", m_pDocument,
-                             m_pDocument->AddIndirectObject(pCS));
+                             m_pDocument->AddIndirectObject(std::move(pCS)));
     } else {
       pDict->SetNameFor("ColorSpace", "DeviceGray");
     }
@@ -274,9 +274,9 @@
       }
     }
     pMaskDict->SetIntegerFor("Length", mask_size);
-    pDict->SetReferenceFor("SMask", m_pDocument,
-                           m_pDocument->AddIndirectObject(new CPDF_Stream(
-                               mask_buf, mask_size, pMaskDict)));
+    pDict->SetReferenceFor(
+        "SMask", m_pDocument,
+        m_pDocument->AddIndirectStream(mask_buf, mask_size, pMaskDict));
     if (bDeleteMask)
       delete pMaskBitmap;
   }
diff --git a/core/fpdfapi/parser/cfdf_document.cpp b/core/fpdfapi/parser/cfdf_document.cpp
index a1518df..1239fcd 100644
--- a/core/fpdfapi/parser/cfdf_document.cpp
+++ b/core/fpdfapi/parser/cfdf_document.cpp
@@ -26,8 +26,7 @@
 
 CFDF_Document* CFDF_Document::CreateNewDoc() {
   CFDF_Document* pDoc = new CFDF_Document;
-  pDoc->m_pRootDict = new CPDF_Dictionary(pDoc->GetByteStringPool());
-  pDoc->AddIndirectObject(pDoc->m_pRootDict);
+  pDoc->m_pRootDict = pDoc->AddIndirectDictionary(pDoc->GetByteStringPool());
   pDoc->m_pRootDict->SetFor("FDF",
                             new CPDF_Dictionary(pDoc->GetByteStringPool()));
   return pDoc;
@@ -69,7 +68,8 @@
       if (!pObj)
         break;
 
-      ReplaceIndirectObjectIfHigherGeneration(objnum, pObj);
+      // TODO(tsepez): check |pObj| ownership.
+      ReplaceIndirectObjectIfHigherGeneration(objnum, UniqueObject(pObj));
       word = parser.GetNextWord(nullptr);
       if (word != "endobj")
         break;
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index 807f62d..db3b18b 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -152,8 +152,9 @@
   if (!m_Objects[i] || m_Objects[i]->IsReference())
     return;
 
-  uint32_t dwObjNum = pHolder->AddIndirectObject(m_Objects[i].release());
-  m_Objects[i] = UniqueObject(new CPDF_Reference(pHolder, dwObjNum));
+  CPDF_Object* pUnowned = pHolder->AddIndirectObject(std::move(m_Objects[i]));
+  m_Objects[i] =
+      UniqueObject(new CPDF_Reference(pHolder, pUnowned->GetObjNum()));
 }
 
 void CPDF_Array::SetAt(size_t i, CPDF_Object* pObj) {
@@ -205,3 +206,8 @@
                               uint32_t objnum) {
   Add(new CPDF_Reference(pDoc, objnum));
 }
+
+void CPDF_Array::AddReference(CPDF_IndirectObjectHolder* pDoc,
+                              const CPDF_Object* pObj) {
+  AddReference(pDoc, pObj->GetObjNum());
+}
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index f473e26..18f1c00 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -54,6 +54,7 @@
   void AddString(const CFX_ByteString& str);
   void AddName(const CFX_ByteString& str);
   void AddReference(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum);
+  void AddReference(CPDF_IndirectObjectHolder* pDoc, const CPDF_Object* pObj);
 
   iterator begin() { return m_Objects.begin(); }
   iterator end() { return m_Objects.end(); }
diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp
index bc9f578..a3a27fc 100644
--- a/core/fpdfapi/parser/cpdf_array_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp
@@ -113,10 +113,11 @@
     for (size_t i = 0; i < kNumOfRows; ++i) {
       CPDF_Array* arr_elem = new CPDF_Array;
       for (size_t j = 0; j < kNumOfRowElems; ++j) {
-        CPDF_Number* obj = new CPDF_Number(elems[i][j]);
-        // Starts object number from 1.
+        UniqueObject obj(new CPDF_Number(elems[i][j]));
+        // Object number starts from 1.
         int obj_num = i * kNumOfRowElems + j + 1;
-        obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num, obj);
+        obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num,
+                                                            std::move(obj));
         arr_elem->InsertAt(j, new CPDF_Reference(obj_holder.get(), obj_num));
       }
       arr->InsertAt(i, arr_elem);
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index 980c94d..9629c20 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -1771,8 +1771,9 @@
       if (!pPageDict)
         return nullptr;
 
-      if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(dwObjNum,
-                                                                pPageDict)) {
+      // TODO(tsepez): check |pPageDict| ownership.
+      if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(
+              dwObjNum, UniqueObject(pPageDict))) {
         return nullptr;
       }
       return pPageDict->GetDict();
diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp
index 435eee7..0f03947 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.cpp
+++ b/core/fpdfapi/parser/cpdf_dictionary.cpp
@@ -188,8 +188,8 @@
   if (it == m_Map.end() || it->second->IsReference())
     return;
 
-  uint32_t objnum = pHolder->AddIndirectObject(it->second.release());
-  it->second = UniqueReference(new CPDF_Reference(pHolder, objnum));
+  CPDF_Object* pObj = pHolder->AddIndirectObject(std::move(it->second));
+  it->second = UniqueReference(new CPDF_Reference(pHolder, pObj->GetObjNum()));
 }
 
 void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) {
@@ -229,6 +229,12 @@
   SetFor(key, new CPDF_Reference(pDoc, objnum));
 }
 
+void CPDF_Dictionary::SetReferenceFor(const CFX_ByteString& key,
+                                      CPDF_IndirectObjectHolder* pDoc,
+                                      const CPDF_Object* pObj) {
+  SetReferenceFor(key, pDoc, pObj->GetObjNum());
+}
+
 void CPDF_Dictionary::SetNumberFor(const CFX_ByteString& key, FX_FLOAT f) {
   SetFor(key, new CPDF_Number(f));
 }
diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h
index 6265522..3e55812 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.h
+++ b/core/fpdfapi/parser/cpdf_dictionary.h
@@ -67,6 +67,9 @@
   void SetReferenceFor(const CFX_ByteString& key,
                        CPDF_IndirectObjectHolder* pDoc,
                        uint32_t objnum);
+  void SetReferenceFor(const CFX_ByteString& key,
+                       CPDF_IndirectObjectHolder* pDoc,
+                       const CPDF_Object* objnum);
   void SetRectFor(const CFX_ByteString& key, const CFX_FloatRect& rect);
   void SetMatrixFor(const CFX_ByteString& key, const CFX_Matrix& matrix);
   void SetBooleanFor(const CFX_ByteString& key, bool bValue);
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index c5f64a7..fdd395e 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -256,7 +256,7 @@
       if (nPagesToGo == 0) {
         if (bInsert) {
           pKidList->InsertAt(i, new CPDF_Reference(pDoc, pPage->GetObjNum()));
-          pPage->SetReferenceFor("Parent", pDoc, pPages->GetObjNum());
+          pPage->SetReferenceFor("Parent", pDoc, pPages);
         } else {
           pKidList->RemoveAt(i);
         }
@@ -307,7 +307,7 @@
     }
     pPagesList->Add(new CPDF_Reference(pDoc, pPageDict->GetObjNum()));
     pPages->SetIntegerFor("Count", nPages + 1);
-    pPageDict->SetReferenceFor("Parent", pDoc, pPages->GetObjNum());
+    pPageDict->SetReferenceFor("Parent", pDoc, pPages);
   } else {
     std::set<CPDF_Dictionary*> stack = {pPages};
     if (InsertDeletePDFPage(pDoc, pPages, iPage, pPageDict, TRUE, &stack) < 0)
@@ -693,25 +693,23 @@
 
 void CPDF_Document::CreateNewDoc() {
   ASSERT(!m_pRootDict && !m_pInfoDict);
-  m_pRootDict = new CPDF_Dictionary(m_pByteStringPool);
+  m_pRootDict = AddIndirectDictionary(m_pByteStringPool);
   m_pRootDict->SetNameFor("Type", "Catalog");
-  AddIndirectObject(m_pRootDict);
 
-  CPDF_Dictionary* pPages = new CPDF_Dictionary(m_pByteStringPool);
+  CPDF_Dictionary* pPages = AddIndirectDictionary(m_pByteStringPool);
   pPages->SetNameFor("Type", "Pages");
   pPages->SetNumberFor("Count", 0);
   pPages->SetFor("Kids", new CPDF_Array);
-  m_pRootDict->SetReferenceFor("Pages", this, AddIndirectObject(pPages));
-  m_pInfoDict = new CPDF_Dictionary(m_pByteStringPool);
-  AddIndirectObject(m_pInfoDict);
+
+  m_pRootDict->SetReferenceFor("Pages", this, pPages);
+  m_pInfoDict = AddIndirectDictionary(m_pByteStringPool);
 }
 
 CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) {
-  CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pByteStringPool);
+  CPDF_Dictionary* pDict = AddIndirectDictionary(m_pByteStringPool);
   pDict->SetNameFor("Type", "Page");
-  uint32_t dwObjNum = AddIndirectObject(pDict);
   if (InsertNewPage(this, iPage, pDict, m_PageList) < 0) {
-    ReleaseIndirectObject(dwObjNum);
+    DeleteIndirectObject(pDict->GetObjNum());
     return nullptr;
   }
   return pDict;
@@ -750,7 +748,8 @@
   }
   if (i == FX_ArraySize(g_FX_CharsetUnicodes))
     return i;
-  CPDF_Dictionary* pEncodingDict = new CPDF_Dictionary(m_pByteStringPool);
+
+  CPDF_Dictionary* pEncodingDict = AddIndirectDictionary(m_pByteStringPool);
   pEncodingDict->SetNameFor("BaseEncoding", "WinAnsiEncoding");
   CPDF_Array* pArray = new CPDF_Array;
   pArray->AddInteger(128);
@@ -760,9 +759,7 @@
     pArray->AddName(name.IsEmpty() ? ".notdef" : name);
   }
   pEncodingDict->SetFor("Differences", pArray);
-  pBaseDict->SetReferenceFor("Encoding", this,
-                             AddIndirectObject(pEncodingDict));
-
+  pBaseDict->SetReferenceFor("Encoding", this, pEncodingDict);
   return i;
 }
 
@@ -772,7 +769,7 @@
     FX_BOOL bVert,
     CFX_ByteString basefont,
     std::function<void(FX_WCHAR, FX_WCHAR, CPDF_Array*)> Insert) {
-  CPDF_Dictionary* pFontDict = new CPDF_Dictionary(m_pByteStringPool);
+  CPDF_Dictionary* pFontDict = AddIndirectDictionary(m_pByteStringPool);
   CFX_ByteString cmap;
   CFX_ByteString ordering;
   int supplement = 0;
@@ -822,14 +819,17 @@
   pFontDict->SetNameFor("Type", "Font");
   pFontDict->SetNameFor("Subtype", "CIDFontType2");
   pFontDict->SetNameFor("BaseFont", basefont);
+
   CPDF_Dictionary* pCIDSysInfo = new CPDF_Dictionary(m_pByteStringPool);
   pCIDSysInfo->SetStringFor("Registry", "Adobe");
   pCIDSysInfo->SetStringFor("Ordering", ordering);
   pCIDSysInfo->SetIntegerFor("Supplement", supplement);
   pFontDict->SetFor("CIDSystemInfo", pCIDSysInfo);
+
   CPDF_Array* pArray = new CPDF_Array;
   pBaseDict->SetFor("DescendantFonts", pArray);
-  pArray->AddReference(this, AddIndirectObject(pFontDict));
+
+  pArray->AddReference(this, pFontDict);
   return pFontDict;
 }
 
@@ -847,7 +847,7 @@
       CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
                      false, false, charset == FXFONT_SYMBOL_CHARSET);
 
-  CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool);
+  CPDF_Dictionary* pBaseDict = AddIndirectDictionary(m_pByteStringPool);
   pBaseDict->SetNameFor("Type", "Font");
   std::unique_ptr<CFX_UnicodeEncoding> pEncoding(
       new CFX_UnicodeEncoding(pFont));
@@ -888,7 +888,6 @@
                                                 end, widthArr);
                             });
   }
-  AddIndirectObject(pBaseDict);
   int italicangle =
       pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0;
   FX_RECT bbox;
@@ -916,8 +915,11 @@
   CPDF_Dictionary* pFontDesc =
       CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(),
                         pFont->GetDescent(), pBBox, nStemV);
+
+  // TODO(tsepez): check |pFontDesc| ownership.
   pFontDict->SetReferenceFor("FontDescriptor", this,
-                             AddIndirectObject(pFontDesc));
+                             AddIndirectObject(UniqueDictionary(pFontDesc)));
+
   return LoadFont(pBaseDict);
 }
 
@@ -979,7 +981,7 @@
                  ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
   FX_Free(tm_buf);
   basefont.Replace(" ", "");
-  CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool);
+  CPDF_Dictionary* pBaseDict = AddIndirectDictionary(m_pByteStringPool);
   pBaseDict->SetNameFor("Type", "Font");
   CPDF_Dictionary* pFontDict = pBaseDict;
   if (!bCJK) {
@@ -1004,7 +1006,6 @@
                       InsertWidthArray(hDC, start, end, widthArr);
                     });
   }
-  AddIndirectObject(pBaseDict);
   CPDF_Array* pBBox = new CPDF_Array;
   for (int i = 0; i < 4; i++)
     pBBox->AddInteger(bbox[i]);
@@ -1012,8 +1013,11 @@
       CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend,
                         pBBox, pLogFont->lfWeight / 5);
   pFontDesc->SetIntegerFor("CapHeight", capheight);
+
+  // TODO(tsepez): check |pFontDesc| ownership.
   pFontDict->SetReferenceFor("FontDescriptor", this,
-                             AddIndirectObject(pFontDesc));
+                             AddIndirectObject(UniqueObject(pFontDesc)));
+
   hFont = SelectObject(hDC, hFont);
   DeleteObject(hFont);
   DeleteDC(hDC);
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
index 6e549de..49567e5 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
@@ -6,8 +6,11 @@
 
 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
 
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
 
 CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder() : m_LastObjNum(0) {}
 
@@ -42,35 +45,59 @@
   return nullptr;
 }
 
-uint32_t CPDF_IndirectObjectHolder::AddIndirectObject(CPDF_Object* pObj) {
+CPDF_Object* CPDF_IndirectObjectHolder::AddIndirectObject(UniqueObject pObj) {
   if (pObj->m_ObjNum)
-    return pObj->m_ObjNum;
+    return pObj.release();  // TODO(tsepez): shouldn't happen, stop this leak.
 
-  m_LastObjNum++;
+  pObj->m_ObjNum = ++m_LastObjNum;
   m_IndirectObjs[m_LastObjNum].release();  // TODO(tsepez): stop this leak.
-  m_IndirectObjs[m_LastObjNum].reset(pObj);
-  pObj->m_ObjNum = m_LastObjNum;
-  return m_LastObjNum;
+  m_IndirectObjs[m_LastObjNum].reset(pObj.release());  // Changes deleters.
+  return m_IndirectObjs[m_LastObjNum].get();
+}
+
+CPDF_Array* CPDF_IndirectObjectHolder::AddIndirectArray() {
+  return ToArray(AddIndirectObject(UniqueObject(new CPDF_Array())));
+}
+
+CPDF_Dictionary* CPDF_IndirectObjectHolder::AddIndirectDictionary() {
+  return ToDictionary(AddIndirectObject(UniqueObject(new CPDF_Dictionary())));
+}
+
+CPDF_Dictionary* CPDF_IndirectObjectHolder::AddIndirectDictionary(
+    const CFX_WeakPtr<CFX_ByteStringPool>& pPool) {
+  return ToDictionary(
+      AddIndirectObject(UniqueObject(new CPDF_Dictionary(pPool))));
+}
+
+CPDF_Stream* CPDF_IndirectObjectHolder::AddIndirectStream() {
+  return ToStream(AddIndirectObject(UniqueObject(new CPDF_Stream())));
+}
+
+CPDF_Stream* CPDF_IndirectObjectHolder::AddIndirectStream(
+    uint8_t* pData,
+    uint32_t size,
+    CPDF_Dictionary* pDict) {
+  return ToStream(
+      AddIndirectObject(UniqueObject(new CPDF_Stream(pData, size, pDict))));
 }
 
 bool CPDF_IndirectObjectHolder::ReplaceIndirectObjectIfHigherGeneration(
     uint32_t objnum,
-    CPDF_Object* pObj) {
+    UniqueObject pObj) {
   if (!objnum || !pObj)
     return false;
 
   CPDF_Object* pOldObj = GetIndirectObject(objnum);
-  if (pOldObj && pObj->GetGenNum() <= pOldObj->GetGenNum()) {
-    delete pObj;
+  if (pOldObj && pObj->GetGenNum() <= pOldObj->GetGenNum())
     return false;
-  }
+
   pObj->m_ObjNum = objnum;
-  m_IndirectObjs[objnum].reset(pObj);
+  m_IndirectObjs[objnum].reset(pObj.release());  // Changes deleters.
   m_LastObjNum = std::max(m_LastObjNum, objnum);
   return true;
 }
 
-void CPDF_IndirectObjectHolder::ReleaseIndirectObject(uint32_t objnum) {
+void CPDF_IndirectObjectHolder::DeleteIndirectObject(uint32_t objnum) {
   CPDF_Object* pObj = GetIndirectObject(objnum);
   if (!pObj || pObj->GetObjNum() == CPDF_Object::kInvalidObjNum)
     return;
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.h b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
index da4e942..074e428 100644
--- a/core/fpdfapi/parser/cpdf_indirect_object_holder.h
+++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
@@ -10,9 +10,14 @@
 #include <map>
 #include <memory>
 
+#include "core/fpdfapi/parser/cpdf_object.h"
+#include "core/fxcrt/cfx_string_pool_template.h"
+#include "core/fxcrt/cfx_weak_ptr.h"
 #include "core/fxcrt/fx_system.h"
 
-class CPDF_Object;
+class CPDF_Array;
+class CPDF_Dictionary;
+class CPDF_Stream;
 
 class CPDF_IndirectObjectHolder {
  public:
@@ -24,12 +29,23 @@
 
   CPDF_Object* GetIndirectObject(uint32_t objnum) const;
   CPDF_Object* GetOrParseIndirectObject(uint32_t objnum);
-  void ReleaseIndirectObject(uint32_t objnum);
+  void DeleteIndirectObject(uint32_t objnum);
 
-  // Take ownership of |pObj|.
-  uint32_t AddIndirectObject(CPDF_Object* pObj);
+  // Take ownership of |pObj|, returns unowned pointer to it.
+  CPDF_Object* AddIndirectObject(UniqueObject pObj);
+
+  // Adds and owns a new object, returns unowned pointer to it.
+  CPDF_Array* AddIndirectArray();
+  CPDF_Dictionary* AddIndirectDictionary();
+  CPDF_Dictionary* AddIndirectDictionary(
+      const CFX_WeakPtr<CFX_ByteStringPool>& pPool);
+  CPDF_Stream* AddIndirectStream();
+  CPDF_Stream* AddIndirectStream(uint8_t* pData,
+                                 uint32_t size,
+                                 CPDF_Dictionary* pDict);
+
   bool ReplaceIndirectObjectIfHigherGeneration(uint32_t objnum,
-                                               CPDF_Object* pObj);
+                                               UniqueObject pObj);
 
   uint32_t GetLastObjNum() const { return m_LastObjNum; }
   void SetLastObjNum(uint32_t objnum) { m_LastObjNum = objnum; }
@@ -42,6 +58,8 @@
 
  private:
   uint32_t m_LastObjNum;
+
+  // Ordinary deleter, not Release().
   std::map<uint32_t, std::unique_ptr<CPDF_Object>> m_IndirectObjs;
 };
 
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index e5a5f54..b47a06f 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -101,7 +101,7 @@
                       m_ArrayObj->Clone(),       m_DictObj->Clone(),
                       stream_obj->Clone()};
     for (size_t i = 0; i < m_IndirectObjs.size(); ++i) {
-      m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]);
+      m_ObjHolder->AddIndirectObject(UniqueObject(m_IndirectObjs[i]));
       m_RefObjs.emplace_back(new CPDF_Reference(
           m_ObjHolder.get(), m_IndirectObjs[i]->GetObjNum()));
     }
@@ -730,8 +730,8 @@
   // Create two arrays of references by different AddReference() APIs.
   for (size_t i = 0; i < FX_ArraySize(indirect_objs); ++i) {
     // All the indirect objects inserted will be owned by holder.
-    holder->ReplaceIndirectObjectIfHigherGeneration(obj_nums[i],
-                                                    indirect_objs[i]);
+    holder->ReplaceIndirectObjectIfHigherGeneration(
+        obj_nums[i], UniqueObject(indirect_objs[i]));
     arr->AddReference(holder.get(), obj_nums[i]);
     arr1->AddReference(holder.get(), indirect_objs[i]->GetObjNum());
   }
@@ -841,9 +841,8 @@
   {
     CPDF_IndirectObjectHolder objects_holder;
     // Create an object with a reference loop.
-    CPDF_Dictionary* dict_obj = new CPDF_Dictionary();
+    CPDF_Dictionary* dict_obj = objects_holder.AddIndirectDictionary();
     CPDF_Array* arr_obj = new CPDF_Array;
-    objects_holder.AddIndirectObject(dict_obj);
     EXPECT_EQ(1u, dict_obj->GetObjNum());
     dict_obj->SetFor("arr", arr_obj);
     arr_obj->InsertAt(
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index 40a615f..d9c892f 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -955,21 +955,18 @@
 }
 
 FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE* pos, FX_BOOL bMainXRef) {
-  std::unique_ptr<CPDF_Object> pObject(
-      ParseIndirectObjectAt(m_pDocument, *pos, 0));
+  UniqueObject pObject(ParseIndirectObjectAt(m_pDocument, *pos, 0));
   if (!pObject)
     return FALSE;
 
   CPDF_Object* pUnownedObject = pObject.get();
-
   if (m_pDocument) {
     CPDF_Dictionary* pRootDict = m_pDocument->GetRoot();
     if (pRootDict && pRootDict->GetObjNum() == pObject->m_ObjNum)
       return FALSE;
-    // Takes ownership of object (std::move someday).
     uint32_t objnum = pObject->m_ObjNum;
     if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(
-            objnum, pObject.release())) {
+            objnum, std::move(pObject))) {
       return FALSE;
     }
   }
diff --git a/core/fpdfdoc/cpdf_formfield_unittest.cpp b/core/fpdfdoc/cpdf_formfield_unittest.cpp
index 11cccf1..a9d3d24 100644
--- a/core/fpdfdoc/cpdf_formfield_unittest.cpp
+++ b/core/fpdfdoc/cpdf_formfield_unittest.cpp
@@ -12,15 +12,13 @@
   EXPECT_TRUE(name.IsEmpty());
 
   CPDF_IndirectObjectHolder obj_holder;
-  CPDF_Dictionary* root = new CPDF_Dictionary();
-  obj_holder.AddIndirectObject(root);
+  CPDF_Dictionary* root = obj_holder.AddIndirectDictionary();
   root->SetNameFor("T", "foo");
   name = FPDF_GetFullName(root);
   EXPECT_STREQ("foo", name.UTF8Encode().c_str());
 
-  CPDF_Dictionary* dict1 = new CPDF_Dictionary();
-  root->SetReferenceFor("Parent", &obj_holder,
-                        obj_holder.AddIndirectObject(dict1));
+  CPDF_Dictionary* dict1 = obj_holder.AddIndirectDictionary();
+  root->SetReferenceFor("Parent", &obj_holder, dict1);
   dict1->SetNameFor("T", "bar");
   name = FPDF_GetFullName(root);
   EXPECT_STREQ("bar.foo", name.UTF8Encode().c_str());
@@ -30,9 +28,8 @@
   name = FPDF_GetFullName(root);
   EXPECT_STREQ("bar.foo", name.UTF8Encode().c_str());
 
-  CPDF_Dictionary* dict3 = new CPDF_Dictionary();
-  dict2->SetReferenceFor("Parent", &obj_holder,
-                         obj_holder.AddIndirectObject(dict3));
+  CPDF_Dictionary* dict3 = obj_holder.AddIndirectDictionary();
+  dict2->SetReferenceFor("Parent", &obj_holder, dict3);
   dict3->SetNameFor("T", "qux");
   name = FPDF_GetFullName(root);
   EXPECT_STREQ("qux.bar.foo", name.UTF8Encode().c_str());
diff --git a/core/fpdfdoc/cpdf_interform.cpp b/core/fpdfdoc/cpdf_interform.cpp
index 3bef85e..cafc912 100644
--- a/core/fpdfdoc/cpdf_interform.cpp
+++ b/core/fpdfdoc/cpdf_interform.cpp
@@ -59,9 +59,9 @@
     return;
 
   if (!pFormDict) {
-    pFormDict = new CPDF_Dictionary(pDocument->GetByteStringPool());
-    pDocument->GetRoot()->SetReferenceFor(
-        "AcroForm", pDocument, pDocument->AddIndirectObject(pFormDict));
+    pFormDict =
+        pDocument->AddIndirectDictionary(pDocument->GetByteStringPool());
+    pDocument->GetRoot()->SetReferenceFor("AcroForm", pDocument, pFormDict);
   }
 
   CFX_ByteString csDA;
@@ -274,8 +274,7 @@
   csNameTag.Remove(' ');
   csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4,
                                                       csNameTag.c_str());
-  pFonts->SetReferenceFor(csNameTag, pDocument,
-                          pFont->GetFontDict()->GetObjNum());
+  pFonts->SetReferenceFor(csNameTag, pDocument, pFont->GetFontDict());
 }
 
 CPDF_Font* AddNativeFont(CPDF_Dictionary*& pFormDict,
diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp
index a47595a..5960fc1 100644
--- a/core/fpdfdoc/cpvt_fontmap.cpp
+++ b/core/fpdfdoc/cpvt_fontmap.cpp
@@ -38,10 +38,9 @@
     return;
 
   CPDF_Dictionary* pFontList = pResDict->GetDictFor("Font");
-  if (pFontList && !pFontList->KeyExist(sSysFontAlias)) {
-    pFontList->SetReferenceFor(sSysFontAlias, pDoc,
-                               pPDFFont->GetFontDict()->GetObjNum());
-  }
+  if (pFontList && !pFontList->KeyExist(sSysFontAlias))
+    pFontList->SetReferenceFor(sSysFontAlias, pDoc, pPDFFont->GetFontDict());
+
   pSysFont = pPDFFont;
 }
 
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 28b436a..24827e3 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -58,13 +58,12 @@
 
   CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1));
   if (!pFontDict) {
-    pFontDict = new CPDF_Dictionary(pDoc->GetByteStringPool());
+    pFontDict = pDoc->AddIndirectDictionary(pDoc->GetByteStringPool());
     pFontDict->SetNameFor("Type", "Font");
     pFontDict->SetNameFor("Subtype", "Type1");
     pFontDict->SetNameFor("BaseFont", "Helvetica");
     pFontDict->SetNameFor("Encoding", "WinAnsiEncoding");
-    pDRFontDict->SetReferenceFor(sFontName.Mid(1), pDoc,
-                                 pDoc->AddIndirectObject(pFontDict));
+    pDRFontDict->SetReferenceFor(sFontName.Mid(1), pDoc, pFontDict);
   }
   CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
   if (!pDefFont)
@@ -168,8 +167,8 @@
   }
   CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
   if (!pNormalStream) {
-    pNormalStream = new CPDF_Stream;
-    pAPDict->SetReferenceFor("N", pDoc, pDoc->AddIndirectObject(pNormalStream));
+    pNormalStream = pDoc->AddIndirectStream();
+    pAPDict->SetReferenceFor("N", pDoc, pNormalStream);
   }
   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
   if (pStreamDict) {
@@ -183,8 +182,7 @@
         pStreamResList->SetFor("Font", pStreamResFontList);
       }
       if (!pStreamResFontList->KeyExist(sFontName))
-        pStreamResFontList->SetReferenceFor(sFontName, pDoc,
-                                            pFontDict->GetObjNum());
+        pStreamResFontList->SetReferenceFor(sFontName, pDoc, pFontDict);
     } else {
       pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
       pStreamResList = pStreamDict->GetDictFor("Resources");
@@ -434,8 +432,7 @@
           pStreamResList->SetFor("Font", pStreamResFontList);
         }
         if (!pStreamResFontList->KeyExist(sFontName))
-          pStreamResFontList->SetReferenceFor(sFontName, pDoc,
-                                              pFontDict->GetObjNum());
+          pStreamResFontList->SetReferenceFor(sFontName, pDoc, pFontDict);
       } else {
         pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
         pStreamResList = pStreamDict->GetDictFor("Resources");
@@ -559,7 +556,8 @@
 
 CPDF_Dictionary* GenerateResourceFontDict(CPDF_Document* pDoc,
                                           const CFX_ByteString& sFontDictName) {
-  CPDF_Dictionary* pFontDict = new CPDF_Dictionary(pDoc->GetByteStringPool());
+  CPDF_Dictionary* pFontDict =
+      pDoc->AddIndirectDictionary(pDoc->GetByteStringPool());
   pFontDict->SetNameFor("Type", "Font");
   pFontDict->SetNameFor("Subtype", "Type1");
   pFontDict->SetNameFor("BaseFont", "Helvetica");
@@ -567,8 +565,7 @@
 
   CPDF_Dictionary* pResourceFontDict =
       new CPDF_Dictionary(pDoc->GetByteStringPool());
-  pResourceFontDict->SetReferenceFor(sFontDictName, pDoc,
-                                     pDoc->AddIndirectObject(pFontDict));
+  pResourceFontDict->SetReferenceFor(sFontDictName, pDoc, pFontDict);
   return pResourceFontDict;
 }
 
@@ -596,9 +593,9 @@
   CPDF_Dictionary* pAPDict = new CPDF_Dictionary(pDoc->GetByteStringPool());
   pAnnotDict->SetFor("AP", pAPDict);
 
-  CPDF_Stream* pNormalStream = new CPDF_Stream;
+  CPDF_Stream* pNormalStream = pDoc->AddIndirectStream();
   pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
-  pAPDict->SetReferenceFor("N", pDoc, pDoc->AddIndirectObject(pNormalStream));
+  pAPDict->SetReferenceFor("N", pDoc, pNormalStream);
 
   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
   pStreamDict->SetIntegerFor("FormType", 1);
diff --git a/fpdfsdk/cpdfsdk_baannot.cpp b/fpdfsdk/cpdfsdk_baannot.cpp
index 72468e1..e704822 100644
--- a/fpdfsdk/cpdfsdk_baannot.cpp
+++ b/fpdfsdk/cpdfsdk_baannot.cpp
@@ -316,10 +316,9 @@
   }
 
   if (!pStream) {
-    pStream = new CPDF_Stream;
     CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
-    pParentDict->SetReferenceFor(sAPType, pDoc,
-                                 pDoc->AddIndirectObject(pStream));
+    pStream = pDoc->AddIndirectStream();
+    pParentDict->SetReferenceFor(sAPType, pDoc, pStream);
   }
 
   CPDF_Dictionary* pStreamDict = pStream->GetDict();
@@ -354,8 +353,10 @@
   CPDF_Dictionary* pDict = action.GetDict();
   if (pDict != m_pAnnot->GetAnnotDict()->GetDictFor("A")) {
     CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
-    m_pAnnot->GetAnnotDict()->SetReferenceFor("A", pDoc,
-                                              pDoc->AddIndirectObject(pDict));
+
+    // TODO(tsepez): check |pDict| ownership.
+    m_pAnnot->GetAnnotDict()->SetReferenceFor(
+        "A", pDoc, pDoc->AddIndirectObject(UniqueDictionary(pDict)));
   }
 }
 
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index e1624a0..62bfcf7 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -1811,7 +1811,7 @@
   }
 
   CPDF_Dictionary* pXObject = new CPDF_Dictionary(pDoc->GetByteStringPool());
-  pXObject->SetReferenceFor(sImageAlias, pDoc, pImage->GetObjNum());
+  pXObject->SetReferenceFor(sImageAlias, pDoc, pImage);
   pStreamResList->SetFor("XObject", pXObject);
 }
 
diff --git a/fpdfsdk/formfiller/cba_fontmap.cpp b/fpdfsdk/formfiller/cba_fontmap.cpp
index 7178b90..af518fe 100644
--- a/fpdfsdk/formfiller/cba_fontmap.cpp
+++ b/fpdfsdk/formfiller/cba_fontmap.cpp
@@ -166,9 +166,8 @@
 
   CPDF_Stream* pStream = pAPDict->GetStreamFor(m_sAPType);
   if (!pStream) {
-    pStream = new CPDF_Stream;
-    pAPDict->SetReferenceFor(m_sAPType, m_pDocument,
-                             m_pDocument->AddIndirectObject(pStream));
+    pStream = m_pDocument->AddIndirectStream();
+    pAPDict->SetReferenceFor(m_sAPType, m_pDocument, pStream);
   }
 
   CPDF_Dictionary* pStreamDict = pStream->GetDict();
@@ -186,14 +185,12 @@
     CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
     if (!pStreamResFontList) {
       pStreamResFontList =
-          new CPDF_Dictionary(m_pDocument->GetByteStringPool());
-      pStreamResList->SetReferenceFor(
-          "Font", m_pDocument,
-          m_pDocument->AddIndirectObject(pStreamResFontList));
+          m_pDocument->AddIndirectDictionary(m_pDocument->GetByteStringPool());
+      pStreamResList->SetReferenceFor("Font", m_pDocument, pStreamResFontList);
     }
     if (!pStreamResFontList->KeyExist(sAlias)) {
       pStreamResFontList->SetReferenceFor(sAlias, m_pDocument,
-                                          pFont->GetFontDict()->GetObjNum());
+                                          pFont->GetFontDict());
     }
   }
 }
diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp
index abfc69b..3a11351 100644
--- a/fpdfsdk/fpdf_flatten.cpp
+++ b/fpdfsdk/fpdf_flatten.cpp
@@ -186,12 +186,12 @@
 
 uint32_t NewIndirectContentsStream(const CFX_ByteString& key,
                                    CPDF_Document* pDocument) {
-  CPDF_Stream* pNewContents = new CPDF_Stream(
+  CPDF_Stream* pNewContents = pDocument->AddIndirectStream(
       nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool()));
   CFX_ByteString sStream;
   sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str());
   pNewContents->SetData(sStream.raw_str(), sStream.GetLength());
-  return pDocument->AddIndirectObject(pNewContents);
+  return pNewContents->GetObjNum();
 }
 
 void SetPageContents(const CFX_ByteString& key,
@@ -211,17 +211,15 @@
   }
   pPage->ConvertToIndirectObjectFor("Contents", pDocument);
   if (!pContentsArray) {
-    pContentsArray = new CPDF_Array;
+    pContentsArray = pDocument->AddIndirectArray();
     CPDF_StreamAcc acc;
     acc.LoadAllData(pContentsStream);
     CFX_ByteString sStream = "q\n";
-    CFX_ByteString sBody =
-        CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize());
+    CFX_ByteString sBody = CFX_ByteString(acc.GetData(), acc.GetSize());
     sStream = sStream + sBody + "\nQ";
     pContentsStream->SetData(sStream.raw_str(), sStream.GetLength());
     pContentsArray->AddReference(pDocument, pContentsStream->GetObjNum());
-    pPage->SetReferenceFor("Contents", pDocument,
-                           pDocument->AddIndirectObject(pContentsArray));
+    pPage->SetReferenceFor("Contents", pDocument, pContentsArray);
   }
   if (!key.IsEmpty()) {
     pContentsArray->AddReference(pDocument,
@@ -318,10 +316,10 @@
     pPageDict->SetFor("Resources", pRes);
   }
 
-  CPDF_Stream* pNewXObject = new CPDF_Stream(
+  CPDF_Stream* pNewXObject = pDocument->AddIndirectStream(
       nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool()));
 
-  uint32_t dwObjNum = pDocument->AddIndirectObject(pNewXObject);
+  uint32_t dwObjNum = pNewXObject->GetObjNum();
   CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject");
   if (!pPageXObject) {
     pPageXObject = new CPDF_Dictionary(pDocument->GetByteStringPool());
@@ -426,8 +424,10 @@
 
     CFX_ByteString sFormName;
     sFormName.Format("F%d", i);
+
+    // TODO(tsepez): check |pObj| ownership.
     pXObject->SetReferenceFor(sFormName, pDocument,
-                              pDocument->AddIndirectObject(pObj));
+                              pDocument->AddIndirectObject(UniqueObject(pObj)));
 
     CPDF_StreamAcc acc;
     acc.LoadAllData(pNewXObject);
diff --git a/fpdfsdk/fpdf_transformpage.cpp b/fpdfsdk/fpdf_transformpage.cpp
index 47b6cec..ce09da3 100644
--- a/fpdfsdk/fpdf_transformpage.cpp
+++ b/fpdfsdk/fpdf_transformpage.cpp
@@ -129,15 +129,13 @@
   if (!pDoc)
     return FALSE;
 
-  CPDF_Dictionary* pDic = new CPDF_Dictionary(pDoc->GetByteStringPool());
-  CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic);
+  CPDF_Stream* pStream = pDoc->AddIndirectStream(
+      nullptr, 0, new CPDF_Dictionary(pDoc->GetByteStringPool()));
   pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize());
-  pDoc->AddIndirectObject(pStream);
-  pDic = new CPDF_Dictionary(pDoc->GetByteStringPool());
 
-  CPDF_Stream* pEndStream = new CPDF_Stream(nullptr, 0, pDic);
+  CPDF_Stream* pEndStream = pDoc->AddIndirectStream(
+      nullptr, 0, new CPDF_Dictionary(pDoc->GetByteStringPool()));
   pEndStream->SetData((const uint8_t*)" Q", 2);
-  pDoc->AddIndirectObject(pEndStream);
 
   CPDF_Array* pContentArray = nullptr;
   CPDF_Array* pArray = ToArray(pContentObj);
@@ -156,12 +154,11 @@
         pContentArray->InsertAt(0, pRef);
         pContentArray->AddReference(pDoc, pEndStream->GetObjNum());
       } else if (pDirectObj->IsStream()) {
-        pContentArray = new CPDF_Array();
+        pContentArray = pDoc->AddIndirectArray();
         pContentArray->AddReference(pDoc, pStream->GetObjNum());
         pContentArray->AddReference(pDoc, pDirectObj->GetObjNum());
         pContentArray->AddReference(pDoc, pEndStream->GetObjNum());
-        pPageDic->SetReferenceFor("Contents", pDoc,
-                                  pDoc->AddIndirectObject(pContentArray));
+        pPageDic->SetReferenceFor("Contents", pDoc, pContentArray);
       }
     }
   }
@@ -305,10 +302,9 @@
   if (!pDoc)
     return;
 
-  CPDF_Dictionary* pDic = new CPDF_Dictionary(pDoc->GetByteStringPool());
-  CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic);
+  CPDF_Stream* pStream = pDoc->AddIndirectStream(
+      nullptr, 0, new CPDF_Dictionary(pDoc->GetByteStringPool()));
   pStream->SetData(strClip.GetBuffer(), strClip.GetSize());
-  pDoc->AddIndirectObject(pStream);
 
   CPDF_Array* pContentArray = nullptr;
   CPDF_Array* pArray = ToArray(pContentObj);
@@ -325,11 +321,10 @@
         CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
         pContentArray->InsertAt(0, pRef);
       } else if (pDirectObj->IsStream()) {
-        pContentArray = new CPDF_Array();
-        pContentArray->AddReference(pDoc, pStream->GetObjNum());
-        pContentArray->AddReference(pDoc, pDirectObj->GetObjNum());
-        pPageDic->SetReferenceFor("Contents", pDoc,
-                                  pDoc->AddIndirectObject(pContentArray));
+        pContentArray = pDoc->AddIndirectArray();
+        pContentArray->AddReference(pDoc, pStream);
+        pContentArray->AddReference(pDoc, pDirectObj);
+        pPageDic->SetReferenceFor("Contents", pDoc, pContentArray);
       }
     }
   }
diff --git a/fpdfsdk/fpdfdoc_unittest.cpp b/fpdfsdk/fpdfdoc_unittest.cpp
index fc85404..40457ee 100644
--- a/fpdfsdk/fpdfdoc_unittest.cpp
+++ b/fpdfsdk/fpdfdoc_unittest.cpp
@@ -80,8 +80,8 @@
     std::vector<DictObjInfo> info;
     for (int i = 0; i < num; ++i) {
       // Objects created will be released by the document.
-      CPDF_Dictionary* obj = new CPDF_Dictionary();
-      info.push_back({m_pIndirectObjs->AddIndirectObject(obj), obj});
+      CPDF_Dictionary* obj = m_pIndirectObjs->AddIndirectDictionary();
+      info.push_back({obj->GetObjNum(), obj});
     }
     return info;
   }
diff --git a/fpdfsdk/fpdfppo.cpp b/fpdfsdk/fpdfppo.cpp
index 8a46ea4..023c41a 100644
--- a/fpdfsdk/fpdfppo.cpp
+++ b/fpdfsdk/fpdfppo.cpp
@@ -70,9 +70,9 @@
   CPDF_Dictionary* pNewPages =
       pElement ? ToDictionary(pElement->GetDirect()) : nullptr;
   if (!pNewPages) {
-    pNewPages = new CPDF_Dictionary(pDestPDFDoc->GetByteStringPool());
-    pNewRoot->SetReferenceFor("Pages", pDestPDFDoc,
-                              pDestPDFDoc->AddIndirectObject(pNewPages));
+    pNewPages =
+        pDestPDFDoc->AddIndirectDictionary(pDestPDFDoc->GetByteStringPool());
+    pNewRoot->SetReferenceFor("Pages", pDestPDFDoc, pNewPages);
   }
 
   CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", "");
@@ -83,7 +83,7 @@
   if (!pNewPages->GetArrayFor("Kids")) {
     pNewPages->SetIntegerFor("Count", 0);
     pNewPages->SetReferenceFor("Kids", pDestPDFDoc,
-                               pDestPDFDoc->AddIndirectObject(new CPDF_Array));
+                               pDestPDFDoc->AddIndirectArray());
   }
 
   return TRUE;
@@ -277,7 +277,7 @@
   if (!pDirect)
     return 0;
 
-  CPDF_Object* pClone = pDirect->Clone();
+  UniqueObject pClone(pDirect->Clone());
   if (!pClone)
     return 0;
 
@@ -294,10 +294,11 @@
       }
     }
   }
-  dwNewObjNum = pDoc->AddIndirectObject(pClone);
+  CPDF_Object* pUnowned = pDoc->AddIndirectObject(std::move(pClone));
+  dwNewObjNum = pUnowned->GetObjNum();
   (*pObjNumberMap)[dwObjnum] = dwNewObjNum;
-  if (!UpdateReference(pClone, pDoc, pObjNumberMap)) {
-    pClone->Release();
+  if (!UpdateReference(pUnowned, pDoc, pObjNumberMap)) {
+    pDoc->DeleteIndirectObject(dwNewObjNum);
     return 0;
   }
   return dwNewObjNum;
diff --git a/fpdfsdk/fpdfsave.cpp b/fpdfsdk/fpdfsave.cpp
index 364f4d2..b594084 100644
--- a/fpdfsdk/fpdfsave.cpp
+++ b/fpdfsdk/fpdfsave.cpp
@@ -184,14 +184,12 @@
         if (pDataSetsStream)
           pDataSetsStream->InitStreamFromFile(pDsfileWrite.get(), pDataDict);
       } else {
-        CPDF_Stream* pData = new CPDF_Stream;
+        CPDF_Stream* pData = pPDFDocument->AddIndirectStream();
         pData->InitStreamFromFile(pDsfileWrite.get(), pDataDict);
         iLast = pArray->GetCount() - 2;
-        pArray->InsertAt(iLast, new CPDF_String("datasets", FALSE));
-        pArray->InsertAt(
-            iLast + 1,
-            new CPDF_Reference(pPDFDocument,
-                               pPDFDocument->AddIndirectObject(pData)));
+        pArray->InsertAt(iLast, new CPDF_String("datasets", false));
+        pArray->InsertAt(iLast + 1,
+                         new CPDF_Reference(pPDFDocument, pData->GetObjNum()));
       }
       fileList->push_back(std::move(pDsfileWrite));
     }
@@ -208,14 +206,12 @@
         if (pFormStream)
           pFormStream->InitStreamFromFile(pfileWrite.get(), pDataDict);
       } else {
-        CPDF_Stream* pData = new CPDF_Stream;
+        CPDF_Stream* pData = pPDFDocument->AddIndirectStream();
         pData->InitStreamFromFile(pfileWrite.get(), pDataDict);
         iLast = pArray->GetCount() - 2;
         pArray->InsertAt(iLast, new CPDF_String("form", FALSE));
-        pArray->InsertAt(
-            iLast + 1,
-            new CPDF_Reference(pPDFDocument,
-                               pPDFDocument->AddIndirectObject(pData)));
+        pArray->InsertAt(iLast + 1,
+                         new CPDF_Reference(pPDFDocument, pData->GetObjNum()));
       }
       fileList->push_back(std::move(pfileWrite));
     }