diff options
-rw-r--r-- | core/jni/Android.bp | 2 | ||||
-rw-r--r-- | core/jni/android/graphics/PaintFilter.cpp (renamed from core/jni/android/graphics/DrawFilter.cpp) | 59 | ||||
-rw-r--r-- | core/jni/android_graphics_Canvas.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvas.cpp | 111 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvas.h | 60 | ||||
-rw-r--r-- | libs/hwui/hwui/Canvas.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/hwui/Canvas.h | 5 | ||||
-rw-r--r-- | libs/hwui/hwui/PaintFilter.h | 19 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 62 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 39 |
10 files changed, 222 insertions, 152 deletions
diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d4903d80c7e2..94ee0217ea2b 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -126,7 +126,6 @@ cc_library_shared { "android/graphics/Camera.cpp", "android/graphics/CanvasProperty.cpp", "android/graphics/ColorFilter.cpp", - "android/graphics/DrawFilter.cpp", "android/graphics/FontFamily.cpp", "android/graphics/FontUtils.cpp", "android/graphics/CreateJavaOutputStreamAdaptor.cpp", @@ -143,6 +142,7 @@ cc_library_shared { "android/graphics/NinePatch.cpp", "android/graphics/NinePatchPeeker.cpp", "android/graphics/Paint.cpp", + "android/graphics/PaintFilter.cpp", "android/graphics/Path.cpp", "android/graphics/PathMeasure.cpp", "android/graphics/PathEffect.cpp", diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/PaintFilter.cpp index c1dc0dd025b6..182b22b3c917 100644 --- a/core/jni/android/graphics/DrawFilter.cpp +++ b/core/jni/android/graphics/PaintFilter.cpp @@ -15,36 +15,43 @@ ** limitations under the License. */ -// This file was generated from the C++ include file: SkColorFilter.h -// Any changes made to this file will be discarded by the build. -// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, -// or one of the auxilary file specifications in device/tools/gluemaker. - #include "jni.h" #include "GraphicsJNI.h" #include <android_runtime/AndroidRuntime.h> #include "core_jni_helpers.h" -#include "SkDrawFilter.h" -#include "SkPaintFlagsDrawFilter.h" +#include "hwui/PaintFilter.h" #include "SkPaint.h" namespace android { -// Custom version of SkPaintFlagsDrawFilter that also calls setFilterQuality. -class CompatFlagsDrawFilter : public SkPaintFlagsDrawFilter { +class PaintFlagsFilter : public PaintFilter { public: - CompatFlagsDrawFilter(uint32_t clearFlags, uint32_t setFlags, - SkFilterQuality desiredQuality) - : SkPaintFlagsDrawFilter(clearFlags, setFlags) + PaintFlagsFilter(uint32_t clearFlags, uint32_t setFlags) { + fClearFlags = static_cast<uint16_t>(clearFlags & SkPaint::kAllFlags); + fSetFlags = static_cast<uint16_t>(setFlags & SkPaint::kAllFlags); + } + void filter(SkPaint* paint) override { + paint->setFlags((paint->getFlags() & ~fClearFlags) | fSetFlags); + } + +private: + uint16_t fClearFlags; + uint16_t fSetFlags; +}; + +// Custom version of PaintFlagsDrawFilter that also calls setFilterQuality. +class CompatPaintFlagsFilter : public PaintFlagsFilter { +public: + CompatPaintFlagsFilter(uint32_t clearFlags, uint32_t setFlags, SkFilterQuality desiredQuality) + : PaintFlagsFilter(clearFlags, setFlags) , fDesiredQuality(desiredQuality) { } - virtual bool filter(SkPaint* paint, Type type) { - SkPaintFlagsDrawFilter::filter(paint, type); + virtual void filter(SkPaint* paint) { + PaintFlagsFilter::filter(paint); paint->setFilterQuality(fDesiredQuality); - return true; } private: @@ -61,16 +68,16 @@ static inline bool hadFiltering(jint& flags) { return result; } -class SkDrawFilterGlue { +class PaintFilterGlue { public: static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) { - SkDrawFilter* obj = reinterpret_cast<SkDrawFilter*>(objHandle); + PaintFilter* obj = reinterpret_cast<PaintFilter*>(objHandle); SkSafeUnref(obj); } - static jlong CreatePaintFlagsDF(JNIEnv* env, jobject clazz, - jint clearFlags, jint setFlags) { + static jlong CreatePaintFlagsFilter(JNIEnv* env, jobject clazz, + jint clearFlags, jint setFlags) { if (clearFlags | setFlags) { // Mask both groups of flags to remove FILTER_BITMAP_FLAG, which no // longer has a Skia equivalent flag (instead it corresponds to @@ -79,16 +86,16 @@ public: const bool turnFilteringOn = hadFiltering(setFlags); const bool turnFilteringOff = hadFiltering(clearFlags); - SkDrawFilter* filter; + PaintFilter* filter; if (turnFilteringOn) { // Turning filtering on overrides turning it off. - filter = new CompatFlagsDrawFilter(clearFlags, setFlags, + filter = new CompatPaintFlagsFilter(clearFlags, setFlags, kLow_SkFilterQuality); } else if (turnFilteringOff) { - filter = new CompatFlagsDrawFilter(clearFlags, setFlags, + filter = new CompatPaintFlagsFilter(clearFlags, setFlags, kNone_SkFilterQuality); } else { - filter = new SkPaintFlagsDrawFilter(clearFlags, setFlags); + filter = new PaintFlagsFilter(clearFlags, setFlags); } return reinterpret_cast<jlong>(filter); } else { @@ -98,11 +105,11 @@ public: }; static const JNINativeMethod drawfilter_methods[] = { - {"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer} + {"nativeDestructor", "(J)V", (void*) PaintFilterGlue::finalizer} }; static const JNINativeMethod paintflags_methods[] = { - {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF} + {"nativeConstructor","(II)J", (void*) PaintFilterGlue::CreatePaintFlagsFilter} }; int register_android_graphics_DrawFilter(JNIEnv* env) { @@ -110,7 +117,7 @@ int register_android_graphics_DrawFilter(JNIEnv* env) { NELEM(drawfilter_methods)); result |= RegisterMethodsOrDie(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods, NELEM(paintflags_methods)); - + return 0; } diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 484b33f1ca9e..3b024b442060 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -22,13 +22,13 @@ #include <androidfw/ResourceTypes.h> #include <hwui/Canvas.h> #include <hwui/Paint.h> +#include <hwui/PaintFilter.h> #include <hwui/Typeface.h> #include <minikin/Layout.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/ScopedStringChars.h> #include "Bitmap.h" -#include "SkDrawFilter.h" #include "SkGraphics.h" #include "SkRegion.h" #include "SkVertices.h" @@ -582,8 +582,9 @@ static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstri env->ReleaseStringChars(text, jchars); } -static void setDrawFilter(jlong canvasHandle, jlong filterHandle) { - get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); +static void setPaintFilter(jlong canvasHandle, jlong filterHandle) { + PaintFilter* paintFilter = reinterpret_cast<PaintFilter*>(filterHandle); + get_canvas(canvasHandle)->setPaintFilter(sk_ref_sp(paintFilter)); } static void freeCaches(JNIEnv* env, jobject) { @@ -633,7 +634,7 @@ static const JNINativeMethod gMethods[] = { {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect}, {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect}, {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath}, - {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter}, + {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setPaintFilter}, }; // If called from Canvas these are regular JNI diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 7b41f89605d2..17f1a3b4db3c 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -21,6 +21,7 @@ #include "VectorDrawable.h" #include "hwui/Bitmap.h" #include "hwui/MinikinUtils.h" +#include "hwui/PaintFilter.h" #include "pipeline/skia/AnimatedDrawables.h" #include <SkAnimatedImage.h> @@ -28,7 +29,6 @@ #include <SkColorFilter.h> #include <SkColorSpaceXformCanvas.h> #include <SkDeque.h> -#include <SkDrawFilter.h> #include <SkDrawable.h> #include <SkGraphics.h> #include <SkImage.h> @@ -40,6 +40,8 @@ #include <SkTextBlob.h> #include <memory> +#include <optional> +#include <utility> namespace android { @@ -211,7 +213,7 @@ public: Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m) : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {} Clip(const SkPath& path, SkClipOp op, const SkMatrix& m) - : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {} + : mType(Type::Path), mOp(op), mMatrix(m), mPath(std::in_place, path) {} void apply(SkCanvas* canvas) const { canvas->setMatrix(mMatrix); @@ -223,7 +225,7 @@ public: canvas->clipRRect(mRRect, mOp); break; case Type::Path: - canvas->clipPath(*mPath.get(), mOp); + canvas->clipPath(mPath.value(), mOp); break; } } @@ -240,7 +242,7 @@ private: SkMatrix mMatrix; // These are logically a union (tracked separately due to non-POD path). - SkTLazy<SkPath> mPath; + std::optional<SkPath> mPath; SkRRect mRRect; }; @@ -400,12 +402,12 @@ bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) { // Canvas state operations: Filters // ---------------------------------------------------------------------------- -SkDrawFilter* SkiaCanvas::getDrawFilter() { - return mCanvas->getDrawFilter(); +PaintFilter* SkiaCanvas::getPaintFilter() { + return mPaintFilter.get(); } -void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { - mCanvas->setDrawFilter(drawFilter); +void SkiaCanvas::setPaintFilter(sk_sp<PaintFilter> paintFilter) { + mPaintFilter = std::move(paintFilter); } // ---------------------------------------------------------------------------- @@ -439,8 +441,15 @@ void SkiaCanvas::drawColor(int color, SkBlendMode mode) { mCanvas->drawColor(color, mode); } +SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const { + if (mPaintFilter) { + mPaintFilter->filter(&paint.writeable()); + } + return std::move(paint); +} + void SkiaCanvas::drawPaint(const SkPaint& paint) { - mCanvas->drawPaint(paint); + mCanvas->drawPaint(*filterPaint(paint)); } // ---------------------------------------------------------------------------- @@ -457,53 +466,53 @@ void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint pts[i].set(points[0], points[1]); points += 2; } - mCanvas->drawPoints(mode, count, pts.get(), paint); + mCanvas->drawPoints(mode, count, pts.get(), *filterPaint(paint)); } void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { - mCanvas->drawPoint(x, y, paint); + mCanvas->drawPoint(x, y, *filterPaint(paint)); } void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { - this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); + this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kPoints_PointMode); } void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, const SkPaint& paint) { - mCanvas->drawLine(startX, startY, stopX, stopY, paint); + mCanvas->drawLine(startX, startY, stopX, stopY, *filterPaint(paint)); } void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return; - this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); + this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kLines_PointMode); } void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; - mCanvas->drawRect({left, top, right, bottom}, paint); + mCanvas->drawRect({left, top, right, bottom}, *filterPaint(paint)); } void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; - mCanvas->drawRegion(region, paint); + mCanvas->drawRegion(region, *filterPaint(paint)); } void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, const SkPaint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - mCanvas->drawRoundRect(rect, rx, ry, paint); + mCanvas->drawRoundRect(rect, rx, ry, *filterPaint(paint)); } void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return; - mCanvas->drawCircle(x, y, radius, paint); + mCanvas->drawCircle(x, y, radius, *filterPaint(paint)); } void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); - mCanvas->drawOval(oval, paint); + mCanvas->drawOval(oval, *filterPaint(paint)); } void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle, @@ -511,9 +520,9 @@ void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); if (fabs(sweepAngle) >= 360.0f) { - mCanvas->drawOval(arc, paint); + mCanvas->drawOval(arc, *filterPaint(paint)); } else { - mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); + mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, *filterPaint(paint)); } } @@ -522,19 +531,19 @@ void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) { return; } - mCanvas->drawPath(path, paint); + mCanvas->drawPath(path, *filterPaint(paint)); } void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { - mCanvas->drawVertices(vertices, mode, paint); + mCanvas->drawVertices(vertices, mode, *filterPaint(paint)); } // ---------------------------------------------------------------------------- // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, - sk_sp<SkColorFilter> colorSpaceFilter) { +SkiaCanvas::PaintCoW&& SkiaCanvas::filterBitmap(PaintCoW&& paint, + sk_sp<SkColorFilter> colorSpaceFilter) const { /* We don't apply the colorSpace filter if this canvas is already wrapped with * a SkColorSpaceXformCanvas since it already takes care of converting the * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper @@ -542,39 +551,31 @@ const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint * to have a non-sRGB colorspace. */ if (!mCanvasWrapper && colorSpaceFilter) { - if (origPaint) { - *tmpPaint = *origPaint; - } - - if (tmpPaint->getColorFilter()) { - tmpPaint->setColorFilter( - SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter)); - LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter()); + SkPaint& tmpPaint = paint.writeable(); + if (tmpPaint.getColorFilter()) { + tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter(tmpPaint.refColorFilter(), + std::move(colorSpaceFilter))); + LOG_ALWAYS_FATAL_IF(!tmpPaint.getColorFilter()); } else { - tmpPaint->setColorFilter(colorSpaceFilter); + tmpPaint.setColorFilter(std::move(colorSpaceFilter)); } - - return tmpPaint; - } else { - return origPaint; } + return filterPaint(std::move(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter)); + mCanvas->drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter)); + mCanvas->drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, @@ -583,10 +584,9 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter), + mCanvas->drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), SkCanvas::kFast_SrcRectConstraint); } @@ -665,21 +665,20 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, #endif // cons-up a shader for the bitmap - SkPaint tmpPaint; - if (paint) { - tmpPaint = *paint; - } + PaintCoW paintCoW(paint); + SkPaint& tmpPaint = paintCoW.writeable(); sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); if (colorFilter) { - shader = shader->makeWithColorFilter(colorFilter); + shader = shader->makeWithColorFilter(std::move(colorFilter)); } - tmpPaint.setShader(shader); + tmpPaint.setShader(std::move(shader)); - mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint); + mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, + *filterPaint(std::move(paintCoW))); } void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft, @@ -706,10 +705,10 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter)); + mCanvas->drawImageLattice(image.get(), lattice, dst, + filterBitmap(paint, std::move(colorFilter))); } double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) { @@ -732,6 +731,9 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p // glyphs centered or right-aligned; the offset above takes // care of all alignment. SkPaint paintCopy(paint); + if (mPaintFilter) { + mPaintFilter->filter(&paintCopy); + } paintCopy.setTextAlign(SkPaint::kLeft_Align); SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and @@ -760,6 +762,9 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, // glyphs centered or right-aligned; the offsets take care of // that portion of the alignment. SkPaint paintCopy(paint); + if (mPaintFilter) { + mPaintFilter->filter(&paintCopy); + } paintCopy.setTextAlign(SkPaint::kLeft_Align); SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 3efc22a03cdf..24b7ec6d5c7b 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -22,7 +22,9 @@ #include "hwui/Canvas.h" #include <SkCanvas.h> -#include <SkTLazy.h> + +#include <cassert> +#include <optional> namespace android { @@ -87,8 +89,8 @@ public: virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override; virtual bool clipPath(const SkPath* path, SkClipOp op) override; - virtual SkDrawFilter* getDrawFilter() override; - virtual void setDrawFilter(SkDrawFilter* drawFilter) override; + virtual PaintFilter* getPaintFilter() override; + virtual void setPaintFilter(sk_sp<PaintFilter> paintFilter) override; virtual SkCanvasState* captureCanvasState() const override; @@ -158,6 +160,46 @@ protected: const SkPaint& 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; } + const SkPaint& operator*() const { assert(mPtr); return *mPtr; } + explicit operator bool() { return mPtr != nullptr; } + private: + const SkPaint* mPtr; + std::optional<SkPaint> mStorage; + }; + + /** 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; + private: struct SaveRec { int saveCount; @@ -174,8 +216,15 @@ private: void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode); - const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, - sk_sp<SkColorFilter> colorSpaceFilter); + /** Filters the paint for bitmap drawing. + * + * After filtering the paint for bitmap drawing, + * also calls filterPaint on the paint. + * + * @param paint the paint to filter. Will be initialized with the default + * SkPaint before filtering if filtering is required. + */ + PaintCoW&& filterBitmap(PaintCoW&& paint, sk_sp<SkColorFilter> colorSpaceFilter) const; class Clip; @@ -185,6 +234,7 @@ private: // unless it is the same as mCanvasOwned.get() std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. std::vector<Clip> mClipStack; // tracks persistent clips. + sk_sp<PaintFilter> mPaintFilter; }; } // namespace android diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index fb6bd6f0821a..af7f013e27b1 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -23,7 +23,7 @@ #include "Typeface.h" #include "pipeline/skia/SkiaRecordingCanvas.h" -#include <SkDrawFilter.h> +#include "hwui/PaintFilter.h" namespace android { @@ -40,10 +40,10 @@ static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkSca void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { uint32_t flags; - SkDrawFilter* drawFilter = getDrawFilter(); - if (drawFilter) { + PaintFilter* paintFilter = getPaintFilter(); + if (paintFilter) { SkPaint paintCopy(paint); - drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); + paintFilter->filter(&paintCopy); flags = paintCopy.getFlags(); } else { flags = paint.getFlags(); diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 88b12b258419..5d380a68631f 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -39,6 +39,7 @@ enum class Bidi : uint8_t; } namespace android { +class PaintFilter; namespace uirenderer { class CanvasPropertyPaint; @@ -213,8 +214,8 @@ public: virtual bool clipPath(const SkPath* path, SkClipOp op) = 0; // filters - virtual SkDrawFilter* getDrawFilter() = 0; - virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0; + virtual PaintFilter* getPaintFilter() = 0; + virtual void setPaintFilter(sk_sp<PaintFilter> paintFilter) = 0; // WebView only virtual SkCanvasState* captureCanvasState() const { return nullptr; } diff --git a/libs/hwui/hwui/PaintFilter.h b/libs/hwui/hwui/PaintFilter.h new file mode 100644 index 000000000000..bf5627eac229 --- /dev/null +++ b/libs/hwui/hwui/PaintFilter.h @@ -0,0 +1,19 @@ +#ifndef ANDROID_GRAPHICS_PAINT_FILTER_H_ +#define ANDROID_GRAPHICS_PAINT_FILTER_H_ + +class SkPaint; + +namespace android { + +class PaintFilter : public SkRefCnt { +public: + /** + * Called with the paint that will be used to draw. + * The implementation may modify the paint as they wish. + */ + virtual void filter(SkPaint*) = 0; +}; + +} // namespace android + +#endif diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index f0da660f17b0..b9fe885ff6ca 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -148,12 +148,45 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { // Recording Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- +SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, + sk_sp<SkColorFilter> colorSpaceFilter) { + 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(); + } + + if (fixBlending || fixAA || colorSpaceFilter) { + SkPaint& tmpPaint = paint.writeable(); + + if (fixBlending) { + tmpPaint.setBlendMode(SkBlendMode::kDstOut); + } + + if (colorSpaceFilter) { + if (tmpPaint.getColorFilter()) { + tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter( + tmpPaint.refColorFilter(), std::move(colorSpaceFilter))); + } else { + tmpPaint.setColorFilter(std::move(colorSpaceFilter)); + } + LOG_ALWAYS_FATAL_IF(!tmpPaint.getColorFilter()); + } + + // disabling AA on bitmap draws matches legacy HWUI behavior + tmpPaint.setAntiAlias(false); + } + + return filterPaint(std::move(paint)); +} void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter)); + mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); // 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. @@ -166,10 +199,9 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter)); + mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } @@ -181,10 +213,9 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - SkPaint tmpPaint; sk_sp<SkColorFilter> colorFilter; sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter), + mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), SkCanvas::kFast_SrcRectConstraint); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { @@ -216,23 +247,16 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - SkPaint tmpPaint; - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - const SkPaint* filteredPaint = bitmapPaint(paint, &tmpPaint, colorFilter); + PaintCoW filteredPaint(paint); // Besides kNone, the other three SkFilterQualities are treated the same. And Android's // Java API only supports kLow and kNone anyway. if (!filteredPaint || filteredPaint->getFilterQuality() == kNone_SkFilterQuality) { - if (filteredPaint != &tmpPaint) { - if (paint) { - tmpPaint = *paint; - } - filteredPaint = &tmpPaint; - } - tmpPaint.setFilterQuality(kLow_SkFilterQuality); + filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } - - mRecorder.drawImageLattice(image.get(), lattice, dst, filteredPaint); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImageLattice(image.get(), lattice, dst, + filterBitmap(std::move(filteredPaint), std::move(colorFilter))); 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 93807a5476e6..ae7fdf8c6d7b 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -89,44 +89,7 @@ private: */ void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height); - inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint, - sk_sp<SkColorFilter> colorSpaceFilter) { - bool fixBlending = false; - bool fixAA = false; - if (origPaint) { - // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and - // older. - fixBlending = sApiLevel <= 27 && origPaint->getBlendMode() == SkBlendMode::kClear; - fixAA = origPaint->isAntiAlias(); - } - - if (fixBlending || fixAA || colorSpaceFilter) { - if (origPaint) { - *tmpPaint = *origPaint; - } - - if (fixBlending) { - tmpPaint->setBlendMode(SkBlendMode::kDstOut); - } - - if (colorSpaceFilter) { - if (tmpPaint->getColorFilter()) { - tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter( - tmpPaint->refColorFilter(), colorSpaceFilter)); - } else { - tmpPaint->setColorFilter(colorSpaceFilter); - } - LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter()); - } - - // disabling AA on bitmap draws matches legacy HWUI behavior - tmpPaint->setAntiAlias(false); - return tmpPaint; - } else { - return origPaint; - } - } - + PaintCoW&& filterBitmap(PaintCoW&& paint, sk_sp<SkColorFilter> colorSpaceFilter); }; }; // namespace skiapipeline |