Introduce CFGAS_GEGraphics::StateRestorer

-- Add NOTREACHED() to ensure all restores are matched.
-- Leave one problem case where manual operations required.

Change-Id: Iaf8561ff6219156b337cd09d81ae16ca3d47d8bd
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/96510
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fgas/graphics/cfgas_gegraphics.cpp b/xfa/fgas/graphics/cfgas_gegraphics.cpp
index 57326f8..1354b0d 100644
--- a/xfa/fgas/graphics/cfgas_gegraphics.cpp
+++ b/xfa/fgas/graphics/cfgas_gegraphics.cpp
@@ -18,6 +18,7 @@
 #include "core/fxge/cfx_unicodeencoding.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
 #include "third_party/base/check.h"
+#include "third_party/base/notreached.h"
 #include "xfa/fgas/graphics/cfgas_gecolor.h"
 #include "xfa/fgas/graphics/cfgas_gepath.h"
 #include "xfa/fgas/graphics/cfgas_gepattern.h"
@@ -127,9 +128,10 @@
 
 void CFGAS_GEGraphics::RestoreGraphState() {
   m_renderDevice->RestoreState(false);
-  if (m_infoStack.empty())
+  if (m_infoStack.empty()) {
+    NOTREACHED();
     return;
-
+  }
   m_info = *m_infoStack.back();
   m_infoStack.pop_back();
   return;
@@ -431,3 +433,12 @@
   fillColor = other.fillColor;
   return *this;
 }
+
+CFGAS_GEGraphics::StateRestorer::StateRestorer(CFGAS_GEGraphics* graphics)
+    : graphics_(graphics) {
+  graphics_->SaveGraphState();
+}
+
+CFGAS_GEGraphics::StateRestorer::~StateRestorer() {
+  graphics_->RestoreGraphState();
+}
diff --git a/xfa/fgas/graphics/cfgas_gegraphics.h b/xfa/fgas/graphics/cfgas_gegraphics.h
index f21255c..4a28ffd 100644
--- a/xfa/fgas/graphics/cfgas_gegraphics.h
+++ b/xfa/fgas/graphics/cfgas_gegraphics.h
@@ -11,7 +11,9 @@
 #include <vector>
 
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "core/fxge/cfx_fillrenderoptions.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "third_party/base/span.h"
@@ -23,6 +25,17 @@
 
 class CFGAS_GEGraphics {
  public:
+  class StateRestorer {
+   public:
+    FX_STACK_ALLOCATED();
+
+    explicit StateRestorer(CFGAS_GEGraphics* graphics);
+    ~StateRestorer();
+
+   private:
+    UnownedPtr<CFGAS_GEGraphics> const graphics_;
+  };
+
   explicit CFGAS_GEGraphics(CFX_RenderDevice* renderDevice);
   ~CFGAS_GEGraphics();
 
diff --git a/xfa/fwl/cfwl_combobox.cpp b/xfa/fwl/cfwl_combobox.cpp
index 541dc9b..4f90aee 100644
--- a/xfa/fwl/cfwl_combobox.cpp
+++ b/xfa/fwl/cfwl_combobox.cpp
@@ -103,17 +103,17 @@
 
 void CFWL_ComboBox::DrawWidget(CFGAS_GEGraphics* pGraphics,
                                const CFX_Matrix& matrix) {
-  pGraphics->SaveGraphState();
-  pGraphics->ConcatMatrix(matrix);
-  if (!m_BtnRect.IsEmpty(0.1f)) {
-    CFWL_ThemeBackground param(this, pGraphics);
-    param.m_iPart = CFWL_ThemePart::Part::kDropDownButton;
-    param.m_dwStates = m_iBtnState;
-    param.m_PartRect = m_BtnRect;
-    GetThemeProvider()->DrawBackground(param);
+  {
+    CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
+    pGraphics->ConcatMatrix(matrix);
+    if (!m_BtnRect.IsEmpty(0.1f)) {
+      CFWL_ThemeBackground param(this, pGraphics);
+      param.m_iPart = CFWL_ThemePart::Part::kDropDownButton;
+      param.m_dwStates = m_iBtnState;
+      param.m_PartRect = m_BtnRect;
+      GetThemeProvider()->DrawBackground(param);
+    }
   }
-  pGraphics->RestoreGraphState();
-
   if (m_pEdit) {
     CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
     CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index 06bb3cd..7c101dc 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -311,7 +311,7 @@
 
 void CFWL_Edit::DrawContent(CFGAS_GEGraphics* pGraphics,
                             const CFX_Matrix& mtMatrix) {
-  pGraphics->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_CombText)
     pGraphics->SaveGraphState();
 
@@ -369,7 +369,6 @@
     param.SetPath(&path);
     GetThemeProvider()->DrawBackground(param);
   }
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_Edit::RenderText(CFX_RenderDevice* pRenderDev,
diff --git a/xfa/fwl/cfwl_listbox.cpp b/xfa/fwl/cfwl_listbox.cpp
index c7aaa44..ce2ddff 100644
--- a/xfa/fwl/cfwl_listbox.cpp
+++ b/xfa/fwl/cfwl_listbox.cpp
@@ -91,7 +91,7 @@
   if (!pGraphics)
     return;
 
-  pGraphics->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_ThemePart::Part::kBorder, matrix);
 
@@ -106,7 +106,6 @@
     DrawBkground(pGraphics, matrix);
 
   DrawItems(pGraphics, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 int32_t CFWL_ListBox::CountSelItems() {
diff --git a/xfa/fwl/theme/cfwl_checkboxtp.cpp b/xfa/fwl/theme/cfwl_checkboxtp.cpp
index 3753c30..cee86f7 100644
--- a/xfa/fwl/theme/cfwl_checkboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_checkboxtp.cpp
@@ -55,11 +55,11 @@
   CFX_Matrix mt;
   mt.Translate(rtSign.left, rtSign.top);
   mt.Concat(matrix);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(argbFill));
   pGraphics->FillPath(*m_pCheckPath, CFX_FillRenderOptions::FillType::kWinding,
                       mt);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignCircle(CFGAS_GEGraphics* pGraphics,
@@ -68,10 +68,10 @@
                                      const CFX_Matrix& matrix) {
   CFGAS_GEPath path;
   path.AddEllipse(rtSign);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(argbFill));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignCross(CFGAS_GEGraphics* pGraphics,
@@ -79,17 +79,16 @@
                                     FX_ARGB argbFill,
                                     const CFX_Matrix& matrix) {
   CFGAS_GEPath path;
-  float fRight = rtSign.right();
-  float fBottom = rtSign.bottom();
+  const float fRight = rtSign.right();
+  const float fBottom = rtSign.bottom();
   path.AddLine(rtSign.TopLeft(), CFX_PointF(fRight, fBottom));
   path.AddLine(CFX_PointF(rtSign.left, fBottom),
                CFX_PointF(fRight, rtSign.top));
 
-  pGraphics->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetStrokeColor(CFGAS_GEColor(argbFill));
   pGraphics->SetLineWidth(1.0f);
   pGraphics->StrokePath(path, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignDiamond(CFGAS_GEGraphics* pGraphics,
@@ -97,19 +96,18 @@
                                       FX_ARGB argbFill,
                                       const CFX_Matrix& matrix) {
   CFGAS_GEPath path;
-  float fWidth = rtSign.width;
-  float fHeight = rtSign.height;
-  float fBottom = rtSign.bottom();
+  const float fWidth = rtSign.width;
+  const float fHeight = rtSign.height;
+  const float fBottom = rtSign.bottom();
   path.MoveTo(CFX_PointF(rtSign.left + fWidth / 2, rtSign.top));
   path.LineTo(CFX_PointF(rtSign.left, rtSign.top + fHeight / 2));
   path.LineTo(CFX_PointF(rtSign.left + fWidth / 2, fBottom));
   path.LineTo(CFX_PointF(rtSign.right(), rtSign.top + fHeight / 2));
   path.LineTo(CFX_PointF(rtSign.left + fWidth / 2, rtSign.top));
 
-  pGraphics->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(argbFill));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignSquare(CFGAS_GEGraphics* pGraphics,
@@ -118,10 +116,10 @@
                                      const CFX_Matrix& matrix) {
   CFGAS_GEPath path;
   path.AddRectangle(rtSign.left, rtSign.top, rtSign.width, rtSign.height);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(argbFill));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignStar(CFGAS_GEGraphics* pGraphics,
@@ -148,10 +146,10 @@
     next = (next + 2) % std::size(points);
     path.LineTo(points[next]);
   }
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(argbFill));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::EnsureCheckPathInitialized(float fCheckLen) {
diff --git a/xfa/fwl/theme/cfwl_comboboxtp.cpp b/xfa/fwl/theme/cfwl_comboboxtp.cpp
index e04fb77..65f8f19 100644
--- a/xfa/fwl/theme/cfwl_comboboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_comboboxtp.cpp
@@ -35,11 +35,10 @@
       else
         argb_color = 0xFFFFFFFF;
 
-      pParams.GetGraphics()->SaveGraphState();
+      CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
       pParams.GetGraphics()->SetFillColor(CFGAS_GEColor(argb_color));
       pParams.GetGraphics()->FillPath(
           path, CFX_FillRenderOptions::FillType::kWinding, pParams.m_matrix);
-      pParams.GetGraphics()->RestoreGraphState();
       break;
     }
     case CFWL_ThemePart::Part::kDropDownButton: {
diff --git a/xfa/fwl/theme/cfwl_edittp.cpp b/xfa/fwl/theme/cfwl_edittp.cpp
index b4e0de6..22b2597 100644
--- a/xfa/fwl/theme/cfwl_edittp.cpp
+++ b/xfa/fwl/theme/cfwl_edittp.cpp
@@ -27,12 +27,11 @@
       const CFGAS_GEPath* pParamsPath = pParams.GetPath();
       if (pParamsPath) {
         CFGAS_GEGraphics* pGraphics = pParams.GetGraphics();
-        pGraphics->SaveGraphState();
+        CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
         pGraphics->SetFillColor(CFGAS_GEColor(FWLTHEME_COLOR_BKSelected));
         pGraphics->FillPath(*pParamsPath,
                             CFX_FillRenderOptions::FillType::kWinding,
                             pParams.m_matrix);
-        pGraphics->RestoreGraphState();
       } else {
         CFGAS_GEPath path;
         path.AddRectangle(pParams.m_PartRect.left, pParams.m_PartRect.top,
@@ -46,11 +45,10 @@
           else
             cr = CFGAS_GEColor(0xFFFFFFFF);
         }
-        pParams.GetGraphics()->SaveGraphState();
+        CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
         pParams.GetGraphics()->SetFillColor(cr);
         pParams.GetGraphics()->FillPath(
             path, CFX_FillRenderOptions::FillType::kWinding, pParams.m_matrix);
-        pParams.GetGraphics()->RestoreGraphState();
       }
       break;
     }
diff --git a/xfa/fwl/theme/cfwl_listboxtp.cpp b/xfa/fwl/theme/cfwl_listboxtp.cpp
index 39961df..d0ed06f 100644
--- a/xfa/fwl/theme/cfwl_listboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_listboxtp.cpp
@@ -60,7 +60,7 @@
                                      const CFX_RectF* pData,
                                      const CFX_Matrix& matrix) {
   if (dwStates & CFWL_PartState::kSelected) {
-    pGraphics->SaveGraphState();
+    CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
     pGraphics->SetFillColor(CFGAS_GEColor(FWLTHEME_COLOR_BKSelected));
     CFGAS_GEPath path;
 #if BUILDFLAG(IS_APPLE)
@@ -71,7 +71,6 @@
 #endif
     pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding,
                         matrix);
-    pGraphics->RestoreGraphState();
   }
   if ((dwStates & CFWL_PartState::kFocused) && pData)
     DrawFocus(pGraphics, *pData, matrix);
diff --git a/xfa/fwl/theme/cfwl_monthcalendartp.cpp b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
index 8ffc33e..d04976f 100644
--- a/xfa/fwl/theme/cfwl_monthcalendartp.cpp
+++ b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
@@ -103,11 +103,11 @@
   CFGAS_GEPath path;
   CFX_RectF rtTotal(pParams.m_PartRect);
   path.AddRectangle(rtTotal.left, rtTotal.top, rtTotal.width, rtTotal.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetFillColor(CFGAS_GEColor(kBackgroundColor));
   pParams.GetGraphics()->FillPath(
       path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawHeadBk(const CFWL_ThemeBackground& pParams,
@@ -115,11 +115,11 @@
   CFGAS_GEPath path;
   CFX_RectF rtHead = pParams.m_PartRect;
   path.AddRectangle(rtHead.left, rtHead.top, rtHead.width, rtHead.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetFillColor(CFGAS_GEColor(kBackgroundColor));
   pParams.GetGraphics()->FillPath(
       path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawLButton(const CFWL_ThemeBackground& pParams,
@@ -127,7 +127,8 @@
   CFGAS_GEPath path;
   CFX_RectF rtLBtn = pParams.m_PartRect;
   path.AddRectangle(rtLBtn.left, rtLBtn.top, rtLBtn.width, rtLBtn.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(
       CFGAS_GEColor(ArgbEncode(0xff, 205, 219, 243)));
   pParams.GetGraphics()->StrokePath(path, matrix);
@@ -154,7 +155,6 @@
   pParams.GetGraphics()->SetStrokeColor(
       CFGAS_GEColor(ArgbEncode(0xff, 50, 104, 205)));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawRButton(const CFWL_ThemeBackground& pParams,
@@ -162,7 +162,8 @@
   CFGAS_GEPath path;
   CFX_RectF rtRBtn = pParams.m_PartRect;
   path.AddRectangle(rtRBtn.left, rtRBtn.top, rtRBtn.width, rtRBtn.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(
       CFGAS_GEColor(ArgbEncode(0xff, 205, 219, 243)));
   pParams.GetGraphics()->StrokePath(path, matrix);
@@ -189,7 +190,6 @@
   pParams.GetGraphics()->SetStrokeColor(
       CFGAS_GEColor(ArgbEncode(0xff, 50, 104, 205)));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawHSeparator(const CFWL_ThemeBackground& pParams,
@@ -198,10 +198,10 @@
   CFX_RectF rtHSep = pParams.m_PartRect;
   path.MoveTo(CFX_PointF(rtHSep.left, rtHSep.top + rtHSep.height / 2));
   path.LineTo(CFX_PointF(rtHSep.right(), rtHSep.top + rtHSep.height / 2));
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(CFGAS_GEColor(kSeparatorColor));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawWeekNumSep(const CFWL_ThemeBackground& pParams,
@@ -210,15 +210,15 @@
   CFX_RectF rtWeekSep = pParams.m_PartRect;
   path.MoveTo(rtWeekSep.TopLeft());
   path.LineTo(rtWeekSep.BottomLeft());
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(CFGAS_GEColor(kSeparatorColor));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawDatesInBK(const CFWL_ThemeBackground& pParams,
                                          const CFX_Matrix& matrix) {
-  pParams.GetGraphics()->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   if (pParams.m_dwStates & CFWL_PartState::kSelected) {
     CFGAS_GEPath path;
     CFX_RectF rtSelDay = pParams.m_PartRect;
@@ -238,7 +238,6 @@
     pParams.GetGraphics()->FillPath(
         path, CFX_FillRenderOptions::FillType::kWinding, matrix);
   }
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawDatesInCircle(
@@ -248,10 +247,10 @@
   CFX_RectF rtSelDay = pParams.m_PartRect;
   path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                     rtSelDay.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(CFGAS_GEColor(kDatesCircleColor));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
 
 void CFWL_MonthCalendarTP::DrawTodayCircle(const CFWL_ThemeBackground& pParams,
@@ -260,8 +259,8 @@
   CFX_RectF rtTodayCircle = pParams.m_PartRect;
   path.AddRectangle(rtTodayCircle.left, rtTodayCircle.top, rtTodayCircle.width,
                     rtTodayCircle.height);
-  pParams.GetGraphics()->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pParams.GetGraphics());
   pParams.GetGraphics()->SetStrokeColor(CFGAS_GEColor(kDatesCircleColor));
   pParams.GetGraphics()->StrokePath(path, matrix);
-  pParams.GetGraphics()->RestoreGraphState();
 }
diff --git a/xfa/fwl/theme/cfwl_pushbuttontp.cpp b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
index a0ccdea..5571d85 100644
--- a/xfa/fwl/theme/cfwl_pushbuttontp.cpp
+++ b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
@@ -55,8 +55,7 @@
       fillPath.AddSubpath(strokePath);
 
       CFGAS_GEGraphics* pGraphics = pParams.GetGraphics();
-      pGraphics->SaveGraphState();
-
+      CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
       CFX_RectF rtInner(rect);
       rtInner.Deflate(kPushbuttonSizeCorner + 1, kPushbuttonSizeCorner + 1,
                       kPushbuttonSizeCorner, kPushbuttonSizeCorner);
@@ -81,7 +80,6 @@
         rtInner.Inflate(1, 1, 0, 0);
         DrawFocus(pGraphics, rtInner, pParams.m_matrix);
       }
-      pGraphics->RestoreGraphState();
       break;
     }
     default:
diff --git a/xfa/fwl/theme/cfwl_scrollbartp.cpp b/xfa/fwl/theme/cfwl_scrollbartp.cpp
index 562d1a0..1e75e9f 100644
--- a/xfa/fwl/theme/cfwl_scrollbartp.cpp
+++ b/xfa/fwl/theme/cfwl_scrollbartp.cpp
@@ -79,14 +79,12 @@
                 m_pThemeData->clrBtnBK[static_cast<size_t>(eState) - 1][1],
                 rect, matrix);
 
-  pGraphics->SaveGraphState();
-
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   CFGAS_GEPath path;
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   pGraphics->SetStrokeColor(CFGAS_GEColor(
       m_pThemeData->clrBtnBorder[static_cast<size_t>(eState) - 1]));
   pGraphics->StrokePath(path, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_ScrollBarTP::DrawTrack(CFGAS_GEGraphics* pGraphics,
@@ -98,22 +96,24 @@
   if (eState < FWLTHEME_STATE::kNormal || eState > FWLTHEME_STATE::kDisable)
     return;
 
-  pGraphics->SaveGraphState();
-  CFGAS_GEPath path;
-  float fRight = rect.right();
-  float fBottom = rect.bottom();
-  if (bVert) {
-    path.AddRectangle(rect.left, rect.top, 1, rect.height);
-    path.AddRectangle(fRight - 1, rect.top, 1, rect.height);
-  } else {
-    path.AddRectangle(rect.left, rect.top, rect.width, 1);
-    path.AddRectangle(rect.left, fBottom - 1, rect.width, 1);
+  {
+    CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
+    CFGAS_GEPath path;
+    float fRight = rect.right();
+    float fBottom = rect.bottom();
+    if (bVert) {
+      path.AddRectangle(rect.left, rect.top, 1, rect.height);
+      path.AddRectangle(fRight - 1, rect.top, 1, rect.height);
+    } else {
+      path.AddRectangle(rect.left, rect.top, rect.width, 1);
+      path.AddRectangle(rect.left, fBottom - 1, rect.width, 1);
+    }
+    pGraphics->SetFillColor(CFGAS_GEColor(ArgbEncode(255, 238, 237, 229)));
+    pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding,
+                        matrix);
+    path.Clear();
+    path.AddRectangle(rect.left + 1, rect.top, rect.width - 2, rect.height);
   }
-  pGraphics->SetFillColor(CFGAS_GEColor(ArgbEncode(255, 238, 237, 229)));
-  pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  path.Clear();
-  path.AddRectangle(rect.left + 1, rect.top, rect.width - 2, rect.height);
-  pGraphics->RestoreGraphState();
   FillSolidRect(pGraphics, m_pThemeData->clrTrackBKEnd, rect, matrix);
 }
 
diff --git a/xfa/fwl/theme/cfwl_widgettp.cpp b/xfa/fwl/theme/cfwl_widgettp.cpp
index ed9160f..03c6d18 100644
--- a/xfa/fwl/theme/cfwl_widgettp.cpp
+++ b/xfa/fwl/theme/cfwl_widgettp.cpp
@@ -88,10 +88,10 @@
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   path.AddRectangle(rect.left + 1, rect.top + 1, rect.width - 2,
                     rect.height - 2);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(ArgbEncode(255, 0, 0, 0)));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kEvenOdd, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::FillBackground(CFGAS_GEGraphics* pGraphics,
@@ -109,10 +109,10 @@
 
   CFGAS_GEPath path;
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetFillColor(CFGAS_GEColor(fillColor));
   pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::DrawFocus(CFGAS_GEGraphics* pGraphics,
@@ -123,12 +123,12 @@
 
   CFGAS_GEPath path;
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
-  pGraphics->SaveGraphState();
+
+  CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
   pGraphics->SetStrokeColor(CFGAS_GEColor(0xFF000000));
   static constexpr float kDashPattern[2] = {1, 1};
   pGraphics->SetLineDash(0.0f, kDashPattern);
   pGraphics->StrokePath(path, matrix);
-  pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::DrawArrow(CFGAS_GEGraphics* pGraphics,
diff --git a/xfa/fxfa/cxfa_ffline.cpp b/xfa/fxfa/cxfa_ffline.cpp
index 8d8a06e..0cf841a 100644
--- a/xfa/fxfa/cxfa_ffline.cpp
+++ b/xfa/fxfa/cxfa_ffline.cpp
@@ -127,7 +127,7 @@
     linePath.AddLine(rtLine.TopLeft(), rtLine.BottomRight());
   }
 
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetLineWidth(fLineWidth);
   pGS->EnableActOnDash();
   XFA_StrokeTypeSetLineDash(pGS, iStrokeType, iCap);
@@ -135,5 +135,4 @@
   pGS->SetStrokeColor(CFGAS_GEColor(lineColor));
   pGS->SetLineCap(LineCapToFXGE(iCap));
   pGS->StrokePath(linePath, mtRotate);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_box.cpp b/xfa/fxfa/parser/cxfa_box.cpp
index 271f3222..611b7ef 100644
--- a/xfa/fxfa/parser/cxfa_box.cpp
+++ b/xfa/fxfa/parser/cxfa_box.cpp
@@ -220,10 +220,9 @@
   if (!fill || !fill->IsVisible())
     return;
 
-  pGS->SaveGraphState();
-
   CFGAS_GEPath fillPath;
   XFA_Element type = GetElementType();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   if (type == XFA_Element::Arc || forceRound) {
     CXFA_Edge* edge = GetEdgeIfExists(0);
     float fThickness = fmax(0.0, edge ? edge->GetThickness() : 0);
@@ -241,9 +240,7 @@
     NOTREACHED();
   }
   fillPath.Close();
-
   fill->Draw(pGS, fillPath, rtWidget, matrix);
-  pGS->RestoreGraphState();
 }
 
 void CXFA_Box::GetPathArcOrRounded(CFX_RectF rtDraw,
@@ -310,7 +307,7 @@
       edge->Stroke(pGS, arcPath, matrix);
     return;
   }
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetLineWidth(fHalf);
 
   float a = rtWidget.width / 2.0f;
@@ -351,5 +348,4 @@
 
   pGS->SetStrokeColor(CFGAS_GEColor(0xFFC0C0C0));
   pGS->StrokePath(arcPath, matrix);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_fill.cpp b/xfa/fxfa/parser/cxfa_fill.cpp
index 13b691b..80f3b91 100644
--- a/xfa/fxfa/parser/cxfa_fill.cpp
+++ b/xfa/fxfa/parser/cxfa_fill.cpp
@@ -96,8 +96,7 @@
                      const CFGAS_GEPath& fillPath,
                      const CFX_RectF& rtWidget,
                      const CFX_Matrix& matrix) {
-  pGS->SaveGraphState();
-
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   switch (GetType()) {
     case XFA_Element::Radial:
       DrawRadial(pGS, fillPath, rtWidget, matrix);
@@ -117,8 +116,6 @@
                     matrix);
       break;
   }
-
-  pGS->RestoreGraphState();
 }
 
 void CXFA_Fill::DrawStipple(CFGAS_GEGraphics* pGS,
diff --git a/xfa/fxfa/parser/cxfa_linear.cpp b/xfa/fxfa/parser/cxfa_linear.cpp
index 394efab..55c20b0 100644
--- a/xfa/fxfa/parser/cxfa_linear.cpp
+++ b/xfa/fxfa/parser/cxfa_linear.cpp
@@ -85,8 +85,7 @@
   }
 
   CFGAS_GEShading shading(ptStart, ptEnd, false, false, crStart, crEnd);
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetFillColor(CFGAS_GEColor(&shading));
   pGS->FillPath(fillPath, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_pattern.cpp b/xfa/fxfa/parser/cxfa_pattern.cpp
index 01456c6..c87912c 100644
--- a/xfa/fxfa/parser/cxfa_pattern.cpp
+++ b/xfa/fxfa/parser/cxfa_pattern.cpp
@@ -80,8 +80,7 @@
   }
 
   CFGAS_GEPattern pattern(iHatch, crEnd, crStart);
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetFillColor(CFGAS_GEColor(&pattern, 0x0));
   pGS->FillPath(fillPath, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_radial.cpp b/xfa/fxfa/parser/cxfa_radial.cpp
index 9f67a67..251706f 100644
--- a/xfa/fxfa/parser/cxfa_radial.cpp
+++ b/xfa/fxfa/parser/cxfa_radial.cpp
@@ -70,8 +70,7 @@
   CFGAS_GEShading shading(rtFill.Center(), rtFill.Center(), 0, end_radius, true,
                           true, crStart, crEnd);
 
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetFillColor(CFGAS_GEColor(&shading));
   pGS->FillPath(fillPath, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_stipple.cpp b/xfa/fxfa/parser/cxfa_stipple.cpp
index f5ddfd9..63ebe5d 100644
--- a/xfa/fxfa/parser/cxfa_stipple.cpp
+++ b/xfa/fxfa/parser/cxfa_stipple.cpp
@@ -67,8 +67,7 @@
   std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(crColor);
   FX_ARGB cr = AlphaAndColorRefToArgb(iRate * alpha / 100, colorref);
 
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   pGS->SetFillColor(CFGAS_GEColor(cr));
   pGS->FillPath(fillPath, CFX_FillRenderOptions::FillType::kWinding, matrix);
-  pGS->RestoreGraphState();
 }
diff --git a/xfa/fxfa/parser/cxfa_stroke.cpp b/xfa/fxfa/parser/cxfa_stroke.cpp
index fe29a97..a7be4cb 100644
--- a/xfa/fxfa/parser/cxfa_stroke.cpp
+++ b/xfa/fxfa/parser/cxfa_stroke.cpp
@@ -180,7 +180,7 @@
   if (fThickness < 0.001f)
     return;
 
-  pGS->SaveGraphState();
+  CFGAS_GEGraphics::StateRestorer restorer(pGS);
   if (IsCorner() && fThickness > 2 * GetRadius())
     fThickness = 2 * GetRadius();
 
@@ -190,5 +190,4 @@
   XFA_StrokeTypeSetLineDash(pGS, GetStrokeType(), XFA_AttributeValue::Butt);
   pGS->SetStrokeColor(CFGAS_GEColor(GetColor()));
   pGS->StrokePath(pPath, matrix);
-  pGS->RestoreGraphState();
 }