diff options
author | 2018-05-03 10:40:30 -0400 | |
---|---|---|
committer | 2018-05-04 13:56:02 +0000 | |
commit | d401da64f0eb94239442018395ab150bc9535746 (patch) | |
tree | 652857da6ce723e4937c375e317a98a852486c78 /src/gpu | |
parent | 9eeede2e710f0e5fab0f65e06e8d40a40cdaebcd (diff) |
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>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 14 | ||||
-rw-r--r-- | src/gpu/text/GrGlyphCache.cpp | 109 | ||||
-rw-r--r-- | src/gpu/text/GrSDFMaskFilter.cpp | 102 | ||||
-rw-r--r-- | src/gpu/text/GrSDFMaskFilter.h | 24 |
4 files changed, 149 insertions, 100 deletions
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index e99d9df044..a2e62430ce 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -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; diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp index 8f5e2bad77..b564c93c02 100644 --- a/src/gpu/text/GrGlyphCache.cpp +++ b/src/gpu/text/GrGlyphCache.cpp @@ -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( diff --git a/src/gpu/text/GrSDFMaskFilter.cpp b/src/gpu/text/GrSDFMaskFilter.cpp new file mode 100644 index 0000000000..ff79cdb3f0 --- /dev/null +++ b/src/gpu/text/GrSDFMaskFilter.cpp @@ -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()); +} diff --git a/src/gpu/text/GrSDFMaskFilter.h b/src/gpu/text/GrSDFMaskFilter.h new file mode 100644 index 0000000000..cc9cf4bd3d --- /dev/null +++ b/src/gpu/text/GrSDFMaskFilter.h @@ -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 |