Alloc glyph image correctly for SkMask::k3D_Format.

This removes the no longer used outside Skia
SK_SUPPORT_LEGACY_EMBOSSMASKFILTER define, and either deletes the code
it guards or updates it to use the new emboss mask filter factory. This
re-enables the code to test the emboss mask filter. Also added is a test
to ensure that embossed text is drawn correctly, as before this glyphs
did not allocate the proper amount of memory for the k3D_Format which
this mask filter produces. This also fixes SkEmbossMask::Emboss to write
the whole of the mul and add planes to avoid pixel differences and
MemorySanitizer errors.

Change-Id: Ib492c72a19d6a27d140e3cd48179a3ca9ce313f5
Reviewed-on: https://skia-review.googlesource.com/70260
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
Ben Wagner 2017-11-10 16:24:50 -05:00 committed by Skia Commit-Bot
parent 0030c5ed3c
commit 6b26deb8d6
8 changed files with 93 additions and 97 deletions

View File

@ -6,11 +6,11 @@
*/ */
#include "gm.h" #include "gm.h"
#include "SkBlurMaskFilter.h" #include "SkBlurMask.h"
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkColorFilter.h" #include "SkColorFilter.h"
#include "SkEmbossMaskFilter.h"
#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
static SkBitmap make_bm() { static SkBitmap make_bm() {
SkBitmap bm; SkBitmap bm;
bm.allocN32Pixels(100, 100); bm.allocN32Pixels(100, 100);
@ -41,17 +41,36 @@ protected:
SkPaint paint; SkPaint paint;
SkBitmap bm = make_bm(); SkBitmap bm = make_bm();
canvas->drawBitmap(bm, 10, 10, &paint); canvas->drawBitmap(bm, 10, 10, &paint);
const SkScalar dir[] = { 1, 1, 1 };
paint.setMaskFilter(SkBlurMaskFilter::MakeEmboss(3, dir, 0.3f, 0.1f));
canvas->translate(bm.width() + SkIntToScalar(10), 0); canvas->translate(bm.width() + SkIntToScalar(10), 0);
paint.setMaskFilter(SkEmbossMaskFilter::Make(
SkBlurMask::ConvertRadiusToSigma(3),
{ { SK_Scalar1, SK_Scalar1, SK_Scalar1 }, 0, 128, 16*2 }));
canvas->drawBitmap(bm, 10, 10, &paint); canvas->drawBitmap(bm, 10, 10, &paint);
canvas->translate(bm.width() + SkIntToScalar(10), 0);
// this combination of emboss+colorfilter used to crash -- so we exercise it to // this combination of emboss+colorfilter used to crash -- so we exercise it to
// confirm that we have a fix. // confirm that we have a fix.
paint.setColorFilter(SkColorFilter::MakeModeFilter(0xFFFF0000, SkBlendMode::kSrcATop)); paint.setColorFilter(SkColorFilter::MakeModeFilter(0xFFFF0000, SkBlendMode::kSrcATop));
canvas->translate(bm.width() + SkIntToScalar(10), 0);
canvas->drawBitmap(bm, 10, 10, &paint); canvas->drawBitmap(bm, 10, 10, &paint);
canvas->translate(bm.width() + SkIntToScalar(10), 0);
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(10));
paint.setMaskFilter(SkEmbossMaskFilter::Make(
SkBlurMask::ConvertRadiusToSigma(4),
{ { SK_Scalar1, SK_Scalar1, SK_Scalar1 }, 0, 128, 16*2 }));
paint.setColorFilter(nullptr);
paint.setShader(SkShader::MakeColorShader(SK_ColorBLUE));
paint.setDither(true);
canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
SkIntToScalar(30), paint);
canvas->translate(SkIntToScalar(100), 0);
paint.setStyle(SkPaint::kFill_Style);
paint.setTextSize(50);
canvas->drawText("Hello", 5, 0, 50, paint);
} }
private: private:
@ -59,4 +78,3 @@ private:
}; };
DEF_GM(return new EmbossGM;) DEF_GM(return new EmbossGM;)
#endif

View File

@ -48,19 +48,6 @@ public:
return Make(style, sigma, SkRect::MakeEmpty(), flags); return Make(style, sigma, SkRect::MakeEmpty(), flags);
} }
#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
/** Create an emboss maskfilter
@param blurSigma standard deviation of the Gaussian blur to apply
before applying lighting (e.g. 3)
@param direction array of 3 scalars [x, y, z] specifying the direction of the light source
@param ambient 0...1 amount of ambient light
@param specular coefficient for specular highlights (e.g. 8)
@return the emboss maskfilter
*/
static sk_sp<SkMaskFilter> MakeEmboss(SkScalar blurSigma, const SkScalar direction[3],
SkScalar ambient, SkScalar specular);
#endif
static const int kMaxDivisions = 6; static const int kMaxDivisions = 6;
// This method computes all the parameters for drawing a partially occluded nine-patched // This method computes all the parameters for drawing a partially occluded nine-patched

View File

@ -208,13 +208,10 @@ static void apply_shader(SkPaint* paint, int index) {
paint->setRasterizer(rastBuilder.detach()); paint->setRasterizer(rastBuilder.detach());
} }
#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER paint->setMaskFilter(SkEmbossMaskFilter::Make(
SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 }; SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)),
paint->setMaskFilter(SkBlurMaskFilter::MakeEmboss( { { SK_Scalar1, SK_Scalar1, SK_Scalar1 }, 0, 128, 16*2 }));
SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)), dir,
SK_Scalar1/4, SkIntToScalar(4)));
paint->setColor(SK_ColorBLUE); paint->setColor(SK_ColorBLUE);
#endif
} }
class DemoView : public SampleView { class DemoView : public SampleView {

View File

@ -10,6 +10,7 @@
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkColorMatrixFilter.h" #include "SkColorMatrixFilter.h"
#include "SkDiscretePathEffect.h" #include "SkDiscretePathEffect.h"
#include "SkEmbossMaskFilter.h"
#include "SkGradientShader.h" #include "SkGradientShader.h"
#include "SkPaint.h" #include "SkPaint.h"
#include "SkView.h" #include "SkView.h"
@ -28,11 +29,9 @@ static void paint_proc1(SkPaint* paint) {
} }
static void paint_proc2(SkPaint* paint) { static void paint_proc2(SkPaint* paint) {
#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER paint->setMaskFilter(SkEmbossMaskFilter::Make(
SkScalar dir[3] = { 1, 1, 1}; SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(1)),
paint->setMaskFilter( { { SK_Scalar1, SK_Scalar1, SK_Scalar1 }, 0, 64, 16 }));
SkBlurMaskFilter::MakeEmboss(SkBlurMask::ConvertRadiusToSigma(1), dir, 0.1f, 0.05f));
#endif
} }
static void paint_proc3(SkPaint* paint) { static void paint_proc3(SkPaint* paint) {

View File

@ -172,34 +172,57 @@ public:
*/ */
static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) { static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
unsigned rb = width; unsigned rb = width;
if (SkMask::kBW_Format == format) { switch (format) {
case SkMask::kBW_Format:
rb = BitsToBytes(rb); rb = BitsToBytes(rb);
} else if (SkMask::kARGB32_Format == format) { break;
rb <<= 2; case SkMask::kA8_Format:
} else if (SkMask::kLCD16_Format == format) {
rb = SkAlign4(rb << 1);
} else {
rb = SkAlign4(rb); rb = SkAlign4(rb);
break;
case SkMask::k3D_Format:
rb = SkAlign4(rb);
break;
case SkMask::kARGB32_Format:
rb <<= 2;
break;
case SkMask::kLCD16_Format:
rb = SkAlign4(rb << 1);
break;
default:
SK_ABORT("Unknown mask format.");
break;
} }
return rb; return rb;
} }
size_t allocImage(SkArenaAlloc* alloc) { size_t allocImage(SkArenaAlloc* alloc) {
size_t allocSize; size_t allocSize;
if (SkMask::kBW_Format == fMaskFormat) { switch (static_cast<SkMask::Format>(fMaskFormat)) {
case SkMask::kBW_Format:
allocSize = BitsToBytes(fWidth) * fHeight; allocSize = BitsToBytes(fWidth) * fHeight;
fImage = alloc->makeArrayDefault<char>(allocSize); fImage = alloc->makeArrayDefault<char>(allocSize);
} else if (SkMask::kARGB32_Format == fMaskFormat) { break;
case SkMask::kA8_Format:
allocSize = SkAlign4(fWidth) * fHeight;
fImage = alloc->makeArrayDefault<char>(allocSize);
break;
case SkMask::k3D_Format:
allocSize = SkAlign4(fWidth) * fHeight * 3;
fImage = alloc->makeArrayDefault<char>(allocSize);
break;
case SkMask::kARGB32_Format:
allocSize = fWidth * fHeight; allocSize = fWidth * fHeight;
fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight); fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight);
allocSize *= sizeof(uint32_t); allocSize *= sizeof(uint32_t);
} else if (SkMask::kLCD16_Format == fMaskFormat) { break;
case SkMask::kLCD16_Format:
allocSize = SkAlign2(fWidth) * fHeight; allocSize = SkAlign2(fWidth) * fHeight;
fImage = alloc->makeArrayDefault<uint16_t>(allocSize); fImage = alloc->makeArrayDefault<uint16_t>(allocSize);
allocSize *= sizeof(uint16_t); allocSize *= sizeof(uint16_t);
} else { break;
allocSize = SkAlign4(fWidth) * fHeight; default:
fImage = alloc->makeArrayDefault<char>(allocSize); SK_ABORT("Unknown mask format.");
break;
} }
return allocSize; return allocSize;
} }

View File

@ -26,8 +26,6 @@
#include "SkStrokeRec.h" #include "SkStrokeRec.h"
#include "SkWriteBuffer.h" #include "SkWriteBuffer.h"
#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
void SkGlyph::toMask(SkMask* mask) const { void SkGlyph::toMask(SkMask* mask) const {
SkASSERT(mask); SkASSERT(mask);

View File

@ -68,47 +68,41 @@ void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light)
int next_row = neq_to_mask(y, maxy) & rowBytes; int next_row = neq_to_mask(y, maxy) & rowBytes;
for (int x = 0; x <= maxx; x++) { for (int x = 0; x <= maxx; x++) {
if (alpha[x]) { int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)];
int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)]; int ny = alpha[x + next_row] - alpha[x - prev_row];
int ny = alpha[x + next_row] - alpha[x - prev_row];
SkFixed numer = lx * nx + ly * ny + lz_dot_nz; SkFixed numer = lx * nx + ly * ny + lz_dot_nz;
int mul = ambient; int mul = ambient;
int add = 0; int add = 0;
if (numer > 0) { // preflight when numer/denom will be <= 0 if (numer > 0) { // preflight when numer/denom will be <= 0
int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta); int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta);
SkFixed dot = numer / denom; SkFixed dot = numer / denom;
dot >>= 8; // now dot is 2^8 instead of 2^16 dot >>= 8; // now dot is 2^8 instead of 2^16
mul = SkFastMin32(mul + dot, 255); mul = SkFastMin32(mul + dot, 255);
// now for the reflection // now for the reflection
// R = 2 (Light * Normal) Normal - Light // R = 2 (Light * Normal) Normal - Light
// hilite = R * Eye(0, 0, 1) // hilite = R * Eye(0, 0, 1)
int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8; int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8;
if (hilite > 0) { if (hilite > 0) {
// pin hilite to 255, since our fast math is also a little sloppy // pin hilite to 255, since our fast math is also a little sloppy
hilite = SkClampMax(hilite, 255); hilite = SkClampMax(hilite, 255);
// specular is 4.4 // specular is 4.4
// would really like to compute the fractional part of this // would really like to compute the fractional part of this
// and then possibly cache a 256 table for a given specular // and then possibly cache a 256 table for a given specular
// value in the light, and just pass that in to this function. // value in the light, and just pass that in to this function.
add = hilite; add = hilite;
for (int i = specular >> 4; i > 0; --i) { for (int i = specular >> 4; i > 0; --i) {
add = div255(add * hilite); add = div255(add * hilite);
}
} }
} }
multiply[x] = SkToU8(mul);
additive[x] = SkToU8(add);
// multiply[x] = 0xFF;
// additive[x] = 0;
// ((uint8_t*)alpha)[x] = alpha[x] * multiply[x] >> 8;
} }
multiply[x] = SkToU8(mul);
additive[x] = SkToU8(add);
} }
alpha += rowBytes; alpha += rowBytes;
multiply += rowBytes; multiply += rowBytes;

View File

@ -17,26 +17,6 @@ sk_sp<SkMaskFilter> SkEmbossMaskFilter::Make(SkScalar blurSigma, const Light& li
return sk_sp<SkMaskFilter>(new SkEmbossMaskFilter(blurSigma, light)); return sk_sp<SkMaskFilter>(new SkEmbossMaskFilter(blurSigma, light));
} }
#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
sk_sp<SkMaskFilter> SkBlurMaskFilter::MakeEmboss(SkScalar blurSigma, const SkScalar direction[3],
SkScalar ambient, SkScalar specular) {
if (direction == nullptr) {
return nullptr;
}
SkEmbossMaskFilter::Light light;
memcpy(light.fDirection, direction, sizeof(light.fDirection));
// ambient should be 0...1 as a scalar
light.fAmbient = SkUnitScalarClampToByte(ambient);
// specular should be 0..15.99 as a scalar
static const SkScalar kSpecularMultiplier = SkIntToScalar(255) / 16;
light.fSpecular = static_cast<U8CPU>(SkScalarPin(specular, 0, 16) * kSpecularMultiplier + 0.5);
return SkEmbossMaskFilter::Make(blurSigma, light);
}
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static void normalize(SkScalar v[3]) { static void normalize(SkScalar v[3]) {