Use MaskFilter to create SDFs for text.
Easy way to store SDFs in the glyph cache. Change-Id: Ia67e5c8619862bdee6aa3b293e30507d029e3bf1 Bug: skia: Reviewed-on: https://skia-review.googlesource.com/123748 Reviewed-by: Ben Wagner <bungeman@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
9eeede2e71
commit
d401da64f0
@ -408,6 +408,8 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/text/GrDistanceFieldAdjustTable.h",
|
||||
"$_src/gpu/text/GrGlyphCache.cpp",
|
||||
"$_src/gpu/text/GrGlyphCache.h",
|
||||
"$_src/gpu/text/GrSDFMaskFilter.cpp",
|
||||
"$_src/gpu/text/GrSDFMaskFilter.h",
|
||||
"$_src/gpu/text/GrTextBlobCache.cpp",
|
||||
"$_src/gpu/text/GrTextBlobCache.h",
|
||||
"$_src/gpu/text/GrTextUtils.cpp",
|
||||
|
@ -41,6 +41,9 @@
|
||||
#include "SkTypeface.h"
|
||||
#include "SkView.h"
|
||||
#include "SkXfermodeImageFilter.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "text/GrSDFMaskFilter.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
@ -455,7 +458,11 @@ static sk_sp<SkPathEffect> make_path_effect(bool canBeNull = true) {
|
||||
|
||||
static sk_sp<SkMaskFilter> make_mask_filter() {
|
||||
sk_sp<SkMaskFilter> maskFilter;
|
||||
#if SK_SUPPORT_GPU
|
||||
switch (R(4)) {
|
||||
#else
|
||||
switch (R(3)) {
|
||||
#endif
|
||||
case 0:
|
||||
maskFilter = SkMaskFilter::MakeBlur(make_blur_style(), make_scalar(),
|
||||
make_blur_mask_filter_respectctm());
|
||||
@ -469,7 +476,13 @@ static sk_sp<SkMaskFilter> make_mask_filter() {
|
||||
light.fSpecular = R(256);
|
||||
maskFilter = SkEmbossMaskFilter::Make(make_scalar(), light);
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
case 2:
|
||||
maskFilter = GrSDFMaskFilter::Make();
|
||||
case 3:
|
||||
#else
|
||||
case 2:
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ static size_t format_alignment(SkMask::Format format) {
|
||||
case SkMask::kBW_Format:
|
||||
case SkMask::kA8_Format:
|
||||
case SkMask::k3D_Format:
|
||||
case SkMask::kSDF_Format:
|
||||
return alignof(uint8_t);
|
||||
case SkMask::kARGB32_Format:
|
||||
return alignof(uint32_t);
|
||||
|
@ -51,6 +51,33 @@ void SkMask::FreeImage(void* image) {
|
||||
sk_free(image);
|
||||
}
|
||||
|
||||
SkMask SkMask::PrepareDestination(int radiusX, int radiusY, const SkMask& src) {
|
||||
SkSafeMath safe;
|
||||
|
||||
SkMask dst;
|
||||
// dstW = srcW + 2 * radiusX;
|
||||
size_t dstW = safe.add(src.fBounds.width(), safe.add(radiusX, radiusX));
|
||||
// dstH = srcH + 2 * radiusY;
|
||||
size_t dstH = safe.add(src.fBounds.height(), safe.add(radiusY, radiusY));
|
||||
|
||||
dst.fBounds.set(0, 0, SkTo<int>(dstW), SkTo<int>(dstH));
|
||||
dst.fBounds.offset(src.fBounds.x(), src.fBounds.y());
|
||||
dst.fBounds.offset(-radiusX, -radiusY);
|
||||
|
||||
dst.fImage = nullptr;
|
||||
dst.fRowBytes = SkTo<uint32_t>(dstW);
|
||||
dst.fFormat = SkMask::kA8_Format;
|
||||
|
||||
size_t toAlloc = safe.mul(dstW, dstH);
|
||||
|
||||
if (safe && src.fImage != nullptr) {
|
||||
dst.fImage = SkMask::AllocImage(toAlloc);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const int gMaskFormatToShift[] = {
|
||||
@ -59,6 +86,7 @@ static const int gMaskFormatToShift[] = {
|
||||
0, // 3D
|
||||
2, // ARGB32
|
||||
1, // LCD16
|
||||
0, // SDF
|
||||
};
|
||||
|
||||
static int maskFormatToShift(SkMask::Format format) {
|
||||
|
@ -25,10 +25,11 @@ struct SkMask {
|
||||
k3D_Format, //!< 3 8bit per pixl planes: alpha, mul, add
|
||||
kARGB32_Format, //!< SkPMColor
|
||||
kLCD16_Format, //!< 565 alpha for r/g/b
|
||||
kSDF_Format, //!< 8bits representing signed distance field
|
||||
};
|
||||
|
||||
enum {
|
||||
kCountMaskFormats = kLCD16_Format + 1
|
||||
kCountMaskFormats = kSDF_Format + 1
|
||||
};
|
||||
|
||||
uint8_t* fImage;
|
||||
@ -68,7 +69,7 @@ struct SkMask {
|
||||
x,y are in the same coordiate space as fBounds.
|
||||
*/
|
||||
uint8_t* getAddr8(int x, int y) const {
|
||||
SkASSERT(kA8_Format == fFormat);
|
||||
SkASSERT(kA8_Format == fFormat || kSDF_Format == fFormat);
|
||||
SkASSERT(fBounds.contains(x, y));
|
||||
SkASSERT(fImage != nullptr);
|
||||
return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
|
||||
@ -126,6 +127,11 @@ struct SkMask {
|
||||
kJustRenderImage_CreateMode, //!< render into preallocate mask
|
||||
kComputeBoundsAndRenderImage_CreateMode //!< compute bounds, alloc image and render into it
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns initial destination mask data padded by radiusX and radiusY
|
||||
*/
|
||||
static SkMask PrepareDestination(int radiusX, int radiusY, const SkMask& src);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "SkMalloc.h"
|
||||
#include "SkMaskBlurFilter.h"
|
||||
#include "SkNx.h"
|
||||
#include "SkSafeMath.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
@ -256,32 +255,6 @@ bool SkMaskBlurFilter::hasNoBlur() const {
|
||||
return (3 * fSigmaW <= 1) && (3 * fSigmaH <= 1);
|
||||
}
|
||||
|
||||
static SkMask prepare_destination(int radiusX, int radiusY, const SkMask& src) {
|
||||
SkSafeMath safe;
|
||||
|
||||
SkMask dst;
|
||||
// dstW = srcW + 2 * radiusX;
|
||||
size_t dstW = safe.add(src.fBounds.width(), safe.add(radiusX, radiusX));
|
||||
// dstH = srcH + 2 * radiusY;
|
||||
size_t dstH = safe.add(src.fBounds.height(), safe.add(radiusY, radiusY));
|
||||
|
||||
dst.fBounds.set(0, 0, SkTo<int>(dstW), SkTo<int>(dstH));
|
||||
dst.fBounds.offset(src.fBounds.x(), src.fBounds.y());
|
||||
dst.fBounds.offset(-radiusX, -radiusY);
|
||||
|
||||
dst.fImage = nullptr;
|
||||
dst.fRowBytes = SkTo<uint32_t>(dstW);
|
||||
dst.fFormat = SkMask::kA8_Format;
|
||||
|
||||
size_t toAlloc = safe.mul(dstW, dstH);
|
||||
|
||||
if (safe && src.fImage != nullptr) {
|
||||
dst.fImage = SkMask::AllocImage(toAlloc);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static constexpr uint16_t _____ = 0u;
|
||||
static constexpr uint16_t kHalf = 0x80u;
|
||||
|
||||
@ -878,7 +851,7 @@ static SkIPoint small_blur(double sigmaX, double sigmaY, const SkMask& src, SkMa
|
||||
prepareGauss(filterX, gaussFactorsX);
|
||||
prepareGauss(filterY, gaussFactorsY);
|
||||
|
||||
*dst = prepare_destination(radiusX, radiusY, src);
|
||||
*dst = SkMask::PrepareDestination(radiusX, radiusY, src);
|
||||
if (src.fImage == nullptr) {
|
||||
return {SkTo<int32_t>(radiusX), SkTo<int32_t>(radiusY)};
|
||||
}
|
||||
@ -936,7 +909,7 @@ SkIPoint SkMaskBlurFilter::blur(const SkMask& src, SkMask* dst) const {
|
||||
borderH = planH.border();
|
||||
SkASSERT(borderH >= 0 && borderW >= 0);
|
||||
|
||||
*dst = prepare_destination(borderW, borderH, src);
|
||||
*dst = SkMask::PrepareDestination(borderW, borderH, src);
|
||||
if (src.fImage == nullptr) {
|
||||
return {SkTo<int32_t>(borderW), SkTo<int32_t>(borderH)};
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "GrTextureProxy.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "effects/GrXfermodeFragmentProcessor.h"
|
||||
#include "text/GrSDFMaskFilter.h"
|
||||
#endif
|
||||
|
||||
SkMaskFilterBase::NinePatch::~NinePatch() {
|
||||
@ -734,5 +735,7 @@ void SkMaskFilter::InitializeFlattenables() {
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeMF)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCombineMF)
|
||||
sk_register_blur_maskfilter_createproc();
|
||||
#if SK_SUPPORT_GPU
|
||||
gr_register_sdf_maskfilter_createproc();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "GrAtlasTextContext.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrContextPriv.h"
|
||||
#include "GrSDFMaskFilter.h"
|
||||
#include "GrTextBlobCache.h"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkDraw.h"
|
||||
@ -661,6 +662,8 @@ void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob,
|
||||
skPaint->setAutohinted(false);
|
||||
skPaint->setHinting(SkPaint::kNormal_Hinting);
|
||||
skPaint->setSubpixelText(true);
|
||||
|
||||
skPaint->setMaskFilter(GrSDFMaskFilter::Make());
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex,
|
||||
@ -793,13 +796,11 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
glyphPos.fY += (2 == scalarsPerPosition ? pos[1] : 0) -
|
||||
SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio;
|
||||
|
||||
if (glyph.fMaskFormat == SkMask::kA8_Format ||
|
||||
glyph.fMaskFormat == SkMask::kBW_Format)
|
||||
{
|
||||
if (glyph.fMaskFormat == SkMask::kSDF_Format) {
|
||||
DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX,
|
||||
glyphPos.fY, paint.filteredPremulColor(), cache.get(), textRatio);
|
||||
} else {
|
||||
// can't append color glyph to SDF batch, send to fallback
|
||||
// can't append non-SDF glyph to SDF batch, send to fallback
|
||||
fallbackTextHelper.appendText(glyph, SkToInt(text - lastText), lastText,
|
||||
glyphPos);
|
||||
}
|
||||
@ -877,6 +878,11 @@ void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int
|
||||
const GrTextUtils::Paint& paint,
|
||||
SkScalerContextFlags scalerContextFlags) {
|
||||
if (fFallbackTxt.count()) {
|
||||
if (fViewMatrix.hasPerspective()) {
|
||||
// TODO: handle perspective
|
||||
return;
|
||||
}
|
||||
|
||||
blob->initOverride(runIndex);
|
||||
blob->setHasBitmap();
|
||||
SkExclusiveStrikePtr cache;
|
||||
|
@ -62,7 +62,8 @@ static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) {
|
||||
SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
|
||||
switch (format) {
|
||||
case SkMask::kBW_Format:
|
||||
// fall through to kA8 -- we store BW glyphs in our 8-bit cache
|
||||
case SkMask::kSDF_Format:
|
||||
// fall through to kA8 -- we store BW and SDF glyphs in our 8-bit cache
|
||||
case SkMask::kA8_Format:
|
||||
return kA8_GrMaskFormat;
|
||||
case SkMask::k3D_Format:
|
||||
@ -89,19 +90,6 @@ static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& g
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
|
||||
SkIRect* bounds) {
|
||||
#if 1
|
||||
// crbug:510931
|
||||
// Retrieving the image from the cache can actually change the mask format.
|
||||
cache->findImage(glyph);
|
||||
#endif
|
||||
bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
|
||||
bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
|
||||
// A8, RGB565, or RGBA8888.
|
||||
template <typename INT_TYPE>
|
||||
@ -182,64 +170,6 @@ static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, in
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph,
|
||||
int width, int height, void* dst) {
|
||||
SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
|
||||
SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
|
||||
|
||||
#ifndef SK_USE_LEGACY_DISTANCE_FIELDS
|
||||
const SkPath* path = cache->findPath(glyph);
|
||||
if (nullptr == path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft,
|
||||
glyph.fTop,
|
||||
glyph.fWidth,
|
||||
glyph.fHeight));
|
||||
SkASSERT(glyphBounds.contains(path->getBounds()));
|
||||
|
||||
// now generate the distance field
|
||||
SkASSERT(dst);
|
||||
SkMatrix drawMatrix;
|
||||
drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop);
|
||||
|
||||
// Generate signed distance field directly from SkPath
|
||||
bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst,
|
||||
*path, drawMatrix,
|
||||
width, height, width * sizeof(unsigned char));
|
||||
|
||||
if (!succeed) {
|
||||
#endif
|
||||
const void* image = cache->findImage(glyph);
|
||||
if (nullptr == image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// now generate the distance field
|
||||
SkASSERT(dst);
|
||||
SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
|
||||
if (SkMask::kA8_Format == maskFormat) {
|
||||
// make the distance field from the image
|
||||
SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
|
||||
(unsigned char*)image,
|
||||
glyph.fWidth, glyph.fHeight,
|
||||
glyph.rowBytes());
|
||||
} else if (SkMask::kBW_Format == maskFormat) {
|
||||
// make the distance field from the image
|
||||
SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
|
||||
(unsigned char*)image,
|
||||
glyph.fWidth, glyph.fHeight,
|
||||
glyph.rowBytes());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#ifndef SK_USE_LEGACY_DISTANCE_FIELDS
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
@ -267,14 +197,8 @@ GrTextStrike::~GrTextStrike() {
|
||||
GrGlyph* GrTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
|
||||
SkGlyphCache* cache) {
|
||||
SkIRect bounds;
|
||||
if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) {
|
||||
if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
|
||||
return nullptr;
|
||||
}
|
||||
GrMaskFormat format = get_packed_glyph_mask_format(skGlyph);
|
||||
|
||||
@ -327,22 +251,15 @@ GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
|
||||
SkAutoSMalloc<1024> storage(size);
|
||||
|
||||
const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
|
||||
if (isSDFGlyph) {
|
||||
if (!get_packed_glyph_df_image(cache, skGlyph, width, height,
|
||||
storage.get())) {
|
||||
return GrDrawOpAtlas::ErrorCode::kError;
|
||||
}
|
||||
} else {
|
||||
void* dataPtr = storage.get();
|
||||
if (addPad) {
|
||||
sk_bzero(dataPtr, size);
|
||||
dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
|
||||
}
|
||||
if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
|
||||
rowBytes, expectedMaskFormat,
|
||||
dataPtr)) {
|
||||
return GrDrawOpAtlas::ErrorCode::kError;
|
||||
}
|
||||
void* dataPtr = storage.get();
|
||||
if (addPad) {
|
||||
sk_bzero(dataPtr, size);
|
||||
dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
|
||||
}
|
||||
if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
|
||||
rowBytes, expectedMaskFormat,
|
||||
dataPtr)) {
|
||||
return GrDrawOpAtlas::ErrorCode::kError;
|
||||
}
|
||||
|
||||
GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
|
||||
|
102
src/gpu/text/GrSDFMaskFilter.cpp
Normal file
102
src/gpu/text/GrSDFMaskFilter.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrSDFMaskFilter.h"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkMaskFilterBase.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkSafeMath.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkString.h"
|
||||
|
||||
class SK_API GrSDFMaskFilterImpl : public SkMaskFilterBase {
|
||||
public:
|
||||
GrSDFMaskFilterImpl();
|
||||
|
||||
// overrides from SkMaskFilterBase
|
||||
// This method is not exported to java.
|
||||
SkMask::Format getFormat() const override;
|
||||
// This method is not exported to java.
|
||||
bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
|
||||
SkIPoint* margin) const override;
|
||||
|
||||
void computeFastBounds(const SkRect&, SkRect*) const override;
|
||||
|
||||
void toString(SkString* str) const override;
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(GrSDFMaskFilterImpl)
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
typedef SkMaskFilter INHERITED;
|
||||
friend void gr_register_sdf_maskfilter_createproc();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrSDFMaskFilterImpl::GrSDFMaskFilterImpl() {}
|
||||
|
||||
SkMask::Format GrSDFMaskFilterImpl::getFormat() const {
|
||||
return SkMask::kSDF_Format;
|
||||
}
|
||||
|
||||
bool GrSDFMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
|
||||
const SkMatrix& matrix, SkIPoint* margin) const {
|
||||
if (src.fFormat != SkMask::kA8_Format && src.fFormat != SkMask::kBW_Format) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*dst = SkMask::PrepareDestination(SK_DistanceFieldPad, SK_DistanceFieldPad, src);
|
||||
dst->fFormat = SkMask::kSDF_Format;
|
||||
|
||||
if (margin) {
|
||||
margin->set(SK_DistanceFieldPad, SK_DistanceFieldPad);
|
||||
}
|
||||
|
||||
if (src.fImage == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (dst->fImage == nullptr) {
|
||||
dst->fBounds.setEmpty();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (src.fFormat == SkMask::kA8_Format) {
|
||||
return SkGenerateDistanceFieldFromA8Image(dst->fImage, src.fImage,
|
||||
src.fBounds.width(), src.fBounds.height(),
|
||||
src.fRowBytes);
|
||||
|
||||
} else {
|
||||
return SkGenerateDistanceFieldFromBWImage(dst->fImage, src.fImage,
|
||||
src.fBounds.width(), src.fBounds.height(),
|
||||
src.fRowBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void GrSDFMaskFilterImpl::computeFastBounds(const SkRect& src,
|
||||
SkRect* dst) const {
|
||||
dst->set(src.fLeft - SK_DistanceFieldPad, src.fTop - SK_DistanceFieldPad,
|
||||
src.fRight + SK_DistanceFieldPad, src.fBottom + SK_DistanceFieldPad);
|
||||
}
|
||||
|
||||
sk_sp<SkFlattenable> GrSDFMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
|
||||
return GrSDFMaskFilter::Make();
|
||||
}
|
||||
|
||||
void GrSDFMaskFilterImpl::toString(SkString* str) const {
|
||||
str->append("GrSDFMaskFilterImpl: ()");
|
||||
}
|
||||
|
||||
void gr_register_sdf_maskfilter_createproc() {
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(GrSDFMaskFilterImpl)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkMaskFilter> GrSDFMaskFilter::Make() {
|
||||
return sk_sp<SkMaskFilter>(new GrSDFMaskFilterImpl());
|
||||
}
|
24
src/gpu/text/GrSDFMaskFilter.h
Normal file
24
src/gpu/text/GrSDFMaskFilter.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrSDFMaskFilter_DEFINED
|
||||
#define GrSDFMaskFilter_DEFINED
|
||||
|
||||
#include "SkMaskFilter.h"
|
||||
|
||||
/** \class GrSDFMaskFilter
|
||||
|
||||
This mask filter converts an alpha mask to a signed distance field representation
|
||||
*/
|
||||
class SK_API GrSDFMaskFilter : public SkMaskFilter {
|
||||
public:
|
||||
static sk_sp<SkMaskFilter> Make();
|
||||
};
|
||||
|
||||
extern void gr_register_sdf_maskfilter_createproc();
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user