Remove clipping operations from SkiaState

Removes clipping operations from SkiaState, as directly calling the
equivalent SkCanvas operations is more efficient and simpler than
maintaining a duplicate clipping state stack.

Bug: pdfium:1963
Change-Id: I2066205686a5a851669607dc00917fd0d80bad09
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/104592
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Nigi <nigi@chromium.org>
Auto-Submit: K. Moon <kmoon@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index 396a301..d01a6bb 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -787,15 +787,9 @@
 
 }  // namespace
 
-// Encapsulate the state used for successive text and path draws so that
-// they can be combined.
+// TODO(crbug.com/pdfium/1936): Inline remaining methods.
 class SkiaState {
  public:
-  enum class Clip {
-    kSave,
-    kPath,
-  };
-
   // mark all cached state as uninitialized
   explicit SkiaState(CFX_SkiaDeviceDriver* pDriver) : m_pDriver(pDriver) {}
 
@@ -813,8 +807,6 @@
       m_drawState = *pDrawState;
     }
 
-    AdjustClip(m_commandIndex);
-
     SkMatrix skMatrix = pMatrix ? ToSkMatrix(*pMatrix) : SkMatrix();
     SkPaint skPaint;
     skPaint.setAntiAlias(!fill_options.aliased_path);
@@ -957,8 +949,6 @@
       }
     }
 
-    AdjustClip(m_commandIndex);
-
     SkPaint skPaint;
     skPaint.setAntiAlias(true);
     skPaint.setColor(color);
@@ -996,127 +986,6 @@
     return true;
   }
 
-  bool IsEmpty() const { return m_commands.empty(); }
-
-  void SetClipFill(const CFX_Path& path,
-                   const CFX_Matrix* pMatrix,
-                   const CFX_FillRenderOptions& fill_options) {
-    SkPath skClipPath;
-    if (path.GetPoints().size() == 5 || path.GetPoints().size() == 4) {
-      absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pMatrix);
-      if (maybe_rectf.has_value()) {
-        CFX_FloatRect& rectf = maybe_rectf.value();
-        rectf.Intersect(CFX_FloatRect(
-            0, 0,
-            static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH)),
-            static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT))));
-        FX_RECT outer = rectf.GetOuterRect();
-        // note that PDF's y-axis goes up; Skia's y-axis goes down
-        skClipPath.addRect({(float)outer.left, (float)outer.bottom,
-                            (float)outer.right, (float)outer.top});
-      }
-    }
-    if (skClipPath.isEmpty()) {
-      skClipPath = BuildPath(path);
-      skClipPath.setFillType(GetAlternateOrWindingFillType(fill_options));
-      SkMatrix skMatrix = ToSkMatrix(*pMatrix);
-      skClipPath.transform(skMatrix);
-    }
-    SetClip(skClipPath);
-  }
-
-  void SetClip(const SkPath& skClipPath) {
-    // if a pending draw depends on clip state that is cached, flush it and draw
-    if (fxcrt::IndexInBounds(m_commands, m_commandIndex)) {
-      if (m_commands[m_commandIndex] == Clip::kPath &&
-          m_clips[m_commandIndex] == skClipPath) {
-        ++m_commandIndex;
-        return;
-      }
-    }
-    while (m_clipIndex > m_commandIndex) {
-      do {
-        --m_clipIndex;
-        DCHECK(m_clipIndex >= 0);
-      } while (m_commands[m_clipIndex] != Clip::kSave);
-      m_pDriver->SkiaCanvas()->restore();
-    }
-    if (fxcrt::IndexInBounds(m_commands, m_commandIndex)) {
-      m_commands[m_commandIndex] = Clip::kPath;
-      m_clips[m_commandIndex] = skClipPath;
-    } else {
-      m_commands.push_back(Clip::kPath);
-      m_clips.push_back(skClipPath);
-    }
-    ++m_commandIndex;
-  }
-
-  void SetClipStroke(const CFX_Path& path,
-                     const CFX_Matrix* pMatrix,
-                     const CFX_GraphStateData* pGraphState) {
-    SkPath skPath = BuildPath(path);
-    SkMatrix skMatrix = ToSkMatrix(*pMatrix);
-    SkPaint skPaint;
-    PaintStroke(&skPaint, pGraphState, skMatrix, CFX_FillRenderOptions());
-    SkPath dst_path;
-    skpathutils::FillPathWithPaint(skPath, skPaint, &dst_path);
-    dst_path.transform(skMatrix);
-    SetClip(dst_path);
-  }
-
-  void ClipSave() {
-    if (m_commandIndex < m_commands.size()) {
-      if (Clip::kSave == m_commands[m_commandIndex]) {
-        ++m_commandIndex;
-        return;
-      }
-      AdjustClip(m_commandIndex);
-      m_commands[m_commandIndex] = Clip::kSave;
-      m_clips[m_commandIndex] = m_skEmptyPath;
-    } else {
-      AdjustClip(m_commandIndex);
-      m_commands.push_back(Clip::kSave);
-      m_clips.push_back(m_skEmptyPath);
-    }
-    ++m_commandIndex;
-  }
-
-  void ClipRestore() {
-    for (size_t i = m_commandIndex - 1; i > 0; --i) {
-      if (m_commands[i] == Clip::kSave) {
-        m_commandIndex = i;
-        break;
-      }
-    }
-  }
-
-  void AdjustClip(size_t limit) {
-    while (m_clipIndex > limit) {
-      while (m_clipIndex > 0) {
-        --m_clipIndex;
-        if (m_commands[m_clipIndex] == Clip::kSave) {
-          m_pDriver->SkiaCanvas()->restore();
-          break;
-        }
-      }
-    }
-    while (m_clipIndex < limit) {
-      if (Clip::kSave == m_commands[m_clipIndex]) {
-        m_pDriver->SkiaCanvas()->save();
-      } else {
-        DCHECK_EQ(Clip::kPath, m_commands[m_clipIndex]);
-        m_pDriver->SkiaCanvas()->clipPath(m_clips[m_clipIndex],
-                                          SkClipOp::kIntersect, true);
-      }
-      ++m_clipIndex;
-    }
-  }
-
-  // TODO(crbug.com/pdfium/1963): Simplify clip handling.
-  void FlushForDraw() {
-    AdjustClip(m_commandIndex);  // set up clip stack with any pending state
-  }
-
  private:
   class CharDetail {
    public:
@@ -1152,21 +1021,11 @@
     DataVector<uint32_t> m_fontCharWidths;
   };
 
-  // stack of clips that may be reused
-  std::vector<SkPath> m_clips;
-  // stack of clip-related commands
-  DataVector<Clip> m_commands;
   CharDetail m_charDetails;
   // accumulator for txt rotate/scale/translate
   DataVector<SkRSXform> m_rsxform;
-  // used as placehold in the clips array
-  SkPath m_skEmptyPath;
   CFX_GraphStateData m_drawState;
   UnownedPtr<CFX_SkiaDeviceDriver> const m_pDriver;
-  // active position in clip command stack
-  size_t m_commandIndex = 0;
-  // position reflecting depth of canvas clip stack
-  size_t m_clipIndex = 0;
 };
 
 // static
@@ -1436,15 +1295,14 @@
 }
 
 void CFX_SkiaDeviceDriver::SaveState() {
-  m_pCache->ClipSave();
+  m_pCanvas->save();
 }
 
 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) {
-  if (m_pCache->IsEmpty())
-    return;
-  m_pCache->ClipRestore();
-  if (bKeepSaved)
-    m_pCache->ClipSave();
+  m_pCanvas->restore();
+  if (bKeepSaved) {
+    m_pCanvas->save();
+  }
 }
 
 bool CFX_SkiaDeviceDriver::SetClip_PathFill(
@@ -1452,25 +1310,30 @@
     const CFX_Matrix* pObject2Device,  // flips object's y-axis
     const CFX_FillRenderOptions& fill_options) {
   m_FillOptions = fill_options;
-  CFX_Matrix identity;
-  const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity;
-  m_pCache->SetClipFill(path, deviceMatrix, fill_options);
+  const CFX_Matrix& deviceMatrix =
+      pObject2Device ? *pObject2Device : CFX_Matrix();
+
+  SkPath skClipPath;
   if (path.GetPoints().size() == 5 || path.GetPoints().size() == 4) {
-    absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(deviceMatrix);
+    absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(&deviceMatrix);
     if (maybe_rectf.has_value()) {
       CFX_FloatRect& rectf = maybe_rectf.value();
       rectf.Intersect(CFX_FloatRect(0, 0,
                                     (float)GetDeviceCaps(FXDC_PIXEL_WIDTH),
                                     (float)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
-      DebugShowCanvasClip(this, m_pCanvas);
-      return true;
+      FX_RECT outer = rectf.GetOuterRect();
+      // note that PDF's y-axis goes up; Skia's y-axis goes down
+      skClipPath.addRect({(float)outer.left, (float)outer.bottom,
+                          (float)outer.right, (float)outer.top});
     }
   }
-  SkPath skClipPath = BuildPath(path);
-  skClipPath.setFillType(GetAlternateOrWindingFillType(fill_options));
-  SkMatrix skMatrix = ToSkMatrix(*deviceMatrix);
-  skClipPath.transform(skMatrix);
-  DebugShowSkiaPath(skClipPath);
+  if (skClipPath.isEmpty()) {
+    skClipPath = BuildPath(path);
+    skClipPath.setFillType(GetAlternateOrWindingFillType(fill_options));
+    skClipPath.transform(ToSkMatrix(deviceMatrix));
+    DebugShowSkiaPath(skClipPath);
+  }
+  m_pCanvas->clipPath(skClipPath, SkClipOp::kIntersect, true);
   DebugShowCanvasClip(this, m_pCanvas);
   return true;
 }
@@ -1480,16 +1343,14 @@
     const CFX_Matrix* pObject2Device,      // required transformation
     const CFX_GraphStateData* pGraphState  // graphic state, for pen attributes
 ) {
-  m_pCache->SetClipStroke(path, pObject2Device, pGraphState);
-
-  // build path data
   SkPath skPath = BuildPath(path);
   SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
   SkPaint skPaint;
-  PaintStroke(&skPaint, pGraphState, skMatrix, m_FillOptions);
+  PaintStroke(&skPaint, pGraphState, skMatrix, CFX_FillRenderOptions());
   SkPath dst_path;
   skpathutils::FillPathWithPaint(skPath, skPaint, &dst_path);
   dst_path.transform(skMatrix);
+  m_pCanvas->clipPath(dst_path, SkClipOp::kIntersect, true);
   DebugShowCanvasClip(this, m_pCanvas);
   return true;
 }
@@ -1518,7 +1379,6 @@
 bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
                                              uint32_t fill_color,
                                              BlendMode blend_type) {
-  m_pCache->FlushForDraw();
   SkPaint spaint;
   spaint.setAntiAlias(true);
   spaint.setColor(fill_color);
@@ -1535,7 +1395,6 @@
                                        const FX_RECT& clip_rect,
                                        int alpha,
                                        bool bAlphaMode) {
-  m_pCache->FlushForDraw();
   ShadingType shadingType = pPattern->GetShadingType();
   if (kAxialShading != shadingType && kRadialShading != shadingType &&
       kCoonsPatchMeshShading != shadingType) {
@@ -1743,7 +1602,6 @@
   uint8_t* srcBuffer = m_pBitmap->GetBuffer().data();
   if (!srcBuffer)
     return true;
-  m_pCache->FlushForDraw();
   int srcWidth = m_pBitmap->GetWidth();
   int srcHeight = m_pBitmap->GetHeight();
   size_t srcRowBytes = m_pBitmap->GetPitch();
@@ -1800,7 +1658,6 @@
                                          const FX_RECT* pClipRect,
                                          const FXDIB_ResampleOptions& options,
                                          BlendMode blend_type) {
-  m_pCache->FlushForDraw();
   if (m_pBitmap->GetBuffer().empty())
     return true;
 
@@ -1832,7 +1689,6 @@
 
 bool CFX_SkiaDeviceDriver::ContinueDIBits(CFX_ImageRenderer* handle,
                                           PauseIndicatorIface* pPause) {
-  m_pCache->FlushForDraw();
   return false;
 }
 
@@ -1908,7 +1764,6 @@
     return false;
   }
   {
-    m_pCache->FlushForDraw();
     SkAutoCanvasRestore scoped_save_restore(m_pCanvas, /*doSave=*/true);
 
     const int src_width = pSource->GetWidth();
@@ -1969,7 +1824,6 @@
     const CFX_Matrix& matrix,
     const FXDIB_ResampleOptions& options,
     BlendMode blend_type) {
-  m_pCache->FlushForDraw();
   DebugValidate(m_pBitmap, m_pBackdropBitmap);
   // Storage vector must outlive `skBitmap`.
   DataVector<uint32_t> dst32_storage;