aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkFindAndPlaceGlyph.h
diff options
context:
space:
mode:
authorGravatar herb <herb@google.com>2015-11-20 13:53:12 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-11-20 13:53:12 -0800
commit4c11b3f8a2d9919a21110dbdd29e67e5cbaa41fb (patch)
tree1f0bd98bddca74031eeb4657266d5ecf7a5bab9e /src/core/SkFindAndPlaceGlyph.h
parent9b137dc54e668ca5552bab8a1c550edc02214db4 (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/SkFindAndPlaceGlyph.h')
-rw-r--r--src/core/SkFindAndPlaceGlyph.h209
1 files changed, 161 insertions, 48 deletions
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);
}
}
};