Simplify paint filtering
Removes complication of copy-on-write intermediate class, and
allows for shaing a single applyLooper() function.
Test: make
Bug: 178700363
Change-Id: Ia74cb8e7c650e469b8429de1d7cf9204821d8f11
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1fddac4..28d2b4c 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -188,7 +188,7 @@
}
if (mCanvas->getSaveCount() == restoreCount + 1) {
- SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
+ SkCanvasPriv::DrawBehind(mCanvas, filterPaint(paint));
this->restore();
}
}
@@ -431,15 +431,14 @@
mCanvas->drawColor(color, mode);
}
-SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const {
+void SkiaCanvas::onFilterPaint(SkPaint& paint) {
if (mPaintFilter) {
- mPaintFilter->filter(&paint.writeable());
+ mPaintFilter->filter(&paint);
}
- return std::move(paint);
}
void SkiaCanvas::drawPaint(const SkPaint& paint) {
- mCanvas->drawPaint(*filterPaint(paint));
+ mCanvas->drawPaint(filterPaint(paint));
}
// ----------------------------------------------------------------------------
@@ -457,13 +456,11 @@
points += 2;
}
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawPoints(mode, count, pts.get(), p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoints(mode, count, pts.get(), p); });
}
void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
}
void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
@@ -472,9 +469,8 @@
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawLine(startX, startY, stopX, stopY, p);
- });
+ applyLooper(&paint,
+ [&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); });
}
void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
@@ -484,46 +480,44 @@
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) {
+ applyLooper(&paint, [&](const SkPaint& p) {
mCanvas->drawRect({left, top, right, bottom}, p);
});
}
void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
}
void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawRoundRect(rect, rx, ry, p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); });
}
void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
}
void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
}
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);
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
+ applyLooper(&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 Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
- apply_looper(&paint, [&](const SkPaint& p) {
+ applyLooper(&paint, [&](const SkPaint& p) {
if (fabs(sweepAngle) >= 360.0f) {
mCanvas->drawOval(arc, p);
} else {
@@ -537,13 +531,11 @@
if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
return;
}
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
}
void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawVertices(vertices, mode, p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); });
}
// ----------------------------------------------------------------------------
@@ -552,7 +544,7 @@
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto image = bitmap.makeImage();
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, left, top, sampling, &p);
});
@@ -562,7 +554,7 @@
auto image = bitmap.makeImage();
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, 0, 0, sampling, &p);
});
@@ -575,7 +567,7 @@
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
SkCanvas::kFast_SrcRectConstraint);
@@ -672,11 +664,11 @@
pnt.setShader(image->makeShader(sampling));
auto v = builder.detach();
- apply_looper(&pnt, [&](const SkPaint& p) {
+ applyLooper(&pnt, [&](const SkPaint& p) {
SkPaint copy(p);
auto s = SkSamplingOptions(p.getFilterQuality());
if (s != sampling) {
- // apply_looper changed the quality?
+ // applyLooper changed the quality?
copy.setShader(image->makeShader(s));
}
mCanvas->drawVertices(v, SkBlendMode::kModulate, copy);
@@ -707,7 +699,7 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
auto image = bitmap.makeImage();
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
});
@@ -746,9 +738,7 @@
sk_sp<SkTextBlob> textBlob(builder.make());
- apply_looper(&paintCopy, [&](const SkPaint& p) {
- mCanvas->drawTextBlob(textBlob, 0, 0, p);
- });
+ applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
drawTextDecorations(x, y, totalAdvance, paintCopy);
}
@@ -788,9 +778,7 @@
sk_sp<SkTextBlob> textBlob(builder.make());
- apply_looper(&paintCopy, [&](const SkPaint& p) {
- mCanvas->drawTextBlob(textBlob, 0, 0, p);
- });
+ applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index eac3f22..9ab2b10 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -169,53 +169,24 @@
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
- /** This class acts as a copy on write SkPaint.
- *
- * Initially this will be the SkPaint passed to the contructor.
- * The first time writable() is called this will become a copy of the
- * initial SkPaint (or a default SkPaint if nullptr).
- */
- struct PaintCoW {
- PaintCoW(const SkPaint& that) : mPtr(&that) {}
- PaintCoW(const SkPaint* ptr) : mPtr(ptr) {}
- PaintCoW(const PaintCoW&) = delete;
- PaintCoW(PaintCoW&&) = delete;
- PaintCoW& operator=(const PaintCoW&) = delete;
- PaintCoW& operator=(PaintCoW&&) = delete;
- SkPaint& writeable() {
- if (!mStorage) {
- if (!mPtr) {
- mStorage.emplace();
- } else {
- mStorage.emplace(*mPtr);
- }
- mPtr = &*mStorage;
- }
- return *mStorage;
- }
- operator const SkPaint*() const { return mPtr; }
- const SkPaint* operator->() const { assert(mPtr); return mPtr; }
- explicit operator bool() { return mPtr != nullptr; }
- private:
- const SkPaint* mPtr;
- std::optional<SkPaint> mStorage;
- };
+ void onFilterPaint(SkPaint& paint);
- /** Filters the paint using the current paint filter.
- *
- * @param paint the paint to filter. Will be initialized with the default
- * SkPaint before filtering if filtering is required.
- */
- PaintCoW&& filterPaint(PaintCoW&& paint) const;
+ SkPaint filterPaint(const SkPaint& src) {
+ SkPaint dst(src);
+ this->onFilterPaint(dst);
+ return dst;
+ }
// proc(const SkPaint& modifiedPaint)
- template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
- SkPaint skp;
- BlurDrawLooper* looper = nullptr;
- if (paint) {
- skp = *filterPaint(paint);
- looper = paint->getLooper();
+ template <typename Proc>
+ void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
+ BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
+ const SkPaint* skpPtr = paint;
+ SkPaint skp = skpPtr ? *skpPtr : SkPaint();
+ if (preFilter) {
+ preFilter(skp);
}
+ this->onFilterPaint(skp);
if (looper) {
looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
mCanvas->save();
@@ -228,7 +199,6 @@
}
}
-
private:
struct SaveRec {
int saveCount;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 04e3a1c..af7271e 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -170,36 +170,23 @@
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
- bool fixBlending = false;
- bool fixAA = false;
- if (paint) {
- // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
- // older.
- fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear;
- fixAA = paint->isAntiAlias();
+void SkiaRecordingCanvas::FilterForImage(SkPaint& paint) {
+ // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
+ // older.
+ if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
+ paint.setBlendMode(SkBlendMode::kDstOut);
}
- if (fixBlending || fixAA) {
- SkPaint& tmpPaint = paint.writeable();
-
- if (fixBlending) {
- tmpPaint.setBlendMode(SkBlendMode::kDstOut);
- }
-
- // disabling AA on bitmap draws matches legacy HWUI behavior
- tmpPaint.setAntiAlias(false);
- }
-
- return filterPaint(std::move(paint));
+ // disabling AA on bitmap draws matches legacy HWUI behavior
+ paint.setAntiAlias(false);
}
-static SkFilterMode Paint_to_filter(const SkPaint* paint) {
- return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
- : SkFilterMode::kNearest;
+static SkFilterMode Paint_to_filter(const SkPaint& paint) {
+ return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
+ : SkFilterMode::kNearest;
}
-static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
+static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) {
// Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
}
@@ -207,9 +194,12 @@
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette());
+ },
+ FilterForImage);
// 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
@@ -225,9 +215,12 @@
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette());
+ },
+ FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
@@ -242,10 +235,13 @@
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p),
- p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p,
+ SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+ },
+ FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
!dstRect.isEmpty()) {
@@ -281,10 +277,12 @@
// HWUI always draws 9-patches with linear filtering, regardless of the Paint.
const SkFilterMode filter = SkFilterMode::kLinear;
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p,
- bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImageLattice(image, lattice, dst, filter, &p, bitmap.palette());
+ },
+ FilterForImage);
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 1e404b8..ff03e0c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -87,22 +87,7 @@
std::unique_ptr<SkiaDisplayList> mDisplayList;
StartReorderBarrierDrawable* mCurrentBarrier;
- template <typename Proc>
- void applyLooper(const Paint* paint, Proc proc) {
- SkPaint skp;
- BlurDrawLooper* looper = nullptr;
- if (paint) {
- skp = *filterBitmap(paint);
- looper = paint->getLooper();
- }
- if (looper) {
- looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
- proc(offset.fX, offset.fY, &modifiedPaint);
- });
- } else {
- proc(0, 0, &skp);
- }
- }
+ static void FilterForImage(SkPaint&);
/**
* A new SkiaDisplayList is created or recycled if available.
@@ -113,7 +98,7 @@
*/
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
- PaintCoW&& filterBitmap(PaintCoW&& paint);
+ using INHERITED = SkiaCanvas;
};
} // namespace skiapipeline