aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2018-05-03 10:40:30 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-04 13:56:02 +0000
commitd401da64f0eb94239442018395ab150bc9535746 (patch)
tree652857da6ce723e4937c375e317a98a852486c78 /src/gpu
parent9eeede2e710f0e5fab0f65e06e8d40a40cdaebcd (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.cpp14
-rw-r--r--src/gpu/text/GrGlyphCache.cpp109
-rw-r--r--src/gpu/text/GrSDFMaskFilter.cpp102
-rw-r--r--src/gpu/text/GrSDFMaskFilter.h24
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