From 4f169ec7378f52c6c8b0c5a4b824670b22f58bfc Mon Sep 17 00:00:00 2001 From: Herb Derby Date: Wed, 22 Aug 2018 17:26:46 -0400 Subject: [PATCH] Introduce SkGlyphCacheInterface Change-Id: I54ee9f5a5a13eff0b7f9a07bb22314d8ea2350a4 Reviewed-on: https://skia-review.googlesource.com/148813 Commit-Queue: Herb Derby Reviewed-by: Mike Klein --- src/core/SkGlyphCache.cpp | 18 ++++++++++++++- src/core/SkGlyphCache.h | 13 ++++++++--- src/core/SkGlyphRun.cpp | 38 ++++--------------------------- src/core/SkGlyphRun.h | 47 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index 30f7def312..9b2a7c026e 100644 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -27,7 +27,9 @@ SkGlyphCache::SkGlyphCache( const SkPaint::FontMetrics& fontMetrics) : fDesc{desc} , fScalerContext{std::move(scaler)} - , fFontMetrics(fontMetrics) + , fFontMetrics{fontMetrics} + , fIsSubpixel{fScalerContext->isSubpixel()} + , fAxisAlignment{fScalerContext->computeAxisAlignmentForHText()} { SkASSERT(fScalerContext != nullptr); fMemoryUsed = sizeof(*this); @@ -282,6 +284,20 @@ void SkGlyphCache::initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph& fa fMemoryUsed += glyph->copyImageData(fallback, &fAlloc); } +SkVector SkGlyphCache::rounding() const { + return SkGlyphCacheCommon::PixelRounding(fIsSubpixel, fAxisAlignment); +} + +const SkGlyph& SkGlyphCache::getGlyphMetrics(SkGlyphID glyphID, SkPoint position) { + if (!fIsSubpixel) { + return this->getGlyphIDMetrics(glyphID); + } else { + SkIPoint lookupPosition = SkGlyphCacheCommon::SubpixelLookup(fAxisAlignment, position); + + return this->getGlyphIDMetrics(glyphID, lookupPosition.x(), lookupPosition.y()); + } +} + #include "../pathops/SkPathOpsCubic.h" #include "../pathops/SkPathOpsQuad.h" diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h index 0d979d3afa..4eba18ee2a 100644 --- a/src/core/SkGlyphCache.h +++ b/src/core/SkGlyphCache.h @@ -30,12 +30,12 @@ The Find*Exclusive() method returns SkExclusiveStrikePtr, which releases exclusive ownership when they go out of scope. */ -class SkGlyphCache { +class SkGlyphCache : public SkGlyphCacheInterface { public: SkGlyphCache(const SkDescriptor& desc, std::unique_ptr scaler, const SkPaint::FontMetrics&); - ~SkGlyphCache(); + ~SkGlyphCache() override; const SkDescriptor& getDescriptor() const; @@ -132,9 +132,13 @@ public: } bool isSubpixel() const { - return fScalerContext->isSubpixel(); + return fIsSubpixel; } + SkVector rounding() const override; + + const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override; + /** Return the approx RAM usage for this cache. */ size_t getMemoryUsed() const { return fMemoryUsed; } @@ -233,6 +237,9 @@ private: // used to track (approx) how much ram is tied-up in this cache size_t fMemoryUsed; + + const bool fIsSubpixel; + const SkAxisAlignment fAxisAlignment; }; #endif // SkGlyphCache_DEFINED diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 0134921daf..00e0049165 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -140,42 +140,16 @@ SkGlyphRunListPainter::SkGlyphRunListPainter( SkGlyphRunListPainter::SkGlyphRunListPainter(const GrRenderTargetContext& rtc) : SkGlyphRunListPainter{rtc.surfaceProps(), rtc.colorSpaceInfo()} {} -// TODO: all this logic should move to the glyph cache. -static const SkGlyph& lookup_glyph_by_subpixel( - SkAxisAlignment axisAlignment, SkPoint position, SkGlyphID glyphID, SkGlyphCache* cache) { - SkFixed lookupX = SkScalarToFixed(SkScalarFraction(position.x())), - lookupY = SkScalarToFixed(SkScalarFraction(position.y())); - - // Snap to a given axis if alignment is requested. - if (axisAlignment == kX_SkAxisAlignment) { - lookupY = 0; - } else if (axisAlignment == kY_SkAxisAlignment) { - lookupX = 0; - } - - return cache->getGlyphIDMetrics(glyphID, lookupX, lookupY); -} - - // forEachMappedDrawableGlyph handles positioning for mask type glyph handling for both sub-pixel // and full pixel positioning. template void SkGlyphRunListPainter::forEachMappedDrawableGlyph( const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix, - SkGlyphCache* cache, EachGlyph eachGlyph) { - bool isSubpixel = cache->isSubpixel(); - - SkAxisAlignment axisAlignment = kNone_SkAxisAlignment; + SkGlyphCacheInterface* cache, EachGlyph eachGlyph) { SkMatrix mapping = deviceMatrix; mapping.preTranslate(origin.x(), origin.y()); - // TODO: all this logic should move to the glyph cache. - if (isSubpixel) { - axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText(); - SkPoint rounding = SkFindAndPlaceGlyph::SubpixelPositionRounding(axisAlignment); - mapping.postTranslate(rounding.x(), rounding.y()); - } else { - mapping.postTranslate(SK_ScalarHalf, SK_ScalarHalf); - } + SkVector rounding = cache->rounding(); + mapping.postTranslate(rounding.x(), rounding.y()); auto runSize = glyphRun.runSize(); if (this->ensureBitmapBuffers(runSize)) { @@ -186,10 +160,7 @@ void SkGlyphRunListPainter::forEachMappedDrawableGlyph( auto mappedPt = *mappedPtCursor++; auto pt = origin + *ptCursor++; if (SkScalarsAreFinite(mappedPt.x(), mappedPt.y())) { - // TODO: all this logic should move to the glyph cache. - const SkGlyph& glyph = - isSubpixel ? lookup_glyph_by_subpixel(axisAlignment, mappedPt, glyphID, cache) - : cache->getGlyphIDMetrics(glyphID); + const SkGlyph& glyph = cache->getGlyphMetrics(glyphID, mappedPt); if (!glyph.isEmpty()) { // Prevent glyphs from being drawn outside of or straddling the edge // of device space. Comparisons written a little weirdly so that NaN @@ -357,7 +328,6 @@ void SkGlyphRunListPainter::drawGlyphRunAsFullpixelMask( } } - void SkGlyphRunListPainter::drawForBitmapDevice( const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix, PerMaskCreator perMaskCreator, PerPathCreator perPathCreator) { diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index ff0026ca0c..39a8567b61 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -30,6 +30,51 @@ class SkBaseDevice; class SkGlyphRunList; class SkRasterClip; +class SkGlyphCacheInterface { +public: + virtual ~SkGlyphCacheInterface() = default; + virtual SkVector rounding() const = 0; + virtual const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) = 0; +}; + +class SkGlyphCacheCommon { +public: + static SkVector PixelRounding(bool isSubpixel, SkAxisAlignment axisAlignment) { + if (!isSubpixel) { + return {SK_ScalarHalf, SK_ScalarHalf}; + } else { + static constexpr SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRound); + switch (axisAlignment) { + case kX_SkAxisAlignment: + return {kSubpixelRounding, SK_ScalarHalf}; + case kY_SkAxisAlignment: + return {SK_ScalarHalf, kSubpixelRounding}; + case kNone_SkAxisAlignment: + return {kSubpixelRounding, kSubpixelRounding}; + } + } + + // Some compilers need this. + return {0, 0}; + } + + // This assumes that position has the appropriate rounding term applied. + static SkIPoint SubpixelLookup(SkAxisAlignment axisAlignment, SkPoint position) { + // TODO: SkScalarFraction uses truncf to calculate the fraction. This should be floorf. + SkFixed lookupX = SkScalarToFixed(SkScalarFraction(position.x())), + lookupY = SkScalarToFixed(SkScalarFraction(position.y())); + + // Snap to a given axis if alignment is requested. + if (axisAlignment == kX_SkAxisAlignment) { + lookupY = 0; + } else if (axisAlignment == kY_SkAxisAlignment) { + lookupX = 0; + } + + return {lookupX, lookupY}; + } +}; + class SkGlyphRun { public: SkGlyphRun() = default; @@ -128,7 +173,7 @@ private: template void forEachMappedDrawableGlyph( const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix, - SkGlyphCache* cache, EachGlyph eachGlyph); + SkGlyphCacheInterface* cache, EachGlyph eachGlyph); void drawGlyphRunAsSubpixelMask( SkGlyphCache* cache, const SkGlyphRun& glyphRun,