diff options
author | herb <herb@google.com> | 2015-11-20 13:53:12 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-20 13:53:12 -0800 |
commit | 4c11b3f8a2d9919a21110dbdd29e67e5cbaa41fb (patch) | |
tree | 1f0bd98bddca74031eeb4657266d5ecf7a5bab9e /src/core | |
parent | 9b137dc54e668ca5552bab8a1c550edc02214db4 (diff) |
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
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkDraw.cpp | 9 | ||||
-rw-r--r-- | src/core/SkFindAndPlaceGlyph.h | 209 |
2 files changed, 165 insertions, 53 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<H, Ts...> { class SkFindAndPlaceGlyph { public: template<typename ProcessOneGlyph> - 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<typename ProcessOneGlyph> - 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<Utf8GlyphFinder>(cache); + break; + case SkPaint::kUTF16_TextEncoding: + to_init->initialize<Utf16GlyphFinder>(cache); + break; + case SkPaint::kUTF32_TextEncoding: + to_init->initialize<Utf32GlyphFinder>(cache); + break; + case SkPaint::kGlyphID_TextEncoding: + to_init->initialize<GlyphIdGlyphFinder>(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<ProcessOneGlyph> { 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<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKerning kUseKerning> class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> { 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<ProcessOneGlyph>::Variants* to_init, SkAxisAlignment axisAlignment, - SkGlyphCache* cache, - SkDrawCacheProc glyphCacheProc) { + LookupGlyph& glyphFinder) { switch (axisAlignment) { case kX_SkAxisAlignment: to_init->template initialize<GlyphFindAndPlaceSubpixel< - ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( - cache, glyphCacheProc); + ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(glyphFinder); break; case kNone_SkAxisAlignment: to_init->template initialize<GlyphFindAndPlaceSubpixel< - ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( - cache, glyphCacheProc); + ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(glyphFinder); break; case kY_SkAxisAlignment: to_init->template initialize<GlyphFindAndPlaceSubpixel< - ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( - 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<typename ProcessOneGlyph> 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<ProcessOneGlyph, SkPaint::kLeft_Align>( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); break; case SkPaint::kCenter_Align: InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>( - to_init, axisAlignment, cache, glyphCacheProc); + to_init, axisAlignment, glyphFinder); break; case SkPaint::kRight_Align: InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>( - 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<ProcessOneGlyph, - SkPaint::kLeft_Align, kNoKerning>>(cache, glyphCacheProc); + SkPaint::kLeft_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kCenter_Align: to_init->template initialize< GlyphFindAndPlaceFullPixel<ProcessOneGlyph, - SkPaint::kCenter_Align, kNoKerning>>(cache, glyphCacheProc); + SkPaint::kCenter_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kRight_Align: to_init->template initialize< GlyphFindAndPlaceFullPixel<ProcessOneGlyph, - SkPaint::kRight_Align, kNoKerning>>(cache, glyphCacheProc); + SkPaint::kRight_Align, kNoKerning>>(glyphFinder); break; } } @@ -554,16 +666,18 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( template<typename ProcessOneGlyph> 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<ProcessOneGlyph, SkPaint::kLeft_Align>( - 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); } } }; |