Remove NoDestructor usage in CPDF_StreamContentParser

Add static methods to initialize/destroy CPDF_StreamContentParser when
the page module is initialized/destroyed. This lets
FPDF_DestroyLibrary() free more memory and work as it was originally
intended.

Bug: pdfium:1876
Change-Id: I7b378abc610a13c22b0fb370b360b3b766205e29
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/112418
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_pagemodule.cpp b/core/fpdfapi/page/cpdf_pagemodule.cpp
index 3ef0f8f..f606c28 100644
--- a/core/fpdfapi/page/cpdf_pagemodule.cpp
+++ b/core/fpdfapi/page/cpdf_pagemodule.cpp
@@ -8,16 +8,19 @@
 
 #include "core/fpdfapi/font/cpdf_fontglobals.h"
 #include "core/fpdfapi/page/cpdf_colorspace.h"
+#include "core/fpdfapi/page/cpdf_streamcontentparser.h"
 
 // static
 void CPDF_PageModule::Create() {
   CPDF_ColorSpace::InitializeGlobals();
   CPDF_FontGlobals::Create();
   CPDF_FontGlobals::GetInstance()->LoadEmbeddedMaps();
+  CPDF_StreamContentParser::InitializeGlobals();
 }
 
 // static
 void CPDF_PageModule::Destroy() {
+  CPDF_StreamContentParser::DestroyGlobals();
   CPDF_FontGlobals::Destroy();
   CPDF_ColorSpace::DestroyGlobals();
 }
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index ad36283..7078804 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfapi/page/cpdf_streamcontentparser.h"
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -44,7 +45,6 @@
 #include "third_party/base/check.h"
 #include "third_party/base/containers/contains.h"
 #include "third_party/base/containers/span.h"
-#include "third_party/base/no_destructor.h"
 #include "third_party/base/notreached.h"
 
 namespace {
@@ -68,6 +68,9 @@
 const char kPathOperatorClosePath = 'h';
 const char kPathOperatorRectangle[] = "re";
 
+using OpCodes = std::map<uint32_t, void (CPDF_StreamContentParser::*)()>;
+OpCodes* g_opcodes = nullptr;
+
 CFX_FloatRect GetShadingBBox(CPDF_ShadingPattern* pShading,
                              const CFX_Matrix& matrix) {
   ShadingType type = pShading->GetShadingType();
@@ -244,6 +247,133 @@
 
 }  // namespace
 
+// static
+void CPDF_StreamContentParser::InitializeGlobals() {
+  CHECK(!g_opcodes);
+  g_opcodes = new OpCodes({
+      {FXBSTR_ID('"', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_NextLineShowText_Space},
+      {FXBSTR_ID('\'', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_NextLineShowText},
+      {FXBSTR_ID('B', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_FillStrokePath},
+      {FXBSTR_ID('B', '*', 0, 0),
+       &CPDF_StreamContentParser::Handle_EOFillStrokePath},
+      {FXBSTR_ID('B', 'D', 'C', 0),
+       &CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary},
+      {FXBSTR_ID('B', 'I', 0, 0), &CPDF_StreamContentParser::Handle_BeginImage},
+      {FXBSTR_ID('B', 'M', 'C', 0),
+       &CPDF_StreamContentParser::Handle_BeginMarkedContent},
+      {FXBSTR_ID('B', 'T', 0, 0), &CPDF_StreamContentParser::Handle_BeginText},
+      {FXBSTR_ID('C', 'S', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetColorSpace_Stroke},
+      {FXBSTR_ID('D', 'P', 0, 0),
+       &CPDF_StreamContentParser::Handle_MarkPlace_Dictionary},
+      {FXBSTR_ID('D', 'o', 0, 0),
+       &CPDF_StreamContentParser::Handle_ExecuteXObject},
+      {FXBSTR_ID('E', 'I', 0, 0), &CPDF_StreamContentParser::Handle_EndImage},
+      {FXBSTR_ID('E', 'M', 'C', 0),
+       &CPDF_StreamContentParser::Handle_EndMarkedContent},
+      {FXBSTR_ID('E', 'T', 0, 0), &CPDF_StreamContentParser::Handle_EndText},
+      {FXBSTR_ID('F', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPathOld},
+      {FXBSTR_ID('G', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_SetGray_Stroke},
+      {FXBSTR_ID('I', 'D', 0, 0),
+       &CPDF_StreamContentParser::Handle_BeginImageData},
+      {FXBSTR_ID('J', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineCap},
+      {FXBSTR_ID('K', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke},
+      {FXBSTR_ID('M', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_SetMiterLimit},
+      {FXBSTR_ID('M', 'P', 0, 0), &CPDF_StreamContentParser::Handle_MarkPlace},
+      {FXBSTR_ID('Q', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_RestoreGraphState},
+      {FXBSTR_ID('R', 'G', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetRGBColor_Stroke},
+      {FXBSTR_ID('S', 0, 0, 0), &CPDF_StreamContentParser::Handle_StrokePath},
+      {FXBSTR_ID('S', 'C', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetColor_Stroke},
+      {FXBSTR_ID('S', 'C', 'N', 0),
+       &CPDF_StreamContentParser::Handle_SetColorPS_Stroke},
+      {FXBSTR_ID('T', '*', 0, 0),
+       &CPDF_StreamContentParser::Handle_MoveToNextLine},
+      {FXBSTR_ID('T', 'D', 0, 0),
+       &CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading},
+      {FXBSTR_ID('T', 'J', 0, 0),
+       &CPDF_StreamContentParser::Handle_ShowText_Positioning},
+      {FXBSTR_ID('T', 'L', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetTextLeading},
+      {FXBSTR_ID('T', 'c', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetCharSpace},
+      {FXBSTR_ID('T', 'd', 0, 0),
+       &CPDF_StreamContentParser::Handle_MoveTextPoint},
+      {FXBSTR_ID('T', 'f', 0, 0), &CPDF_StreamContentParser::Handle_SetFont},
+      {FXBSTR_ID('T', 'j', 0, 0), &CPDF_StreamContentParser::Handle_ShowText},
+      {FXBSTR_ID('T', 'm', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetTextMatrix},
+      {FXBSTR_ID('T', 'r', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetTextRenderMode},
+      {FXBSTR_ID('T', 's', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetTextRise},
+      {FXBSTR_ID('T', 'w', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetWordSpace},
+      {FXBSTR_ID('T', 'z', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetHorzScale},
+      {FXBSTR_ID('W', 0, 0, 0), &CPDF_StreamContentParser::Handle_Clip},
+      {FXBSTR_ID('W', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOClip},
+      {FXBSTR_ID('b', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_CloseFillStrokePath},
+      {FXBSTR_ID('b', '*', 0, 0),
+       &CPDF_StreamContentParser::Handle_CloseEOFillStrokePath},
+      {FXBSTR_ID('c', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_123},
+      {FXBSTR_ID('c', 'm', 0, 0),
+       &CPDF_StreamContentParser::Handle_ConcatMatrix},
+      {FXBSTR_ID('c', 's', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetColorSpace_Fill},
+      {FXBSTR_ID('d', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetDash},
+      {FXBSTR_ID('d', '0', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetCharWidth},
+      {FXBSTR_ID('d', '1', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetCachedDevice},
+      {FXBSTR_ID('f', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPath},
+      {FXBSTR_ID('f', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOFillPath},
+      {FXBSTR_ID('g', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetGray_Fill},
+      {FXBSTR_ID('g', 's', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetExtendGraphState},
+      {FXBSTR_ID('h', 0, 0, 0), &CPDF_StreamContentParser::Handle_ClosePath},
+      {FXBSTR_ID('i', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetFlat},
+      {FXBSTR_ID('j', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineJoin},
+      {FXBSTR_ID('k', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_SetCMYKColor_Fill},
+      {FXBSTR_ID('l', 0, 0, 0), &CPDF_StreamContentParser::Handle_LineTo},
+      {FXBSTR_ID('m', 0, 0, 0), &CPDF_StreamContentParser::Handle_MoveTo},
+      {FXBSTR_ID('n', 0, 0, 0), &CPDF_StreamContentParser::Handle_EndPath},
+      {FXBSTR_ID('q', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_SaveGraphState},
+      {FXBSTR_ID('r', 'e', 0, 0), &CPDF_StreamContentParser::Handle_Rectangle},
+      {FXBSTR_ID('r', 'g', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetRGBColor_Fill},
+      {FXBSTR_ID('r', 'i', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetRenderIntent},
+      {FXBSTR_ID('s', 0, 0, 0),
+       &CPDF_StreamContentParser::Handle_CloseStrokePath},
+      {FXBSTR_ID('s', 'c', 0, 0),
+       &CPDF_StreamContentParser::Handle_SetColor_Fill},
+      {FXBSTR_ID('s', 'c', 'n', 0),
+       &CPDF_StreamContentParser::Handle_SetColorPS_Fill},
+      {FXBSTR_ID('s', 'h', 0, 0), &CPDF_StreamContentParser::Handle_ShadeFill},
+      {FXBSTR_ID('v', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_23},
+      {FXBSTR_ID('w', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineWidth},
+      {FXBSTR_ID('y', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_13},
+  });
+}
+
+// static
+void CPDF_StreamContentParser::DestroyGlobals() {
+  delete g_opcodes;
+  g_opcodes = nullptr;
+}
+
 CPDF_StreamContentParser::CPDF_StreamContentParser(
     CPDF_Document* pDocument,
     RetainPtr<CPDF_Dictionary> pPageResources,
@@ -431,134 +561,11 @@
   }
 }
 
-// static
-CPDF_StreamContentParser::OpCodes
-CPDF_StreamContentParser::InitializeOpCodes() {
-  return OpCodes({
-      {FXBSTR_ID('"', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_NextLineShowText_Space},
-      {FXBSTR_ID('\'', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_NextLineShowText},
-      {FXBSTR_ID('B', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_FillStrokePath},
-      {FXBSTR_ID('B', '*', 0, 0),
-       &CPDF_StreamContentParser::Handle_EOFillStrokePath},
-      {FXBSTR_ID('B', 'D', 'C', 0),
-       &CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary},
-      {FXBSTR_ID('B', 'I', 0, 0), &CPDF_StreamContentParser::Handle_BeginImage},
-      {FXBSTR_ID('B', 'M', 'C', 0),
-       &CPDF_StreamContentParser::Handle_BeginMarkedContent},
-      {FXBSTR_ID('B', 'T', 0, 0), &CPDF_StreamContentParser::Handle_BeginText},
-      {FXBSTR_ID('C', 'S', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetColorSpace_Stroke},
-      {FXBSTR_ID('D', 'P', 0, 0),
-       &CPDF_StreamContentParser::Handle_MarkPlace_Dictionary},
-      {FXBSTR_ID('D', 'o', 0, 0),
-       &CPDF_StreamContentParser::Handle_ExecuteXObject},
-      {FXBSTR_ID('E', 'I', 0, 0), &CPDF_StreamContentParser::Handle_EndImage},
-      {FXBSTR_ID('E', 'M', 'C', 0),
-       &CPDF_StreamContentParser::Handle_EndMarkedContent},
-      {FXBSTR_ID('E', 'T', 0, 0), &CPDF_StreamContentParser::Handle_EndText},
-      {FXBSTR_ID('F', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPathOld},
-      {FXBSTR_ID('G', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_SetGray_Stroke},
-      {FXBSTR_ID('I', 'D', 0, 0),
-       &CPDF_StreamContentParser::Handle_BeginImageData},
-      {FXBSTR_ID('J', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineCap},
-      {FXBSTR_ID('K', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke},
-      {FXBSTR_ID('M', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_SetMiterLimit},
-      {FXBSTR_ID('M', 'P', 0, 0), &CPDF_StreamContentParser::Handle_MarkPlace},
-      {FXBSTR_ID('Q', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_RestoreGraphState},
-      {FXBSTR_ID('R', 'G', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetRGBColor_Stroke},
-      {FXBSTR_ID('S', 0, 0, 0), &CPDF_StreamContentParser::Handle_StrokePath},
-      {FXBSTR_ID('S', 'C', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetColor_Stroke},
-      {FXBSTR_ID('S', 'C', 'N', 0),
-       &CPDF_StreamContentParser::Handle_SetColorPS_Stroke},
-      {FXBSTR_ID('T', '*', 0, 0),
-       &CPDF_StreamContentParser::Handle_MoveToNextLine},
-      {FXBSTR_ID('T', 'D', 0, 0),
-       &CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading},
-      {FXBSTR_ID('T', 'J', 0, 0),
-       &CPDF_StreamContentParser::Handle_ShowText_Positioning},
-      {FXBSTR_ID('T', 'L', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetTextLeading},
-      {FXBSTR_ID('T', 'c', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetCharSpace},
-      {FXBSTR_ID('T', 'd', 0, 0),
-       &CPDF_StreamContentParser::Handle_MoveTextPoint},
-      {FXBSTR_ID('T', 'f', 0, 0), &CPDF_StreamContentParser::Handle_SetFont},
-      {FXBSTR_ID('T', 'j', 0, 0), &CPDF_StreamContentParser::Handle_ShowText},
-      {FXBSTR_ID('T', 'm', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetTextMatrix},
-      {FXBSTR_ID('T', 'r', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetTextRenderMode},
-      {FXBSTR_ID('T', 's', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetTextRise},
-      {FXBSTR_ID('T', 'w', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetWordSpace},
-      {FXBSTR_ID('T', 'z', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetHorzScale},
-      {FXBSTR_ID('W', 0, 0, 0), &CPDF_StreamContentParser::Handle_Clip},
-      {FXBSTR_ID('W', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOClip},
-      {FXBSTR_ID('b', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_CloseFillStrokePath},
-      {FXBSTR_ID('b', '*', 0, 0),
-       &CPDF_StreamContentParser::Handle_CloseEOFillStrokePath},
-      {FXBSTR_ID('c', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_123},
-      {FXBSTR_ID('c', 'm', 0, 0),
-       &CPDF_StreamContentParser::Handle_ConcatMatrix},
-      {FXBSTR_ID('c', 's', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetColorSpace_Fill},
-      {FXBSTR_ID('d', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetDash},
-      {FXBSTR_ID('d', '0', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetCharWidth},
-      {FXBSTR_ID('d', '1', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetCachedDevice},
-      {FXBSTR_ID('f', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPath},
-      {FXBSTR_ID('f', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOFillPath},
-      {FXBSTR_ID('g', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetGray_Fill},
-      {FXBSTR_ID('g', 's', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetExtendGraphState},
-      {FXBSTR_ID('h', 0, 0, 0), &CPDF_StreamContentParser::Handle_ClosePath},
-      {FXBSTR_ID('i', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetFlat},
-      {FXBSTR_ID('j', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineJoin},
-      {FXBSTR_ID('k', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_SetCMYKColor_Fill},
-      {FXBSTR_ID('l', 0, 0, 0), &CPDF_StreamContentParser::Handle_LineTo},
-      {FXBSTR_ID('m', 0, 0, 0), &CPDF_StreamContentParser::Handle_MoveTo},
-      {FXBSTR_ID('n', 0, 0, 0), &CPDF_StreamContentParser::Handle_EndPath},
-      {FXBSTR_ID('q', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_SaveGraphState},
-      {FXBSTR_ID('r', 'e', 0, 0), &CPDF_StreamContentParser::Handle_Rectangle},
-      {FXBSTR_ID('r', 'g', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetRGBColor_Fill},
-      {FXBSTR_ID('r', 'i', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetRenderIntent},
-      {FXBSTR_ID('s', 0, 0, 0),
-       &CPDF_StreamContentParser::Handle_CloseStrokePath},
-      {FXBSTR_ID('s', 'c', 0, 0),
-       &CPDF_StreamContentParser::Handle_SetColor_Fill},
-      {FXBSTR_ID('s', 'c', 'n', 0),
-       &CPDF_StreamContentParser::Handle_SetColorPS_Fill},
-      {FXBSTR_ID('s', 'h', 0, 0), &CPDF_StreamContentParser::Handle_ShadeFill},
-      {FXBSTR_ID('v', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_23},
-      {FXBSTR_ID('w', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineWidth},
-      {FXBSTR_ID('y', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_13},
-  });
-}
-
 void CPDF_StreamContentParser::OnOperator(ByteStringView op) {
-  static const pdfium::base::NoDestructor<OpCodes> s_OpCodes(
-      InitializeOpCodes());
-
-  auto it = s_OpCodes->find(op.GetID());
-  if (it != s_OpCodes->end())
+  auto it = g_opcodes->find(op.GetID());
+  if (it != g_opcodes->end()) {
     (this->*it->second)();
+  }
 }
 
 void CPDF_StreamContentParser::Handle_CloseFillStrokePath() {
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h
index c31dd15..28ede19 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.h
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.h
@@ -7,7 +7,6 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_STREAMCONTENTPARSER_H_
 #define CORE_FPDFAPI_PAGE_CPDF_STREAMCONTENTPARSER_H_
 
-#include <map>
 #include <memory>
 #include <stack>
 #include <vector>
@@ -41,6 +40,9 @@
 
 class CPDF_StreamContentParser {
  public:
+  static void InitializeGlobals();
+  static void DestroyGlobals();
+
   CPDF_StreamContentParser(CPDF_Document* pDoc,
                            RetainPtr<CPDF_Dictionary> pPageResources,
                            RetainPtr<CPDF_Dictionary> pParentResources,
@@ -82,9 +84,6 @@
 
   static constexpr int kParamBufSize = 16;
 
-  using OpCodes = std::map<uint32_t, void (CPDF_StreamContentParser::*)()>;
-  static OpCodes InitializeOpCodes();
-
   void AddNameParam(ByteStringView bsName);
   void AddNumberParam(ByteStringView str);
   void AddObjectParam(RetainPtr<CPDF_Object> pObj);