Just pass color glyph masks to filters.

Allow the filters to try to apply themselves to the color mask. Most
mask filters will just return false, but allow them the opprotunity.
This removes the behavior of trying to create a mask from the color
mask.

This updates the blur mask filter to handle kARGB32_Format directly by
using just the alpha (which mirrors current behavior).

Change-Id: I15eb736060ecf9b24aca874758c167b74d9ebc22
Reviewed-on: https://skia-review.googlesource.com/124185
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2018-04-25 15:27:40 -04:00 committed by Skia Commit-Bot
parent 34a388edbd
commit 275df2e873
7 changed files with 110 additions and 175 deletions

View File

@ -97,8 +97,7 @@ void SkMask_FreeImage(uint8_t* image) {
bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, SkScalar sigma, SkBlurStyle style, bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, SkScalar sigma, SkBlurStyle style,
SkIPoint* margin) { SkIPoint* margin) {
if (src.fFormat != SkMask::kA8_Format && src.fFormat != SkMask::kARGB32_Format) {
if (src.fFormat != SkMask::kA8_Format) {
return false; return false;
} }

View File

@ -17,43 +17,7 @@
static const double kPi = 3.14159265358979323846264338327950288; static const double kPi = 3.14159265358979323846264338327950288;
class BlurScanInterface { class PlanGauss final {
public:
virtual ~BlurScanInterface() = default;
virtual void blur(const uint8_t* src, int srcStride, const uint8_t* srcEnd,
uint8_t* dst, int dstStride, uint8_t* dstEnd) const = 0;
virtual bool canBlur4() { return false; }
virtual void blur4Transpose(
const uint8_t* src, int srcStride, const uint8_t* srcEnd,
uint8_t* dst, int dstStride, uint8_t* dstEnd) const {
SK_ABORT("This should not be called.");
}
};
class PlanningInterface {
public:
virtual ~PlanningInterface() = default;
virtual size_t bufferSize() const = 0;
virtual int border() const = 0;
virtual bool needsBlur() const = 0;
virtual BlurScanInterface* makeBlurScan(
SkArenaAlloc* alloc, int width, uint32_t* buffer) const = 0;
};
class None final : public PlanningInterface {
public:
None() = default;
size_t bufferSize() const override { return 0; }
int border() const override { return 0; }
bool needsBlur() const override { return false; }
BlurScanInterface* makeBlurScan(
SkArenaAlloc* alloc, int width, uint32_t* buffer) const override {
SK_ABORT("Should never be called.");
return nullptr;
}
};
class PlanGauss final : public PlanningInterface {
public: public:
explicit PlanGauss(double sigma) { explicit PlanGauss(double sigma) {
auto possibleWindow = static_cast<int>(floor(sigma * 3 * sqrt(2 * kPi) / 4 + 0.5)); auto possibleWindow = static_cast<int>(floor(sigma * 3 * sqrt(2 * kPi) / 4 + 0.5));
@ -117,36 +81,17 @@ public:
fWeight = static_cast<uint64_t>(round(1.0 / divisor * (1ull << 32))); fWeight = static_cast<uint64_t>(round(1.0 / divisor * (1ull << 32)));
} }
size_t bufferSize() const override { return fPass0Size + fPass1Size + fPass2Size; } size_t bufferSize() const { return fPass0Size + fPass1Size + fPass2Size; }
int border() const override { return fBorder; } int border() const { return fBorder; }
bool needsBlur() const override { return true; }
BlurScanInterface* makeBlurScan(
SkArenaAlloc* alloc, int width, uint32_t* buffer) const override
{
uint32_t* buffer0, *buffer0End, *buffer1, *buffer1End, *buffer2, *buffer2End;
buffer0 = buffer;
buffer0End = buffer1 = buffer0 + fPass0Size;
buffer1End = buffer2 = buffer1 + fPass1Size;
buffer2End = buffer2 + fPass2Size;
int noChangeCount = fSlidingWindow > width ? fSlidingWindow - width : 0;
return alloc->make<Gauss>(
fWeight, noChangeCount,
buffer0, buffer0End,
buffer1, buffer1End,
buffer2, buffer2End);
}
public: public:
class Gauss final : public BlurScanInterface { class Scan {
public: public:
Gauss(uint64_t weight, int noChangeCount, Scan(uint64_t weight, int noChangeCount,
uint32_t* buffer0, uint32_t* buffer0End, uint32_t* buffer0, uint32_t* buffer0End,
uint32_t* buffer1, uint32_t* buffer1End, uint32_t* buffer1, uint32_t* buffer1End,
uint32_t* buffer2, uint32_t* buffer2End) uint32_t* buffer2, uint32_t* buffer2End)
: fWeight{weight} : fWeight{weight}
, fNoChangeCount{noChangeCount} , fNoChangeCount{noChangeCount}
, fBuffer0{buffer0} , fBuffer0{buffer0}
@ -158,7 +103,7 @@ public:
{ } { }
void blur(const uint8_t* src, int srcStride, const uint8_t* srcEnd, void blur(const uint8_t* src, int srcStride, const uint8_t* srcEnd,
uint8_t* dst, int dstStride, uint8_t* dstEnd) const override { uint8_t* dst, int dstStride, uint8_t* dstEnd) const {
auto buffer0Cursor = fBuffer0; auto buffer0Cursor = fBuffer0;
auto buffer1Cursor = fBuffer1; auto buffer1Cursor = fBuffer1;
auto buffer2Cursor = fBuffer2; auto buffer2Cursor = fBuffer2;
@ -264,6 +209,21 @@ public:
uint32_t* fBuffer2End; uint32_t* fBuffer2End;
}; };
Scan makeBlurScan(int width, uint32_t* buffer) const {
uint32_t* buffer0, *buffer0End, *buffer1, *buffer1End, *buffer2, *buffer2End;
buffer0 = buffer;
buffer0End = buffer1 = buffer0 + fPass0Size;
buffer1End = buffer2 = buffer1 + fPass1Size;
buffer2End = buffer2 + fPass2Size;
int noChangeCount = fSlidingWindow > width ? fSlidingWindow - width : 0;
return Scan(
fWeight, noChangeCount,
buffer0, buffer0End,
buffer1, buffer1End,
buffer2, buffer2End);
}
uint64_t fWeight; uint64_t fWeight;
int fBorder; int fBorder;
int fSlidingWindow; int fSlidingWindow;
@ -325,12 +285,13 @@ static SkMask prepare_destination(int radiusX, int radiusY, const SkMask& src) {
static constexpr uint16_t _____ = 0u; static constexpr uint16_t _____ = 0u;
static constexpr uint16_t kHalf = 0x80u; static constexpr uint16_t kHalf = 0x80u;
static SK_ALWAYS_INLINE Sk8h load(const uint8_t* from, int width) { static SK_ALWAYS_INLINE Sk8h load(const uint8_t* from, int width, int stride) {
SkASSERT(0 < width && width <= 8);
uint8_t buffer[8]; uint8_t buffer[8];
if (width < 8) { if (width < 8 || stride != 1) {
sk_bzero(buffer, sizeof(buffer)); sk_bzero(buffer, sizeof(buffer));
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
buffer[i] = from[i]; buffer[i] = from[i * stride];
} }
from = buffer; from = buffer;
} }
@ -580,7 +541,7 @@ static SK_ALWAYS_INLINE void blur_row(
// Go by multiples of 8 in src. // Go by multiples of 8 in src.
int x = 0; int x = 0;
for (; x <= srcW - 8; x += 8) { for (; x <= srcW - 8; x += 8) {
blur(load(src, 8), g0, g1, g2, g3, g4, &d0, &d8); blur(load(src, 8, 1), g0, g1, g2, g3, g4, &d0, &d8);
store(dst, d0, 8); store(dst, d0, 8);
@ -595,7 +556,7 @@ static SK_ALWAYS_INLINE void blur_row(
int srcTail = srcW - x; int srcTail = srcW - x;
if (srcTail > 0) { if (srcTail > 0) {
blur(load(src, srcTail), g0, g1, g2, g3, g4, &d0, &d8); blur(load(src, srcTail, 1), g0, g1, g2, g3, g4, &d0, &d8);
int dstTail = std::min(8, dstW - x); int dstTail = std::min(8, dstW - x);
store(dst, d0, dstTail); store(dst, d0, dstTail);
@ -790,26 +751,26 @@ using BlurY = decltype(blur_y_radius_1);
static SK_ALWAYS_INLINE void blur_column( static SK_ALWAYS_INLINE void blur_column(
BlurY blur, int radius, int width, BlurY blur, int radius, int width,
const Sk8h& g0, const Sk8h& g1, const Sk8h& g2, const Sk8h& g3, const Sk8h& g4, const Sk8h& g0, const Sk8h& g1, const Sk8h& g2, const Sk8h& g3, const Sk8h& g4,
const uint8_t* src, size_t srcStride, int srcH, const uint8_t* src, size_t srcRB, int srcStride, int srcH,
uint8_t* dst, size_t dstStride) { uint8_t* dst, size_t dstRB) {
Sk8h d01{kHalf}, d12{kHalf}, d23{kHalf}, d34{kHalf}, Sk8h d01{kHalf}, d12{kHalf}, d23{kHalf}, d34{kHalf},
d45{kHalf}, d56{kHalf}, d67{kHalf}, d78{kHalf}; d45{kHalf}, d56{kHalf}, d67{kHalf}, d78{kHalf};
auto flush = [&](uint8_t* to, const Sk8h& v0, const Sk8h& v1) { auto flush = [&](uint8_t* to, const Sk8h& v0, const Sk8h& v1) {
store(to, v0, width); store(to, v0, width);
to += dstStride; to += dstRB;
store(to, v1, width); store(to, v1, width);
return to + dstStride; return to + dstRB;
}; };
for (int y = 0; y < srcH; y += 1) { for (int y = 0; y < srcH; y += 1) {
auto s = load(src, width); auto s = load(src, width, srcStride);
auto b = blur(s, auto b = blur(s,
g0, g1, g2, g3, g4, g0, g1, g2, g3, g4,
&d01, &d12, &d23, &d34, &d45, &d56, &d67, &d78); &d01, &d12, &d23, &d34, &d45, &d56, &d67, &d78);
store(dst, b, width); store(dst, b, width);
src += srcStride; src += srcRB;
dst += dstStride; dst += dstRB;
} }
if (radius >= 1) { if (radius >= 1) {
@ -829,8 +790,8 @@ static SK_ALWAYS_INLINE void blur_column(
// BlurY will be one of blur_y_radius_(1|2|3|4). // BlurY will be one of blur_y_radius_(1|2|3|4).
static SK_ALWAYS_INLINE void blur_y_rect( static SK_ALWAYS_INLINE void blur_y_rect(
BlurY blur, int radius, uint16_t *gauss, BlurY blur, int radius, uint16_t *gauss,
const uint8_t *src, size_t srcStride, int srcW, int srcH, const uint8_t *src, size_t srcRB, int srcStride, int srcW, int srcH,
uint8_t *dst, size_t dstStride) { uint8_t *dst, size_t dstRB) {
Sk8h g0{gauss[0]}, Sk8h g0{gauss[0]},
g1{gauss[1]}, g1{gauss[1]},
@ -842,9 +803,9 @@ static SK_ALWAYS_INLINE void blur_y_rect(
for (; x <= srcW - 8; x += 8) { for (; x <= srcW - 8; x += 8) {
blur_column(blur, radius, 8, blur_column(blur, radius, 8,
g0, g1, g2, g3, g4, g0, g1, g2, g3, g4,
src, srcStride, srcH, src, srcRB, srcStride, srcH,
dst, dstStride); dst, dstRB);
src += 8; src += 8 * srcStride;
dst += 8; dst += 8;
} }
@ -852,39 +813,39 @@ static SK_ALWAYS_INLINE void blur_y_rect(
if (xTail > 0) { if (xTail > 0) {
blur_column(blur, radius, xTail, blur_column(blur, radius, xTail,
g0, g1, g2, g3, g4, g0, g1, g2, g3, g4,
src, srcStride, srcH, src, srcRB, srcStride, srcH,
dst, dstStride); dst, dstRB);
} }
} }
SK_ATTRIBUTE(noinline) static void direct_blur_y( SK_ATTRIBUTE(noinline) static void direct_blur_y(
int radius, uint16_t* gauss, int radius, uint16_t* gauss,
const uint8_t* src, size_t srcStride, int srcW, int srcH, const uint8_t* src, size_t srcRB, int srcStride, int srcW, int srcH,
uint8_t* dst, size_t dstStride) { uint8_t* dst, size_t dstRB) {
switch (radius) { switch (radius) {
case 1: case 1:
blur_y_rect(blur_y_radius_1, 1, gauss, blur_y_rect(blur_y_radius_1, 1, gauss,
src, srcStride, srcW, srcH, src, srcRB, srcStride, srcW, srcH,
dst, dstStride); dst, dstRB);
break; break;
case 2: case 2:
blur_y_rect(blur_y_radius_2, 2, gauss, blur_y_rect(blur_y_radius_2, 2, gauss,
src, srcStride, srcW, srcH, src, srcRB, srcStride, srcW, srcH,
dst, dstStride); dst, dstRB);
break; break;
case 3: case 3:
blur_y_rect(blur_y_radius_3, 3, gauss, blur_y_rect(blur_y_radius_3, 3, gauss,
src, srcStride, srcW, srcH, src, srcRB, srcStride, srcW, srcH,
dst, dstStride); dst, dstRB);
break; break;
case 4: case 4:
blur_y_rect(blur_y_radius_4, 4, gauss, blur_y_rect(blur_y_radius_4, 4, gauss,
src, srcStride, srcW, srcH, src, srcRB, srcStride, srcW, srcH,
dst, dstStride); dst, dstRB);
break; break;
default: default:
@ -932,20 +893,27 @@ static SkIPoint small_blur(double sigmaX, double sigmaY, const SkMask& src, SkMa
int dstW = dst->fBounds.width(), int dstW = dst->fBounds.width(),
dstH = dst->fBounds.height(); dstH = dst->fBounds.height();
size_t srcStride = src.fRowBytes, size_t srcRB = src.fRowBytes,
dstStride = dst->fRowBytes; dstRB = dst->fRowBytes;
//TODO: handle bluring in only one direction. //TODO: handle bluring in only one direction.
int srcStride = 1;
int srcAlphaOffset = 0;
if (src.fFormat == SkMask::kARGB32_Format) {
srcStride = 4;
srcAlphaOffset = SK_A32_SHIFT / 8;
}
// Blur vertically and copy to destination. // Blur vertically and copy to destination.
direct_blur_y(radiusY, gaussFactorsY, direct_blur_y(radiusY, gaussFactorsY,
src.fImage, srcStride, srcW, srcH, src.fImage + srcAlphaOffset, srcRB, srcStride, srcW, srcH,
dst->fImage + radiusX, dstStride); dst->fImage + radiusX, dstRB);
// Blur horizontally in place. // Blur horizontally in place.
direct_blur_x(radiusX, gaussFactorsX, direct_blur_x(radiusX, gaussFactorsX,
dst->fImage + radiusX, dstStride, srcW, dst->fImage + radiusX, dstRB, srcW,
dst->fImage, dstStride, dstW, dstH); dst->fImage, dstRB, dstW, dstH);
return {radiusX, radiusY}; return {radiusX, radiusY};
} }
@ -961,11 +929,11 @@ SkIPoint SkMaskBlurFilter::blur(const SkMask& src, SkMask* dst) const {
// 1024 is a place holder guess until more analysis can be done. // 1024 is a place holder guess until more analysis can be done.
SkSTArenaAlloc<1024> alloc; SkSTArenaAlloc<1024> alloc;
PlanningInterface* planW = alloc.make<PlanGauss>(fSigmaW); PlanGauss planW(fSigmaW);
PlanningInterface* planH = alloc.make<PlanGauss>(fSigmaH); PlanGauss planH(fSigmaH);
int borderW = planW->border(), int borderW = planW.border(),
borderH = planH->border(); borderH = planH.border();
SkASSERT(borderH >= 0 && borderW >= 0); SkASSERT(borderH >= 0 && borderW >= 0);
*dst = prepare_destination(borderW, borderH, src); *dst = prepare_destination(borderW, borderH, src);
@ -983,41 +951,40 @@ SkIPoint SkMaskBlurFilter::blur(const SkMask& src, SkMask* dst) const {
dstH = dst->fBounds.height(); dstH = dst->fBounds.height();
SkASSERT(srcW >= 0 && srcH >= 0 && dstW >= 0 && dstH >= 0); SkASSERT(srcW >= 0 && srcH >= 0 && dstW >= 0 && dstH >= 0);
auto bufferSize = std::max(planW->bufferSize(), planH->bufferSize()); auto bufferSize = std::max(planW.bufferSize(), planH.bufferSize());
auto buffer = alloc.makeArrayDefault<uint32_t>(bufferSize); auto buffer = alloc.makeArrayDefault<uint32_t>(bufferSize);
if (planW->needsBlur() && planH->needsBlur()) { // Blur both directions.
// Blur both directions. int tmpW = srcH,
int tmpW = srcH, tmpH = dstW;
tmpH = dstW;
auto tmp = alloc.makeArrayDefault<uint8_t>(tmpW * tmpH); auto tmp = alloc.makeArrayDefault<uint8_t>(tmpW * tmpH);
// Blur horizontally, and transpose. int srcStride = 1;
auto scanW = planW->makeBlurScan(&alloc, srcW, buffer); int srcAlphaOffset = 0;
for (int y = 0; y < srcH; y++) { if (src.fFormat == SkMask::kARGB32_Format) {
auto srcStart = &src.fImage[y * src.fRowBytes]; srcStride = 4;
auto tmpStart = &tmp[y]; srcAlphaOffset = SK_A32_SHIFT / 8;
scanW->blur(srcStart, 1, srcStart + srcW, }
tmpStart, tmpW, tmpStart + tmpW * tmpH);
}
// Blur vertically (scan in memory order because of the transposition), // Blur horizontally, and transpose.
// and transpose back to the original orientation. const PlanGauss::Scan& scanW = planW.makeBlurScan(srcW, buffer);
auto scanH = planH->makeBlurScan(&alloc, tmpW, buffer); for (int y = 0; y < srcH; y++) {
for (int y = 0; y < tmpH; y++) { auto srcStart = &src.fImage[y * src.fRowBytes] + srcAlphaOffset;
auto tmpStart = &tmp[y * tmpW]; auto tmpStart = &tmp[y];
auto dstStart = &dst->fImage[y]; scanW.blur(srcStart, srcStride, srcStart + srcW * srcStride,
tmpStart, tmpW, tmpStart + tmpW * tmpH);
}
scanH->blur(tmpStart, 1, tmpStart + tmpW, // Blur vertically (scan in memory order because of the transposition),
dstStart, dst->fRowBytes, dstStart + dst->fRowBytes * dstH); // and transpose back to the original orientation.
} const PlanGauss::Scan& scanH = planH.makeBlurScan(tmpW, buffer);
} else { for (int y = 0; y < tmpH; y++) {
// Copy to dst. No Blur. auto tmpStart = &tmp[y * tmpW];
SkASSERT(false); // should not get here auto dstStart = &dst->fImage[y];
for (int y = 0; y < srcH; y++) {
std::memcpy(&dst->fImage[y * dst->fRowBytes], &src.fImage[y * src.fRowBytes], dstW); scanH.blur(tmpStart, 1, tmpStart + tmpW,
} dstStart, dst->fRowBytes, dstStart + dst->fRowBytes * dstH);
} }
return {SkTo<int32_t>(borderW), SkTo<int32_t>(borderH)}; return {SkTo<int32_t>(borderW), SkTo<int32_t>(borderH)};

View File

@ -34,11 +34,6 @@ SkMaskFilterBase::NinePatch::~NinePatch() {
} }
} }
bool SkMaskFilterBase::filterMask(SkMask*, const SkMask&, const SkMatrix&,
SkIPoint*) const {
return false;
}
bool SkMaskFilterBase::asABlur(BlurRec*) const { bool SkMaskFilterBase::asABlur(BlurRec*) const {
return false; return false;
} }

View File

@ -54,7 +54,7 @@ public:
@return true if the dst mask was correctly created. @return true if the dst mask was correctly created.
*/ */
virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
SkIPoint* margin) const; SkIPoint* margin) const = 0;
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
/** /**

View File

@ -130,7 +130,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
} }
// If we are going to create the mask, then we cannot keep the color // If we are going to create the mask, then we cannot keep the color
if ((generatingImageFromPath || fMaskFilter) && SkMask::kARGB32_Format == glyph->fMaskFormat) { if (generatingImageFromPath && SkMask::kARGB32_Format == glyph->fMaskFormat) {
glyph->fMaskFormat = SkMask::kA8_Format; glyph->fMaskFormat = SkMask::kA8_Format;
} }
@ -382,26 +382,6 @@ static void generateMask(const SkMask& mask, const SkPath& path,
} }
} }
static void extract_alpha(const SkMask& dst,
const SkPMColor* srcRow, size_t srcRB) {
int width = dst.fBounds.width();
int height = dst.fBounds.height();
int dstRB = dst.fRowBytes;
uint8_t* dstRow = dst.fImage;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
dstRow[x] = SkGetPackedA32(srcRow[x]);
}
// zero any padding on each row
for (int x = width; x < dstRB; ++x) {
dstRow[x] = 0;
}
dstRow += dstRB;
srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
}
}
void SkScalerContext::getImage(const SkGlyph& origGlyph) { void SkScalerContext::getImage(const SkGlyph& origGlyph) {
const SkGlyph* glyph = &origGlyph; const SkGlyph* glyph = &origGlyph;
SkGlyph tmpGlyph; SkGlyph tmpGlyph;
@ -456,19 +436,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
// the src glyph image shouldn't be 3D // the src glyph image shouldn't be 3D
SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
SkAutoSMalloc<32*32> a8storage;
glyph->toMask(&srcM); glyph->toMask(&srcM);
if (SkMask::kARGB32_Format == srcM.fFormat) {
// now we need to extract the alpha-channel from the glyph's image
// and copy it into a temp buffer, and then point srcM at that temp.
srcM.fFormat = SkMask::kA8_Format;
srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
size_t size = srcM.computeImageSize();
a8storage.reset(size);
srcM.fImage = (uint8_t*)a8storage.get();
extract_alpha(srcM,
(const SkPMColor*)glyph->fImage, glyph->rowBytes());
}
fRec.getMatrixFrom2x2(&matrix); fRec.getMatrixFrom2x2(&matrix);
@ -496,7 +464,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
} }
SkMask::FreeImage(dstM.fImage); SkMask::FreeImage(dstM.fImage);
if (fPreBlendForFilter.isApplicable()) { if (SkMask::kA8_Format == dstM.fFormat && fPreBlendForFilter.isApplicable()) {
applyLUTToA8Mask(srcM, fPreBlendForFilter.fG); applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
} }
} }

View File

@ -72,6 +72,10 @@ SkMask::Format SkEmbossMaskFilter::getFormat() const {
bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
const SkMatrix& matrix, SkIPoint* margin) const { const SkMatrix& matrix, SkIPoint* margin) const {
if (src.fFormat != SkMask::kA8_Format) {
return false;
}
SkScalar sigma = matrix.mapRadius(fBlurSigma); SkScalar sigma = matrix.mapRadius(fBlurSigma);
if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle)) { if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle)) {

View File

@ -70,7 +70,9 @@ static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm, bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
SkIPoint* margin) const { SkIPoint* margin) const {
SkASSERT(src.fFormat == SkMask::kA8_Format); if (src.fFormat != SkMask::kA8_Format) {
return false;
}
if (margin) { if (margin) {
margin->set(0, 0); margin->set(0, 0);