Merge "Replace SkDrawFilter with PaintFilter."

This commit is contained in:
Ben Wagner
2018-07-11 19:36:52 +00:00
committed by Android (Google) Code Review
10 changed files with 222 additions and 152 deletions

View File

@@ -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",

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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();

View File

@@ -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; }

View File

@@ -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

View File

@@ -157,12 +157,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.
@@ -175,10 +208,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());
}
@@ -190,10 +222,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()) {
@@ -225,23 +256,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());
}

View File

@@ -90,44 +90,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