Update Canvas API with view system calls.
Refactor DisplayListCanvas, RecordingCanvas, and SkiaCanvas
to share a common API.
Change-Id: I0268ec2749ea5d13a3a72bb2784ed6a9911383d9
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index a6c61de..03c94a6 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -27,13 +27,8 @@
#include <SkBitmap.h>
#include <SkRegion.h>
-#if HWUI_NEW_OPS
-#include <RecordingCanvas.h>
-typedef android::uirenderer::RecordingCanvas canvas_t;
-#else
-#include <DisplayListCanvas.h>
-typedef android::uirenderer::DisplayListCanvas canvas_t;
-#endif
+
+#include <Canvas.h>
#include <Rect.h>
#include <RenderNode.h>
#include <CanvasProperty.h>
@@ -52,7 +47,7 @@
static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
jlong canvasPtr, jboolean reorderEnable) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
canvas->insertReorderBarrier(reorderEnable);
}
@@ -62,7 +57,7 @@
static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong functorPtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
canvas->callDrawGLFunction(functor);
}
@@ -92,7 +87,7 @@
static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
@@ -105,7 +100,7 @@
static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
@@ -119,25 +114,25 @@
static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
jobject clazz, jlong canvasPtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
return reinterpret_cast<jlong>(canvas->finishRecording());
}
static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
jint width, jint height) {
- return reinterpret_cast<jlong>(new canvas_t(width, height));
+ return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height));
}
static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
jlong canvasPtr, jint width, jint height) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
- canvas->reset(width, height);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ canvas->resetRecording(width, height);
}
static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
canvas->drawRenderNode(renderNode);
}
@@ -148,7 +143,7 @@
static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong layerPtr) {
- canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
canvas->drawLayer(layer);
}
diff --git a/libs/hwui/Canvas.cpp b/libs/hwui/Canvas.cpp
index bc88c81..11ae1a1 100644
--- a/libs/hwui/Canvas.cpp
+++ b/libs/hwui/Canvas.cpp
@@ -16,10 +16,20 @@
#include "Canvas.h"
+#include "DisplayListCanvas.h"
+#include "RecordingCanvas.h"
#include <SkDrawFilter.h>
namespace android {
+Canvas* Canvas::create_recording_canvas(int width, int height) {
+#if HWUI_NEW_OPS
+ return new uirenderer::RecordingCanvas(width, height);
+#else
+ return new uirenderer::DisplayListCanvas(width, height);
+#endif
+}
+
void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
uint32_t flags;
SkDrawFilter* drawFilter = getDrawFilter();
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index d7e2f09..27facdf 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -18,6 +18,7 @@
#define ANDROID_GRAPHICS_CANVAS_H
#include <cutils/compiler.h>
+#include <utils/Functor.h>
#include "utils/NinePatch.h"
@@ -27,6 +28,14 @@
namespace android {
+namespace uirenderer {
+ class CanvasPropertyPaint;
+ class CanvasPropertyPrimitive;
+ class DeferredLayerUpdater;
+ class DisplayList;
+ class RenderNode;
+}
+
namespace SaveFlags {
// These must match the corresponding Canvas API constants.
@@ -56,6 +65,8 @@
static Canvas* create_canvas(const SkBitmap& bitmap);
+ static Canvas* create_recording_canvas(int width, int height);
+
/**
* Create a new Canvas object which delegates to an SkCanvas.
*
@@ -81,15 +92,36 @@
*/
virtual SkCanvas* asSkCanvas() = 0;
+
virtual void setBitmap(const SkBitmap& bitmap) = 0;
virtual bool isOpaque() = 0;
virtual int width() = 0;
virtual int height() = 0;
+// ----------------------------------------------------------------------------
+// View System operations (not exposed in public Canvas API)
+// ----------------------------------------------------------------------------
+
+ virtual void resetRecording(int width, int height) = 0;
+ virtual uirenderer::DisplayList* finishRecording() = 0;
+ virtual void insertReorderBarrier(bool enableReorder) = 0;
+
virtual void setHighContrastText(bool highContrastText) = 0;
virtual bool isHighContrastText() = 0;
+ virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
+ uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0;
+ virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) = 0;
+
+ virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
+ virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
+ virtual void callDrawGLFunction(Functor* functor) = 0;
+
// ----------------------------------------------------------------------------
// Canvas state operations
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 5366127..3db14b5 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -42,7 +42,7 @@
, mDeferredBarrierType(kBarrier_None)
, mHighContrastText(false)
, mRestoreSaveCount(-1) {
- reset(width, height);
+ resetRecording(width, height);
}
DisplayListCanvas::~DisplayListCanvas() {
@@ -50,7 +50,7 @@
"Destroyed a DisplayListCanvas during a record!");
}
-void DisplayListCanvas::reset(int width, int height) {
+void DisplayListCanvas::resetRecording(int width, int height) {
LOG_ALWAYS_FATAL_IF(mDisplayList,
"prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index d41fff4..06e72a0 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -67,36 +67,33 @@
DisplayListCanvas(int width, int height);
virtual ~DisplayListCanvas();
- void reset(int width, int height);
- WARN_UNUSED_RESULT DisplayList* finishRecording();
+ virtual void resetRecording(int width, int height) override;
+ virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override;
// ----------------------------------------------------------------------------
// HWUI Canvas state operations
// ----------------------------------------------------------------------------
- void insertReorderBarrier(bool enableReorder);
+ virtual void insertReorderBarrier(bool enableReorder) override;
// ----------------------------------------------------------------------------
// HWUI Canvas draw operations
// ----------------------------------------------------------------------------
// Shapes
- void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+ virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint);
- void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
-
+ CanvasPropertyPaint* paint) override;
+ virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
// ----------------------------------------------------------------------------
// HWUI Canvas draw operations - special
// ----------------------------------------------------------------------------
- void drawLayer(DeferredLayerUpdater* layerHandle);
- void drawRenderNode(RenderNode* renderNode);
-
- // TODO: rename for consistency
- void callDrawGLFunction(Functor* functor);
+ virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
+ virtual void drawRenderNode(RenderNode* renderNode) override;
+ virtual void callDrawGLFunction(Functor* functor) override;
// ----------------------------------------------------------------------------
// CanvasStateClient interface
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index abbd9c3..16929b8 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -27,7 +27,7 @@
RecordingCanvas::RecordingCanvas(size_t width, size_t height)
: mState(*this)
, mResourceCache(ResourceCache::getInstance()) {
- reset(width, height);
+ resetRecording(width, height);
}
RecordingCanvas::~RecordingCanvas() {
@@ -35,7 +35,7 @@
"Destroyed a RecordingCanvas during a record!");
}
-void RecordingCanvas::reset(int width, int height) {
+void RecordingCanvas::resetRecording(int width, int height) {
LOG_ALWAYS_FATAL_IF(mDisplayList,
"prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 7c8ad88..cc14e61 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -50,22 +50,19 @@
RecordingCanvas(size_t width, size_t height);
virtual ~RecordingCanvas();
- void reset(int width, int height);
- WARN_UNUSED_RESULT DisplayList* finishRecording();
-
+ virtual void resetRecording(int width, int height) override;
+ virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override;
// ----------------------------------------------------------------------------
// MISC HWUI OPERATIONS - TODO: CATEGORIZE
// ----------------------------------------------------------------------------
- void insertReorderBarrier(bool enableReorder) {
+ virtual void insertReorderBarrier(bool enableReorder) override {
mDeferredBarrierType = enableReorder
? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
}
- void drawLayer(DeferredLayerUpdater* layerHandle);
- void drawRenderNode(RenderNode* renderNode);
-
- // TODO: rename for consistency
- void callDrawGLFunction(Functor* functor);
+ virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
+ virtual void drawRenderNode(RenderNode* renderNode) override;
+ virtual void callDrawGLFunction(Functor* functor) override;
// ----------------------------------------------------------------------------
// CanvasStateClient interface
@@ -78,12 +75,12 @@
// HWUI Canvas draw operations
// ----------------------------------------------------------------------------
- void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+ virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint);
- void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
+ CanvasPropertyPaint* paint) override;
+ virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
// ----------------------------------------------------------------------------
// android/graphics/Canvas interface
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 550995b..bd4442d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -15,13 +15,18 @@
*/
#include "Canvas.h"
+#include "CanvasProperty.h"
+#include "Layer.h"
+#include "RenderNode.h"
#include <SkCanvas.h>
#include <SkClipStack.h>
+#include <SkDrawable.h>
#include <SkDevice.h>
#include <SkDeque.h>
#include <SkDrawFilter.h>
#include <SkGraphics.h>
+#include <SkImage.h>
#include <SkShader.h>
#include <SkTArray.h>
#include <SkTLazy.h>
@@ -54,6 +59,18 @@
return mCanvas.get();
}
+ virtual void resetRecording(int width, int height) override {
+ LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
+ }
+
+ virtual uirenderer::DisplayList* finishRecording() override {
+ LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList");
+ return nullptr;
+ }
+ virtual void insertReorderBarrier(bool enableReorder) override {
+ LOG_ALWAYS_FATAL("SkiaCanvas does not support reordering barriers");
+ }
+
virtual void setBitmap(const SkBitmap& bitmap) override;
virtual bool isOpaque() override;
@@ -140,6 +157,18 @@
virtual bool drawTextAbsolutePos() const override { return true; }
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
+ virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
+ uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) override;
+ virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) override;
+
+ virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
+ virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
+ virtual void callDrawGLFunction(Functor* functor) override;
+
private:
struct SaveRec {
int saveCount;
@@ -748,4 +777,84 @@
mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint);
}
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Animations
+// ----------------------------------------------------------------------------
+
+class AnimatedRoundRect : public SkDrawable {
+ public:
+ AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left,
+ uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p) :
+ mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {}
+
+ protected:
+ virtual SkRect onGetBounds() override {
+ return SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value);
+ }
+ virtual void onDraw(SkCanvas* canvas) override {
+ SkRect rect = SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value);
+ canvas->drawRoundRect(rect, mRx->value, mRy->value, mPaint->value);
+ }
+
+ private:
+ sp<uirenderer::CanvasPropertyPrimitive> mLeft;
+ sp<uirenderer::CanvasPropertyPrimitive> mTop;
+ sp<uirenderer::CanvasPropertyPrimitive> mRight;
+ sp<uirenderer::CanvasPropertyPrimitive> mBottom;
+ sp<uirenderer::CanvasPropertyPrimitive> mRx;
+ sp<uirenderer::CanvasPropertyPrimitive> mRy;
+ sp<uirenderer::CanvasPropertyPaint> mPaint;
+};
+
+class AnimatedCircle : public SkDrawable {
+ public:
+ AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) :
+ mX(x), mY(y), mRadius(radius), mPaint(paint) {}
+
+ protected:
+ virtual SkRect onGetBounds() override {
+ const float x = mX->value;
+ const float y = mY->value;
+ const float radius = mRadius->value;
+ return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
+ }
+ virtual void onDraw(SkCanvas* canvas) override {
+ canvas->drawCircle(mX->value, mY->value, mRadius->value, mPaint->value);
+ }
+
+ private:
+ sp<uirenderer::CanvasPropertyPrimitive> mX;
+ sp<uirenderer::CanvasPropertyPrimitive> mY;
+ sp<uirenderer::CanvasPropertyPrimitive> mRadius;
+ sp<uirenderer::CanvasPropertyPaint> mPaint;
+};
+
+void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
+ uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
+ SkAutoTUnref<AnimatedRoundRect> drawable(
+ new AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
+ mCanvas->drawDrawable(drawable.get());
+}
+
+void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
+ SkAutoTUnref<AnimatedCircle> drawable(new AnimatedCircle(x, y, radius, paint));
+ mCanvas->drawDrawable(drawable.get());
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: View System
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layer) { }
+
+void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { }
+
+void SkiaCanvas::callDrawGLFunction(Functor* functor) { }
+
} // namespace android
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 83af148..b317c12 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -63,7 +63,7 @@
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
- canvas.reset(100, 100);
+ canvas.resetRecording(100, 100);
MicroBench::DoNotOptimize(&canvas);
delete canvas.finishRecording();
}
@@ -77,7 +77,7 @@
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
- canvas.reset(100, 100);
+ canvas.resetRecording(100, 100);
canvas.save(SaveFlags::MatrixClip);
canvas.save(SaveFlags::MatrixClip);
MicroBench::DoNotOptimize(&canvas);
@@ -95,7 +95,7 @@
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
- canvas.reset(100, 100);
+ canvas.resetRecording(100, 100);
canvas.scale(10, 10);
MicroBench::DoNotOptimize(&canvas);
delete canvas.finishRecording();
@@ -119,7 +119,7 @@
StartBenchmarkTiming();
for (int i = 0; i < iters; ++i) {
- canvas.reset(100, 100);
+ canvas.resetRecording(100, 100);
{
canvas.save(SaveFlags::MatrixClip);
canvas.drawRect(0, 0, 100, 100, rectPaint);