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
This commit is contained in:
herb 2015-11-20 13:53:12 -08:00 committed by Commit bot
parent 9b137dc54e
commit 4c11b3f8a2
3 changed files with 171 additions and 58 deletions

View File

@ -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);

View File

@ -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,8 +33,9 @@ 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,
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
@ -52,10 +54,10 @@ 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,
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:
@ -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);
}
}
};

View File

@ -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(