diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index c902a7333f2fd..ece0b472c6bf6 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -23,6 +23,7 @@ #include "hwui/MinikinUtils.h" #include "pipeline/skia/AnimatedDrawables.h" +#include #include #include #include @@ -410,6 +411,30 @@ void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { mCanvas->setDrawFilter(drawFilter); } +// ---------------------------------------------------------------------------- +// Canvas state operations: Capture +// ---------------------------------------------------------------------------- + +SkCanvasState* SkiaCanvas::captureCanvasState() const { + SkCanvas* canvas = mCanvas; + if (mCanvasOwned) { + // Important to use the underlying SkCanvas, not the wrapper. + canvas = mCanvasOwned.get(); + } + + // Workarounds for http://crbug.com/271096: SW draw only supports + // translate & scale transforms, and a simple rectangular clip. + // (This also avoids significant wasted time in calling + // SkCanvasStateUtils::CaptureCanvasState when the clip is complex). + if (!canvas->isClipRect() || + (canvas->getTotalMatrix().getType() & + ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) { + return nullptr; + } + + return SkCanvasStateUtils::CaptureCanvasState(canvas); +} + // ---------------------------------------------------------------------------- // Canvas draw operations // ---------------------------------------------------------------------------- diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 45924f62f6fc2..af2c23e4a2b7d 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -102,6 +102,8 @@ public: virtual SkDrawFilter* getDrawFilter() override; virtual void setDrawFilter(SkDrawFilter* drawFilter) override; + virtual SkCanvasState* captureCanvasState() const override; + virtual void drawColor(int color, SkBlendMode mode) override; virtual void drawPaint(const SkPaint& paint) override; diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 22679456cba1f..ac8a08169997a 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -27,6 +27,7 @@ #include #include +class SkCanvasState; class SkVertices; namespace minikin { @@ -204,6 +205,9 @@ public: virtual SkDrawFilter* getDrawFilter() = 0; virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0; + // WebView only + virtual SkCanvasState* captureCanvasState() const { return nullptr; } + // ---------------------------------------------------------------------------- // Canvas draw operations // ---------------------------------------------------------------------------- diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 44476af742f1c..0d1eba4af2f93 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -128,3 +129,32 @@ TEST(SkiaCanvas, colorSpaceXform) { canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } + +TEST(SkiaCanvas, captureCanvasState) { + // Create a software canvas. + SkImageInfo info = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType); + sk_sp bitmap = Bitmap::allocateHeapBitmap(info); + SkBitmap skBitmap; + bitmap->getSkBitmap(&skBitmap); + skBitmap.eraseColor(0); + SkiaCanvas canvas(skBitmap); + + // Translate, then capture and verify the CanvasState. + canvas.translate(1.0f, 1.0f); + SkCanvasState* state = canvas.captureCanvasState(); + ASSERT_NE(state, nullptr); + std::unique_ptr newCanvas = SkCanvasStateUtils::MakeFromCanvasState(state); + ASSERT_NE(newCanvas.get(), nullptr); + newCanvas->translate(-1.0f, -1.0f); + ASSERT_TRUE(newCanvas->getTotalMatrix().isIdentity()); + SkCanvasStateUtils::ReleaseCanvasState(state); + + // Create a picture canvas. + SkPictureRecorder recorder; + SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0); + SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer); + state = picCanvas.captureCanvasState(); + + // Verify that we cannot get the CanvasState. + ASSERT_EQ(state, nullptr); +}