Add a private API for writing the clip to the stencil

Add a private API used by Android framework, which writes the clip
into a stencil buffer. This is used by HWUI to clip the WebView.

Bug: 31489986
Change-Id: I94515f1539acd9d069c8aceb3300577feed9c94f
Reviewed-on: https://skia-review.googlesource.com/29521
Commit-Queue: Stan Iliev <stani@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index d837d1d..08b94cd 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -678,6 +678,7 @@
   sources += skia_utils_sources
   sources += skia_xps_sources
   sources += [
+    "src/android/SkAndroidFrameworkUtils.cpp",
     "src/android/SkBitmapRegionCodec.cpp",
     "src/android/SkBitmapRegionDecoder.cpp",
     "src/codec/SkAndroidCodec.cpp",
diff --git a/include/android/SkAndroidFrameworkUtils.h b/include/android/SkAndroidFrameworkUtils.h
new file mode 100644
index 0000000..0457d03
--- /dev/null
+++ b/include/android/SkAndroidFrameworkUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAndroidFrameworkUtils_DEFINED
+#define SkAndroidFrameworkUtils_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef SK_BUILD_FOR_ANDROID
+
+class SkCanvas;
+
+/**
+ *  SkAndroidFrameworkUtils expose private APIs used only by Android framework.
+ */
+class SkAndroidFrameworkUtils {
+public:
+
+#if SK_SUPPORT_GPU
+    /**
+     *  clipWithStencil draws the current clip into a stencil buffer with reference value and mask
+     *  set to 0x1. This function works only on a GPU canvas.
+     *
+     *  @param  canvas A GPU canvas that has a non-empty clip.
+     *
+     *  @return true on success or false if clip is empty or not a GPU canvas.
+     */
+    static bool clipWithStencil(SkCanvas* canvas);
+#endif //SK_SUPPORT_GPU
+};
+
+#endif // SK_BUILD_FOR_ANDROID
+
+#endif // SkAndroidFrameworkUtils_DEFINED
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 8fbca71..c4cb175 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -17,6 +17,7 @@
 
 class GrContext;
 class GrRenderTargetContext;
+class SkAndroidFrameworkUtils;
 class SkBaseDevice;
 class SkBitmap;
 class SkClipStack;
@@ -1457,6 +1458,7 @@
     void checkForDeferredSave();
     void internalSetMatrix(const SkMatrix&);
 
+    friend class SkAndroidFrameworkUtils;
     friend class SkDrawIter;        // needs setupDrawForLayerDevice()
     friend class AutoDrawLooper;
     friend class SkDebugCanvas;     // needs experimental fAllowSimplifyClip
diff --git a/src/android/SkAndroidFrameworkUtils.cpp b/src/android/SkAndroidFrameworkUtils.cpp
new file mode 100644
index 0000000..5fbc2ca
--- /dev/null
+++ b/src/android/SkAndroidFrameworkUtils.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAndroidFrameworkUtils.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+
+#if SK_SUPPORT_GPU
+#include "GrStyle.h"
+#include "GrClip.h"
+#include "GrRenderTargetContext.h"
+#include "GrUserStencilSettings.h"
+#include "effects/GrDisableColorXP.h"
+#endif //SK_SUPPORT_GPU
+
+#ifdef SK_BUILD_FOR_ANDROID
+
+#if SK_SUPPORT_GPU
+bool SkAndroidFrameworkUtils::clipWithStencil(SkCanvas* canvas) {
+    SkRegion clipRegion;
+    canvas->temporary_internal_getRgnClip(&clipRegion);
+    if (clipRegion.isEmpty()) {
+        return false;
+    }
+    SkBaseDevice* device = canvas->getDevice();
+    if (!device) {
+        return false;
+    }
+    GrRenderTargetContext* rtc = device->accessRenderTargetContext();
+    if (!rtc) {
+        return false;
+    }
+    GrPaint grPaint;
+    grPaint.setXPFactory(GrDisableColorXPFactory::Get());
+    GrNoClip noClip;
+    static constexpr GrUserStencilSettings kDrawToStencil(
+        GrUserStencilSettings::StaticInit<
+            0x1,
+            GrUserStencilTest::kAlways,
+            0x1,
+            GrUserStencilOp::kReplace,
+            GrUserStencilOp::kReplace,
+            0x1>()
+    );
+    rtc->drawRegion(noClip, std::move(grPaint), GrAA::kNo, SkMatrix::I(), clipRegion,
+                    GrStyle::SimpleFill(), &kDrawToStencil);
+    return true;
+}
+#endif //SK_SUPPORT_GPU
+
+#endif // SK_BUILD_FOR_ANDROID
+
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index c0aef8e..c531b1e 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -13,6 +13,7 @@
 #include "SkColor.h"
 #include "SkSurfaceProps.h"
 
+class SkAndroidFrameworkUtils;
 class SkBitmap;
 class SkDrawFilter;
 struct SkDrawShadowRec;
@@ -346,6 +347,7 @@
     static void LogDrawScaleFactor(const SkMatrix&, SkFilterQuality);
 
 private:
+    friend class SkAndroidFrameworkUtils;
     friend class SkCanvas;
     friend struct DeviceCM; //for setMatrixClip
     friend class SkDraw;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index d54b084..cc82408 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1277,7 +1277,8 @@
                                        GrAA aa,
                                        const SkMatrix& viewMatrix,
                                        const SkRegion& region,
-                                       const GrStyle& style) {
+                                       const GrStyle& style,
+                                       const GrUserStencilSettings* ss) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -1300,7 +1301,8 @@
     }
 
     GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
-    std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(std::move(paint), viewMatrix, region, aaType);
+    std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(std::move(paint), viewMatrix, region, aaType,
+                                                    ss);
     this->addDrawOp(clip, std::move(op));
 }
 
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 964d9e9..d7d2b9b 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -246,7 +246,8 @@
                     GrAA aa,
                     const SkMatrix& viewMatrix,
                     const SkRegion& region,
-                    const GrStyle& style);
+                    const GrStyle& style,
+                    const GrUserStencilSettings* ss = nullptr);
 
     /**
      * Draws an oval.
diff --git a/src/gpu/ops/GrRegionOp.cpp b/src/gpu/ops/GrRegionOp.cpp
index f059ac7..7e2879c 100644
--- a/src/gpu/ops/GrRegionOp.cpp
+++ b/src/gpu/ops/GrRegionOp.cpp
@@ -169,11 +169,11 @@
 namespace GrRegionOp {
 
 std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, const SkRegion& region,
-                               GrAAType aaType) {
+                               GrAAType aaType, const GrUserStencilSettings* stencilSettings) {
     if (aaType != GrAAType::kNone && aaType != GrAAType::kMSAA) {
         return nullptr;
     }
-    return RegionOp::Make(std::move(paint), viewMatrix, region, aaType);
+    return RegionOp::Make(std::move(paint), viewMatrix, region, aaType, stencilSettings);
 }
 }
 
diff --git a/src/gpu/ops/GrRegionOp.h b/src/gpu/ops/GrRegionOp.h
index bfdad71..b74f78c 100644
--- a/src/gpu/ops/GrRegionOp.h
+++ b/src/gpu/ops/GrRegionOp.h
@@ -14,10 +14,12 @@
 class SkMatrix;
 class SkRegion;
 class GrPaint;
+struct GrUserStencilSettings;
 
 namespace GrRegionOp {
 /** GrAAType must be kNone or kMSAA. */
-std::unique_ptr<GrDrawOp> Make(GrPaint&&, const SkMatrix& viewMatrix, const SkRegion&, GrAAType);
+std::unique_ptr<GrDrawOp> Make(GrPaint&&, const SkMatrix& viewMatrix, const SkRegion&, GrAAType,
+                               const GrUserStencilSettings* stencilSettings = nullptr);
 }
 
 #endif