Index: src/core/SkFindAndPlaceGlyph.h |
diff --git a/src/core/SkFindAndPlaceGlyph.h b/src/core/SkFindAndPlaceGlyph.h |
index 15000b3d58395ab6e028b3a0555052c5b710d46d..278be07e0b878538de9e5e7924d809be6fc1570f 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); |
} |
} |
}; |