pass Paint not SkPaint to Canvas

Test: cts

Change-Id: I9a3314bc3f221b6e884c8c84d7b0241f7c5be600
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index f01b1bf..54ac0bd9 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -454,7 +454,7 @@
 // Canvas draw operations: Geometry
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
                             SkCanvas::PointMode mode) {
     if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
     // convert the floats into SkPoints
@@ -464,109 +464,142 @@
         pts[i].set(points[0], points[1]);
         points += 2;
     }
-    mCanvas->drawPoints(mode, count, pts.get(), *filterPaint(paint));
+
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPoints(mode, count, pts.get(), p);
+    });
 }
 
-void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
-    mCanvas->drawPoint(x, y, *filterPaint(paint));
+void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPoint(x, y, p);
+    });
 }
 
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
-    this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kPoints_PointMode);
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
+    this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
 }
 
 void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) {
-    mCanvas->drawLine(startX, startY, stopX, stopY, *filterPaint(paint));
+                          const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawLine(startX, startY, stopX, stopY, p);
+    });
 }
 
-void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
     if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return;
-    this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kLines_PointMode);
+    this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
 }
 
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
-    mCanvas->drawRect({left, top, right, bottom}, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRect({left, top, right, bottom}, p);
+    });
 }
 
-void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
+void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
-    mCanvas->drawRegion(region, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRegion(region, p);
+    });
 }
 
 void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) {
+                               const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawRoundRect(rect, rx, ry, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRoundRect(rect, rx, ry, p);
+    });
 }
 
 void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                                const SkPaint& paint) {
-    mCanvas->drawDRRect(outer, inner, *filterPaint(paint));
+                                const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawDRRect(outer, inner, p);
+    });
 }
 
-void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
     if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
-    mCanvas->drawCircle(x, y, radius, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawCircle(x, y, radius, p);
+    });
 }
 
-void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawOval(oval, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawOval(oval, p);
+    });
 }
 
 void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) {
+                         float sweepAngle, bool useCenter, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
-    if (fabs(sweepAngle) >= 360.0f) {
-        mCanvas->drawOval(arc, *filterPaint(paint));
-    } else {
-        mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, *filterPaint(paint));
-    }
+    apply_looper(&paint, [&](const SkPaint& p) {
+        if (fabs(sweepAngle) >= 360.0f) {
+            mCanvas->drawOval(arc, p);
+        } else {
+            mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, p);
+        }
+    });
 }
 
-void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
         return;
     }
-    mCanvas->drawPath(path, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPath(path, p);
+    });
 }
 
-void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
-    mCanvas->drawVertices(vertices, mode, *filterPaint(paint));
+void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawVertices(vertices, mode, p);
+    });
 }
 
 // ----------------------------------------------------------------------------
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint));
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
+    auto image = bitmap.makeImage();
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImage(image, left, top, &p);
+    });
 }
 
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
+    auto image = bitmap.makeImage();
     SkAutoCanvasRestore acr(mCanvas, true);
     mCanvas->concat(matrix);
-    mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint));
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImage(image, 0, 0, &p);
+    });
 }
 
 void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) {
+                            float dstBottom, const Paint* paint) {
+    auto image = bitmap.makeImage();
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
 
-    mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint),
-                           SkCanvas::kFast_SrcRectConstraint);
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImageRect(image, srcRect, dstRect, &p, SkCanvas::kFast_SrcRectConstraint);
+    });
 }
 
 void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
-                                const float* vertices, const int* colors, const SkPaint* paint) {
+                                const float* vertices, const int* colors, const Paint* paint) {
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     const int indexCount = meshWidth * meshHeight * 6;
     uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
@@ -640,20 +673,20 @@
 #endif
 
     // cons-up a shader for the bitmap
-    PaintCoW paintCoW(paint);
-    SkPaint& tmpPaint = paintCoW.writeable();
-
-    sk_sp<SkImage> image = bitmap.makeImage();
-    sk_sp<SkShader> shader = image->makeShader();
-    tmpPaint.setShader(std::move(shader));
-
-    mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate,
-                          *filterPaint(std::move(paintCoW)));
+    Paint pnt;
+    if (paint) {
+        pnt = *paint;
+    }
+    pnt.setShader(bitmap.makeImage()->makeShader());
+    auto v = builder.detach();
+    apply_looper(&pnt, [&](const SkPaint& p) {
+        mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
+    });
 }
 
 void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) {
+                               const Paint* paint) {
     SkCanvas::Lattice lattice;
     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
@@ -674,8 +707,10 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-
-    mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint));
+    auto image = bitmap.makeImage();
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImageLattice(image.get(), lattice, dst, &p);
+    });
 }
 
 double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 799a891..ec83a19 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -22,8 +22,10 @@
 #include "RenderNode.h"
 #include "VectorDrawable.h"
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 
 #include <SkCanvas.h>
+#include "src/core/SkArenaAlloc.h"
 
 #include <cassert>
 #include <optional>
@@ -99,39 +101,39 @@
     virtual void drawColor(int color, SkBlendMode mode) override;
     virtual void drawPaint(const SkPaint& paint) override;
 
-    virtual void drawPoint(float x, float y, const SkPaint& paint) override;
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawPoint(float x, float y, const Paint& paint) override;
+    virtual void drawPoints(const float* points, int count, const Paint& paint) override;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) override;
-    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+                          const Paint& paint) override;
+    virtual void drawLines(const float* points, int count, const Paint& paint) override;
     virtual void drawRect(float left, float top, float right, float bottom,
-                          const SkPaint& paint) override;
-    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
+                          const Paint& paint) override;
+    virtual void drawRegion(const SkRegion& region, const Paint& paint) override;
     virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) override;
+                               const Paint& paint) override;
 
    virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                               const SkPaint& paint) override;
+                               const Paint& paint) override;
 
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const Paint& paint) override;
     virtual void drawOval(float left, float top, float right, float bottom,
-                          const SkPaint& paint) override;
+                          const Paint& paint) override;
     virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) override;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
-    virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
+                         float sweepAngle, bool useCenter, const Paint& paint) override;
+    virtual void drawPath(const SkPath& path, const Paint& paint) override;
+    virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) override;
 
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) override;
+                            float dstBottom, const Paint* paint) override;
     virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
                                 const float* vertices, const int* colors,
-                                const SkPaint* paint) override;
+                                const Paint* paint) override;
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) override;
+                               const Paint* paint) override;
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
 
     virtual bool drawTextAbsolutePos() const override { return true; }
@@ -208,6 +210,35 @@
      */
     PaintCoW&& filterPaint(PaintCoW&& paint) const;
 
+    template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
+        SkPaint skp;
+        SkDrawLooper* looper = nullptr;
+        if (paint) {
+            skp = *filterPaint(paint);
+            looper = paint->getLooper();
+        }
+        if (looper) {
+            SkSTArenaAlloc<256> alloc;
+            SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+            if (ctx) {
+                SkDrawLooper::Context::Info info;
+                for (;;) {
+                    SkPaint p = skp;
+                    if (!ctx->next(&info, &p)) {
+                        break;
+                    }
+                    mCanvas->save();
+                    mCanvas->translate(info.fTranslate.fX, info.fTranslate.fY);
+                    proc(p);
+                    mCanvas->restore();
+                }
+            }
+        } else {
+            proc(skp);
+        }
+    }
+
+
 private:
     struct SaveRec {
         int saveCount;
@@ -222,7 +253,7 @@
     void recordClip(const T&, SkClipOp);
     void applyPersistentClips(size_t clipStartIndex);
 
-    void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode);
+    void drawPoints(const float* points, int count, const Paint& paint, SkCanvas::PointMode mode);
 
     class Clip;
 
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 89ad1b9..f91d178 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
 #include "VectorDrawable.h"
 
 #include <utils/Log.h>
+#include "hwui/Paint.h"
 #include "PathParser.h"
 #include "SkColorFilter.h"
 #include "SkImageInfo.h"
@@ -458,8 +459,12 @@
         mStagingCache.dirty = false;
     }
 
-    SkPaint paint;
-    getPaintFor(&paint, mStagingProperties);
+    SkPaint skp;
+    getPaintFor(&skp, mStagingProperties);
+    Paint paint;
+    paint.setFilterQuality(skp.getFilterQuality());
+    paint.setColorFilter(skp.refColorFilter());
+    paint.setAlpha(skp.getAlpha());
     outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
                           mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
                           mStagingProperties.getBounds().top(),
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index a48c860..b98ffca 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -34,7 +34,7 @@
 }
 
 static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
-                              const SkPaint& paint, Canvas* canvas) {
+                              const Paint& paint, Canvas* canvas) {
     const SkScalar strokeWidth = fmax(thickness, 1.0f);
     const SkScalar bottom = top + strokeWidth;
     canvas->drawRect(left, top, right, bottom, paint);
@@ -182,7 +182,7 @@
 void Canvas::drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
                             float outerBottom, float outerRx, float outerRy, float innerLeft,
                             float innerTop, float innerRight, float innerBottom, float innerRx,
-                            float innerRy, const SkPaint& paint) {
+                            float innerRy, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
     SkRect inner = SkRect::MakeLTRB(innerLeft, innerTop, innerRight, innerBottom);
@@ -198,7 +198,7 @@
 void Canvas::drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
                             float outerBottom, const float* outerRadii, float innerLeft,
                             float innerTop, float innerRight, float innerBottom,
-                            const float* innerRadii, const SkPaint& paint) {
+                            const float* innerRadii, const Paint& paint) {
     static_assert(sizeof(SkVector) == sizeof(float) * 2);
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index ee4fa1d6..b90a4a3d 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -217,37 +217,37 @@
     virtual void drawPaint(const SkPaint& paint) = 0;
 
     // Geometry
-    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
-    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
+    virtual void drawPoint(float x, float y, const Paint& paint) = 0;
+    virtual void drawPoints(const float* points, int floatCount, const Paint& paint) = 0;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) = 0;
-    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
+    virtual void drawLines(const float* points, int floatCount, const Paint& paint) = 0;
     virtual void drawRect(float left, float top, float right, float bottom,
-                          const SkPaint& paint) = 0;
-    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
+    virtual void drawRegion(const SkRegion& region, const Paint& paint) = 0;
     virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) = 0;
+                               const Paint& paint) = 0;
     virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                                const SkPaint& paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+                                const Paint& paint) = 0;
+    virtual void drawCircle(float x, float y, float radius, const Paint& paint) = 0;
     virtual void drawOval(float left, float top, float right, float bottom,
-                          const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
     virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
-    virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) = 0;
+                         float sweepAngle, bool useCenter, const Paint& paint) = 0;
+    virtual void drawPath(const SkPath& path, const Paint& paint) = 0;
+    virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) = 0;
 
     // Bitmap-based
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) = 0;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) = 0;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) = 0;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) = 0;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) = 0;
+                            float dstBottom, const Paint* paint) = 0;
     virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
-                                const float* vertices, const int* colors, const SkPaint* paint) = 0;
+                                const float* vertices, const int* colors, const Paint* paint) = 0;
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) = 0;
+                               const Paint* paint) = 0;
 
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
     virtual void drawPicture(const SkPicture& picture) = 0;
@@ -281,12 +281,12 @@
     void drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
                                 float outerBottom, float outerRx, float outerRy, float innerLeft,
                                 float innerTop, float innerRight, float innerBottom, float innerRx,
-                                float innerRy, const SkPaint& paint);
+                                float innerRy, const Paint& paint);
 
     void drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
                                 float outerBottom, const float* outerRadii, float innerLeft,
                                 float innerTop, float innerRight, float innerBottom,
-                                const float* innerRadii, const SkPaint& paint);
+                                const float* innerRadii, const Paint& paint);
 
     static int GetApiLevel() { return sApiLevel; }
 
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 9b2fa9d..281ecd2 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -21,6 +21,7 @@
 
 #include <cutils/compiler.h>
 
+#include <SkDrawLooper.h>
 #include <SkFont.h>
 #include <SkPaint.h>
 #include <string>
@@ -58,12 +59,17 @@
     SkFont& getSkFont() { return mFont; }
     const SkFont& getSkFont() const { return mFont; }
 
+    SkDrawLooper* getLooper() const { return mLooper.get(); }
+    void setLooper(sk_sp<SkDrawLooper> looper) { mLooper = std::move(looper); }
+
     // These shadow the methods on SkPaint, but we need to so we can keep related
     // attributes in-sync.
 
     void reset();
     void setAntiAlias(bool);
 
+    bool nothingToDraw() const { return !mLooper && SkPaint::nothingToDraw(); }
+
     // End method shadowing
 
     void setLetterSpacing(float letterSpacing) { mLetterSpacing = letterSpacing; }
@@ -146,6 +152,7 @@
  
 private:
     SkFont mFont;
+    sk_sp<SkDrawLooper> mLooper;
 
     float mLetterSpacing = 0;
     float mWordSpacing = 0;
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 2f2d575..fa2674f 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -34,6 +34,7 @@
 Paint::Paint(const Paint& paint)
         : SkPaint(paint)
         , mFont(paint.mFont)
+        , mLooper(paint.mLooper)
         , mLetterSpacing(paint.mLetterSpacing)
         , mWordSpacing(paint.mWordSpacing)
         , mFontFeatureSettings(paint.mFontFeatureSettings)
@@ -52,6 +53,7 @@
 Paint& Paint::operator=(const Paint& other) {
     SkPaint::operator=(other);
     mFont = other.mFont;
+    mLooper = other.mLooper;
     mLetterSpacing = other.mLetterSpacing;
     mWordSpacing = other.mWordSpacing;
     mFontFeatureSettings = other.mFontFeatureSettings;
@@ -69,6 +71,7 @@
 bool operator==(const Paint& a, const Paint& b) {
     return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
            a.mFont == b.mFont &&
+           a.mLooper == b.mLooper && 
            a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
            a.mFontFeatureSettings == b.mFontFeatureSettings &&
            a.mMinikinLocaleListId == b.mMinikinLocaleListId &&
@@ -83,6 +86,7 @@
 
     mFont = SkFont();
     mFont.setEdging(SkFont::Edging::kAlias);
+    mLooper.reset();
 
     mStrikeThru = false;
     mUnderline = false;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 38ef131..0db5133 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "SkiaRecordingCanvas.h"
-
+#include "hwui/Paint.h"
 #include <SkImagePriv.h>
 #include "CanvasTransform.h"
 #ifdef __ANDROID__ // Layoutlib does not support Layers
@@ -197,9 +197,37 @@
     return filterPaint(std::move(paint));
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
+static SkDrawLooper* get_looper(const Paint* paint) {
+    return paint ? paint->getLooper() : nullptr;
+}
+
+template <typename Proc>
+void applyLooper(SkDrawLooper* looper, const SkPaint& paint, Proc proc) {
+    if (looper) {
+        SkSTArenaAlloc<256> alloc;
+        SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+        if (ctx) {
+            SkDrawLooper::Context::Info info;
+            for (;;) {
+                SkPaint p = paint;
+                if (!ctx->next(&info, &p)) {
+                    break;
+                }
+                proc(info.fTranslate.fX, info.fTranslate.fY, p);
+            }
+        }
+    } else {
+        proc(0, 0, paint);
+    }
+}
+
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImage(image, left, top, filterBitmap(paint), bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImage(image, left + x, top + y, &p, bitmap.palette());
+    });
+
     // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
     // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
     // when this function ends.
@@ -208,12 +236,16 @@
     }
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
     SkAutoCanvasRestore acr(&mRecorder, true);
     concat(matrix);
 
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImage(image, 0, 0, filterBitmap(paint), bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImage(image, x, y, &p, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
@@ -221,13 +253,17 @@
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                                      float srcBottom, float dstLeft, float dstTop, float dstRight,
-                                     float dstBottom, const SkPaint* paint) {
+                                     float dstBottom, const Paint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
 
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint),
-                            SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), &p,
+                                SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
         !dstRect.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
@@ -236,7 +272,7 @@
 
 void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
                                         float dstTop, float dstRight, float dstBottom,
-                                        const SkPaint* paint) {
+                                        const Paint* paint) {
     SkCanvas::Lattice lattice;
     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
@@ -264,8 +300,11 @@
         filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
     }
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImageLattice(image, lattice, dst, filterBitmap(std::move(filteredPaint)),
-                               bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index c42cea3..bd5274c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -45,14 +45,14 @@
 
     virtual uirenderer::DisplayList* finishRecording() override;
 
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) override;
+                            float dstBottom, const Paint* paint) override;
     virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
                                float dstLeft, float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) override;
+                               const Paint* paint) override;
     virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override;
 
     virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 400196b..c4067af 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <SkImagePriv.h>
+#include "hwui/Paint.h"
 #include "TestSceneBase.h"
 #include "tests/common/BitmapAllocationTestUtils.h"
 #include "utils/Color.h"
@@ -43,7 +44,7 @@
                     skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
                 });
 
-        SkPaint paint;
+        Paint paint;
         sk_sp<SkImage> image = hwuiBitmap->makeImage();
         sk_sp<SkShader> repeatShader =
                 image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 659926b..3d0a2b2 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -65,7 +65,7 @@
         sk_sp<SkShader> compositeShader(
                 SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
 
-        SkPaint paint;
+        Paint paint;
         paint.setShader(std::move(compositeShader));
         canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
     }
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index c6b60aae..a9449b6 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -49,7 +49,7 @@
         SkMatrix matrix;
         matrix.setScale(1, length);
         matrix.postRotate(-90);
-        SkPaint fadingPaint;
+        Paint fadingPaint;
         fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
         fadingPaint.setBlendMode(SkBlendMode::kDstOut);
         canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index fb7e34d..d031923 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -79,7 +79,7 @@
         static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
         static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
         // TODO: switch to using round rect clipping, once merging correctly handles that
-        SkPaint roundRectPaint;
+        Paint roundRectPaint;
         roundRectPaint.setAntiAlias(true);
         roundRectPaint.setColor(Color::White);
         canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 4ff868b..402c1ec 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -28,7 +28,7 @@
     void createContent(int width, int height, Canvas& canvas) override {
         canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
         card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
-            SkPaint paint;
+            Paint paint;
             paint.setAntiAlias(true);
             paint.setColor(Color::Black);
             canvas.drawOval(0, 0, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 6a3b6a5..d5ecfaf 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -41,7 +41,7 @@
                 }
             }
 
-            SkPaint paint;
+            Paint paint;
             paint.setColor(0xff00ffff);
             canvas.drawRegion(region, paint);
         });
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 02dd42f..97bfba3 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -45,7 +45,7 @@
             canvas.save(SaveFlags::MatrixClip);
             canvas.translate(0, 400);
             canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0));  // unclipped
-            SkPaint paint;
+            Paint paint;
             paint.setAntiAlias(true);
             paint.setColor(Color::Green_700);
             canvas.drawCircle(200, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index d189a93..70a1557d 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -30,14 +30,14 @@
     void createContent(int width, int height, Canvas& canvas) override {
         card = TestUtils::createNode(
                 0, 0, width, height, [width](RenderProperties& props, Canvas& canvas) {
-                    std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                    std::function<void(Canvas&, float, const Paint&)> ops[] = {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawOval(0, 0, size, size, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 SkPath diamondPath;
                                 diamondPath.moveTo(size / 2, 0);
                                 diamondPath.lineTo(size, size / 2);
@@ -46,18 +46,18 @@
                                 diamondPath.close();
                                 canvas.drawPath(diamondPath, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float data[] = {0, 0, size, size, 0, size, size, 0};
                                 canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float data[] = {0, 0, size, size, 0, size, size, 0};
                                 canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawRect(0, 0, size, size, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float rad = size / 4;
                                 canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
                             }};
@@ -66,7 +66,7 @@
 
                     // each combination of strokeWidth + style gets a column
                     int outerCount = canvas.save(SaveFlags::MatrixClip);
-                    SkPaint paint;
+                    Paint paint;
                     paint.setAntiAlias(true);
                     SkPaint::Style styles[] = {SkPaint::kStroke_Style, SkPaint::kFill_Style,
                                                SkPaint::kStrokeAndFill_Style};
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index e60bd5f..a0bc5aa 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -52,7 +52,7 @@
         return TestUtils::createNode(
                 x, y, x + width, y + height,
                 [width, height](RenderProperties& props, Canvas& canvas) {
-                    SkPaint paint;
+                    Paint paint;
                     // Simple scale/translate case where R, G, and B are all treated equivalently
                     SkColorMatrix cm;
                     cm.setScale(1.1f, 1.1f, 1.1f, 0.5f);
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 8bd804e..57a260c 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -51,7 +51,7 @@
                 [width, height](RenderProperties& props, Canvas& canvas) {
                     float pos[] = {0, 1};
                     SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
-                    SkPaint paint;
+                    Paint paint;
                     // overdraw several times to emphasize shader cost
                     for (int i = 0; i < 10; i++) {
                         // use i%2 start position to pick 2 color combo with black in it
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index 6f76a50..24d3585 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 #include "RenderNode.h"
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 76f0288..bac8870 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -217,7 +217,7 @@
             std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
                     image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
                     image.get()));
-            SkPaint paint;
+            Paint paint;
             sk_sp<SkColorFilter> filter(
                     SkColorFilters::Blend((curFrame % 150) << 24, SkBlendMode::kSrcATop));
             paint.setColorFilter(filter);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 70423a7..4ce6c32 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -18,6 +18,7 @@
 
 #include "DisplayList.h"
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "tests/common/TestUtils.h"
 
@@ -93,7 +94,7 @@
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
     delete canvas->finishRecording();
 
-    SkPaint rectPaint;
+    Paint rectPaint;
     sk_sp<Bitmap> iconBitmap(TestUtils::createBitmap(80, 80));
 
     while (benchState.KeepRunning()) {
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index e70378b..3632be0 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -24,6 +24,7 @@
 #include "DamageAccumulator.h"
 #include "FatalTestCanvas.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "RecordingCanvas.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
@@ -59,7 +60,7 @@
 namespace {
 
 static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
-    SkPaint paint;
+    Paint paint;
     // order put in blue channel, transparent so overlapped content doesn't get rejected
     paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
     canvas->drawRect(0, 0, 100, 100, paint);
@@ -211,7 +212,7 @@
                 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
                 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
 
-                SkPaint paint;
+                Paint paint;
                 paint.setAntiAlias(true);
                 paint.setColor(SK_ColorGREEN);
                 recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
@@ -291,7 +292,7 @@
                 properties.setTranslationX(SCROLL_X);
                 properties.setTranslationY(SCROLL_Y);
 
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, 100, 100, paint);
             },
@@ -302,7 +303,7 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorDKGRAY);
                 canvas.drawRect(-10, -10, 60, 60, paint);
             },
@@ -310,7 +311,7 @@
     auto child = TestUtils::createSkiaNode(
             0, 50, 100, 100,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorBLUE);
                 canvas.drawRect(0, 0, 100, 50, paint);
                 canvas.drawRenderNode(projectingRipple.get());
@@ -375,14 +376,14 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                SkPaint paint;
+                Paint paint;
                 canvas.drawRect(0, 0, 100, 100, paint);
             },
             "P");
     auto child = TestUtils::createSkiaNode(
             0, 0, 100, 100,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 canvas.drawRect(0, 0, 100, 100, paint);
                 canvas.drawRenderNode(projectingRipple.get());
             },
@@ -483,7 +484,7 @@
                 properties.setTranslationX(SCROLL_X);
                 properties.setTranslationY(SCROLL_Y);
 
-                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
             },
             "B");  // B
     auto projectingRipple = TestUtils::createSkiaNode(
@@ -491,14 +492,14 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                canvas.drawOval(100, 100, 300, 300, SkPaint());  // drawn mostly out of layer bounds
+                canvas.drawOval(100, 100, 300, 300, Paint());  // drawn mostly out of layer bounds
             },
             "R");  // R
     auto child = TestUtils::createSkiaNode(
             100, 100, 300, 300,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 canvas.drawRenderNode(projectingRipple.get());
-                canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
+                canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, Paint());
             },
             "C");  // C
     auto parent = TestUtils::createSkiaNode(
@@ -578,7 +579,7 @@
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectionReceiver(true);
-                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
             },
             "B");  // B
     auto projectingRipple = TestUtils::createSkiaNode(
@@ -591,7 +592,7 @@
                 properties.setTranslationY(SCROLL_Y);
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                canvas.drawOval(0, 0, 200, 200, SkPaint());
+                canvas.drawOval(0, 0, 200, 200, Paint());
             },
             "R");  // R
     auto child = TestUtils::createSkiaNode(
@@ -946,7 +947,7 @@
                                           [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
                                               sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
                                               canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
-                                                              SkPaint());
+                                                              Paint());
                                               canvas.drawBitmap(*bitmap, 10, 10, nullptr);
                                           });
 
@@ -1022,7 +1023,7 @@
 
     auto child = TestUtils::createSkiaNode(
             10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, 100, 100, paint);
             });
@@ -1030,7 +1031,7 @@
     auto parent = TestUtils::createSkiaNode(
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorDKGRAY);
                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
 
@@ -1065,7 +1066,7 @@
     auto layerNode = TestUtils::createSkiaNode(
             0, 0, LAYER_WIDTH, LAYER_HEIGHT,
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                canvas.drawPaint(SkPaint());
+                canvas.drawPaint(Paint());
             });
 
     layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 2ed1b25..fcc64fd 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -16,6 +16,7 @@
 
 #include "tests/common/TestUtils.h"
 
+#include <hwui/Paint.h>
 #include <SkBlurDrawLooper.h>
 #include <SkCanvasStateUtils.h>
 #include <SkPicture.h>
@@ -32,7 +33,7 @@
     // clear to white
     canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
 
-    SkPaint paint;
+    Paint paint;
     // it is transparent to ensure that we still draw the rect since it has a looper
     paint.setColor(SK_ColorTRANSPARENT);
     // this is how view's shadow layers are implemented
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7b76bd8..958baa7 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -23,6 +23,7 @@
 #include "AnimationContext.h"
 #include "DamageAccumulator.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
@@ -96,7 +97,7 @@
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(
             0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
-                SkPaint greenPaint;
+                Paint greenPaint;
                 greenPaint.setColor(SK_ColorGREEN);
                 greenPaint.setStyle(SkPaint::kFill_Style);
                 bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
@@ -294,7 +295,7 @@
     };
 
     std::vector<sp<RenderNode>> nodes;
-    SkPaint transparentPaint;
+    Paint transparentPaint;
     transparentPaint.setAlpha(128);
 
     // backdrop
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 635429d..eec25c6 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -24,6 +24,7 @@
 #include "DamageAccumulator.h"
 #include "FatalTestCanvas.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaPipeline.h"
@@ -60,7 +61,7 @@
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
                 propSetupCallback(props);
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
             });
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index ebf2343..e2fdf2f 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -67,29 +67,6 @@
         return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
     }
 
-    struct TextShadow {
-        SkScalar radius;
-        float dx;
-        float dy;
-        SkColor color;
-    };
-
-    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
-        SkDrawLooper::BlurShadowRec blur;
-        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
-            if (textShadow) {
-                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
-                textShadow->dx = blur.fOffset.fX;
-                textShadow->dy = blur.fOffset.fY;
-                textShadow->color = blur.fColor;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    static inline bool hasTextShadow(const SkPaint* paint) { return getTextShadow(paint, nullptr); }
-
     static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) {
         return paint ? paint->getBlendMode() : SkBlendMode::kSrcOver;
     }