From 4c11b3f8a2d9919a21110dbdd29e67e5cbaa41fb Mon Sep 17 00:00:00 2001 From: herb Date: Fri, 20 Nov 2015 13:53:12 -0800 Subject: [PATCH] Move glyph choosing to the find and place glyph code. This duplicates the functionality of the (private) SkPaint::getDrawCacheProc method into SkFindAndPlaceGlyph::LookupGlyph. Eventually LookupGlyph should replace getDrawCacheProc, at which point it should be removed. The remaining users are gpu and pdf. Review URL: https://codereview.chromium.org/1458193003 --- src/core/SkDraw.cpp | 9 +- src/core/SkFindAndPlaceGlyph.h | 209 +++++++++++++++++++++++++-------- src/gpu/GrAtlasTextContext.cpp | 11 +- 3 files changed, 171 insertions(+), 58 deletions(-) diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index ca84e629ee..ef073f8159 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1580,7 +1580,6 @@ void SkDraw::drawText(const char text[], size_t byteLength, return; } - SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); SkGlyphCache* cache = autoCache.getCache(); @@ -1600,7 +1599,8 @@ void SkDraw::drawText(const char text[], size_t byteLength, SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); SkFindAndPlaceGlyph::ProcessText( - text, byteLength, {x, y}, *fMatrix, paint.getTextAlign(), glyphCacheProc, cache, + paint.getTextEncoding(), text, byteLength, + {x, y}, *fMatrix, paint.getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); @@ -1695,11 +1695,10 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, SkDraw1Glyph d1g; SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); SkPaint::Align textAlignment = paint.getTextAlign(); - SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); SkFindAndPlaceGlyph::ProcessPosText( - text, byteLength, offset, *fMatrix, pos, scalarsPerPosition, - textAlignment, glyphCacheProc, cache, + paint.getTextEncoding(), text, byteLength, + offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); diff --git a/src/core/SkFindAndPlaceGlyph.h b/src/core/SkFindAndPlaceGlyph.h index 15000b3d58..278be07e0b 100644 --- a/src/core/SkFindAndPlaceGlyph.h +++ b/src/core/SkFindAndPlaceGlyph.h @@ -13,6 +13,7 @@ #include "SkGlyphCache.h" #include "SkPaint.h" #include "SkTemplates.h" +#include "SkUtils.h" // Calculate a type with the same size as the max of all the Ts. // This must be top level because the is no specialization of inner classes. @@ -32,9 +33,10 @@ struct SkMaxSizeOf { class SkFindAndPlaceGlyph { public: template - static void ProcessText(const char text[], size_t byteLength, SkPoint offset, const - SkMatrix& matrix, SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc, - SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); + static void ProcessText( + SkPaint::TextEncoding, const char text[], size_t byteLength, + SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment, + SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large // multiplicity. It figures out the glyph, position and rounding and pass those parameters to // processOneGlyph. @@ -52,11 +54,11 @@ public: // The number of variations is 108 for sub-pixel and 36 for full-pixel. // This routine handles all of them using inline polymorphic variable (no heap allocation). template - static void ProcessPosText(const char text[], size_t byteLength, - SkPoint offset, const SkMatrix& matrix, - const SkScalar pos[], int scalarsPerPosition, - SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc, - SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); + static void ProcessPosText( + SkPaint::TextEncoding, const char text[], size_t byteLength, + SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition, + SkPaint::Align textAlignment, + SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph); private: // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way @@ -106,6 +108,120 @@ private: mutable Variants fVariants; }; + // GlyphFinderInterface is the polymorphic base for classes that parse a stream of chars into + // the right UniChar (or GlyphID) and lookup up the glyph on the cache. The concrete + // implementations are: Utf8GlyphFinder, Utf16GlyphFinder, Utf32GlyphFinder, + // and GlyphIdGlyphFinder. + class GlyphFinderInterface { + public: + virtual ~GlyphFinderInterface() {} + virtual const SkGlyph& lookupGlyph(const char** text) = 0; + virtual const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) = 0; + }; + + class UtfNGlyphFinder : public GlyphFinderInterface { + public: + UtfNGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); } + + const SkGlyph& lookupGlyph(const char** text) override { + SkASSERT(text != nullptr); + return fCache->getUnicharMetrics(nextUnichar(text)); + } + const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override { + SkASSERT(text != nullptr); + return fCache->getUnicharMetrics(nextUnichar(text), x, y); + } + + private: + virtual SkUnichar nextUnichar(const char** text) = 0; + SkGlyphCache* fCache; + }; + + class Utf8GlyphFinder final : public UtfNGlyphFinder { + public: + Utf8GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } + + private: + SkUnichar nextUnichar(const char** text) override { return SkUTF8_NextUnichar(text); } + }; + + class Utf16GlyphFinder final : public UtfNGlyphFinder { + public: + Utf16GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } + + private: + SkUnichar nextUnichar(const char** text) override { + return SkUTF16_NextUnichar((const uint16_t**)text); + } + }; + + class Utf32GlyphFinder final : public UtfNGlyphFinder { + public: + Utf32GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { } + + private: + SkUnichar nextUnichar(const char** text) override { + const int32_t* ptr = *(const int32_t**)text; + SkUnichar uni = *ptr++; + *text = (const char*)ptr; + return uni; + } + }; + + class GlyphIdGlyphFinder final : public GlyphFinderInterface { + public: + GlyphIdGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); } + + const SkGlyph& lookupGlyph(const char** text) override { + return fCache->getGlyphIDMetrics(nextGlyphId(text)); + } + const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override { + return fCache->getGlyphIDMetrics(nextGlyphId(text), x, y); + } + + private: + uint16_t nextGlyphId(const char** text) { + SkASSERT(text != nullptr); + + const uint16_t* ptr = *(const uint16_t**)text; + uint16_t glyphID = *ptr; + ptr += 1; + *text = (const char*)ptr; + return glyphID; + } + SkGlyphCache* fCache; + }; + + typedef PolymorphicVariant< + GlyphFinderInterface, + Utf8GlyphFinder, + Utf16GlyphFinder, + Utf32GlyphFinder, + GlyphIdGlyphFinder> LookupGlyphVariant; + + class LookupGlyph : public LookupGlyphVariant { + public: + LookupGlyph(SkPaint::TextEncoding encoding, SkGlyphCache* cache) + : LookupGlyphVariant( + [&](LookupGlyphVariant::Variants* to_init) { + switch(encoding) { + case SkPaint::kUTF8_TextEncoding: + to_init->initialize(cache); + break; + case SkPaint::kUTF16_TextEncoding: + to_init->initialize(cache); + break; + case SkPaint::kUTF32_TextEncoding: + to_init->initialize(cache); + break; + case SkPaint::kGlyphID_TextEncoding: + to_init->initialize(cache); + break; + } + } + ) { } + }; + // PositionReaderInterface reads a point from the pos vector. // * HorizontalPositions - assumes a common Y for many X values. // * ArbitraryPositions - a list of (X,Y) pairs. @@ -293,9 +409,8 @@ private: SkAxisAlignment kAxisAlignment> class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface { public: - GlyphFindAndPlaceSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc) - : fCache(cache) - , fGlyphCacheProc(glyphCacheProc) { } + GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder) + : fGlyphFinder(glyphFinder) { } SkPoint findAndPositionGlyph( const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override { @@ -305,7 +420,7 @@ private: // alignment. This is not needed for kLeftAlign because its adjustment is // always {0, 0}. const char* tempText = *text; - const SkGlyph &metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0); + const SkGlyph &metricGlyph = fGlyphFinder->lookupGlyph(&tempText); if (metricGlyph.fWidth <= 0) { // Exiting early, be sure to update text pointer. @@ -321,7 +436,7 @@ private: // Find the glyph. SkIPoint lookupPosition = SubpixelAlignment(kAxisAlignment, finalPosition); const SkGlyph& renderGlyph = - fGlyphCacheProc(fCache, text, lookupPosition.fX, lookupPosition.fY); + fGlyphFinder->lookupGlyphXY(text, lookupPosition.fX, lookupPosition.fY); // If the glyph has no width (no pixels) then don't bother processing it. if (renderGlyph.fWidth > 0) { @@ -333,8 +448,7 @@ private: } private: - SkGlyphCache* const fCache; - SkDrawCacheProc fGlyphCacheProc; + LookupGlyph& fGlyphFinder; }; enum SelectKerning { @@ -348,8 +462,8 @@ private: template class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface { public: - GlyphFindAndPlaceFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc) - : fCache(cache), fGlyphCacheProc(glyphCacheProc) { + GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder) + : fGlyphFinder(glyphFinder) { // Kerning can only be used with SkPaint::kLeft_Align static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment, "Kerning can only be used with left aligned text."); @@ -358,7 +472,7 @@ private: SkPoint findAndPositionGlyph( const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override { SkPoint finalPosition = position; - const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); + const SkGlyph& glyph = fGlyphFinder->lookupGlyph(text); if (kUseKerning) { finalPosition += {SkFixedToScalar(fAutoKern.adjust(glyph)), 0.0f}; } @@ -371,8 +485,8 @@ private: } private: - SkGlyphCache* const fCache; - SkDrawCacheProc fGlyphCacheProc; + LookupGlyph& fGlyphFinder; + SkAutoKern fAutoKern; }; @@ -409,29 +523,24 @@ private: static void InitSubpixel( typename GlyphFindAndPlace::Variants* to_init, SkAxisAlignment axisAlignment, - SkGlyphCache* cache, - SkDrawCacheProc glyphCacheProc) { + LookupGlyph& glyphFinder) { switch (axisAlignment) { case kX_SkAxisAlignment: to_init->template initialize>( - cache, glyphCacheProc); + ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(glyphFinder); break; case kNone_SkAxisAlignment: to_init->template initialize>( - cache, glyphCacheProc); + ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(glyphFinder); break; case kY_SkAxisAlignment: to_init->template initialize>( - cache, glyphCacheProc); + ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>(glyphFinder); break; } } - static SkPoint MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, - const char text[], size_t byteLength) { + static SkPoint MeasureText(LookupGlyph& glyphFinder, const char text[], size_t byteLength) { SkFixed x = 0, y = 0; const char* stop = text + byteLength; @@ -440,7 +549,7 @@ private: while (text < stop) { // don't need x, y here, since all subpixel variants will have the // same advance - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); + const SkGlyph& glyph = glyphFinder->lookupGlyph(&text); x += autokern.adjust(glyph) + glyph.fAdvanceX; y += glyph.fAdvanceY; @@ -452,13 +561,16 @@ private: template inline void SkFindAndPlaceGlyph::ProcessPosText( - const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix, - const SkScalar pos[], int scalarsPerPosition, SkPaint::Align textAlignment, - SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) { + SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength, + SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition, + SkPaint::Align textAlignment, + SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) { SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); uint32_t mtype = matrix.getType(); + LookupGlyph glyphFinder(textEncoding, cache); + // Specialized code for handling the most common case for blink. The while loop is totally // de-virtualized. if (scalarsPerPosition == 1 @@ -470,7 +582,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner; HorizontalPositions positions{pos}; TranslationMapper mapper{matrix, offset}; - Positioner positioner(cache, glyphCacheProc); + Positioner positioner(glyphFinder); const char* cursor = text; const char* stop = text + byteLength; while (cursor < stop) { @@ -511,15 +623,15 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( switch (textAlignment) { case SkPaint::kLeft_Align: InitSubpixel( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); break; case SkPaint::kCenter_Align: InitSubpixel( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); break; case SkPaint::kRight_Align: InitSubpixel( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); break; } } else { @@ -527,17 +639,17 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( case SkPaint::kLeft_Align: to_init->template initialize< GlyphFindAndPlaceFullPixel>(cache, glyphCacheProc); + SkPaint::kLeft_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kCenter_Align: to_init->template initialize< GlyphFindAndPlaceFullPixel>(cache, glyphCacheProc); + SkPaint::kCenter_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kRight_Align: to_init->template initialize< GlyphFindAndPlaceFullPixel>(cache, glyphCacheProc); + SkPaint::kRight_Align, kNoKerning>>(glyphFinder); break; } } @@ -554,16 +666,18 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( template inline void SkFindAndPlaceGlyph::ProcessText( - const char text[], size_t byteLength, SkPoint offset, const SkMatrix& matrix, - SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc, SkGlyphCache* cache, - ProcessOneGlyph&& processOneGlyph) { + SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength, + SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment, + SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) { // transform the starting point matrix.mapPoints(&offset, 1); + LookupGlyph glyphFinder(textEncoding, cache); + // need to measure first if (textAlignment != SkPaint::kLeft_Align) { - SkVector stop = MeasureText(cache, glyphCacheProc, text, byteLength); + SkVector stop = MeasureText(glyphFinder, text, byteLength); if (textAlignment == SkPaint::kCenter_Align) { stop *= SK_ScalarHalf; @@ -576,12 +690,11 @@ inline void SkFindAndPlaceGlyph::ProcessText( if (cache->isSubpixel()) { SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); InitSubpixel( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); } else { to_init->template initialize< GlyphFindAndPlaceFullPixel< - ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>( - cache, glyphCacheProc); + ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>(glyphFinder); } } }; diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index bb6a6ce90e..c158ec1f2c 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -775,13 +775,14 @@ void GrAtlasTextContext::internalDrawBMPText(GrAtlasTextBlob* blob, int runIndex } fCurrStrike = nullptr; - SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); // Get GrFontScaler from cache GrFontScaler* fontScaler = GetGrFontScaler(cache); SkFindAndPlaceGlyph::ProcessText( - text, byteLength, {x, y}, viewMatrix, skPaint.getTextAlign(), glyphCacheProc, cache, + skPaint.getTextEncoding(), text, byteLength, + {x, y}, viewMatrix, skPaint.getTextAlign(), + cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; this->bmpAppendGlyph( @@ -808,14 +809,14 @@ void GrAtlasTextContext::internalDrawBMPPosText(GrAtlasTextBlob* blob, int runIn } fCurrStrike = nullptr; - SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); // Get GrFontScaler from cache GrFontScaler* fontScaler = GetGrFontScaler(cache); SkFindAndPlaceGlyph::ProcessPosText( - text, byteLength, offset, viewMatrix, pos, scalarsPerPosition, - skPaint.getTextAlign(), glyphCacheProc, cache, + skPaint.getTextEncoding(), text, byteLength, + offset, viewMatrix, pos, scalarsPerPosition, + skPaint.getTextAlign(), cache, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; this->bmpAppendGlyph(