Change drawText() to generate positions and send to drawPosText()
The idea here is to have a central place that does layout for drawText(), and then always feed text through drawPosText(). This both makes all of the GrTextContexts consistent in drawText() output, and does a better job of stressing drawPosText(). Because of the effect of matrices on hinting and approximation error, the generated text is not 100% identical to that produced by the raster pipeline. BUG=skia:2778 Review URL: https://codereview.chromium.org/653133004
This commit is contained in:
parent
8c0d2aab62
commit
7851a56895
@ -54,3 +54,15 @@ megalooper_0x0
|
||||
megalooper_1x4
|
||||
megalooper_4x1
|
||||
imagefiltersbase
|
||||
|
||||
# jvanverth https://codereview.chromium.org/653133004/
|
||||
fontscaler
|
||||
fontmgr_iter
|
||||
fontmgr_match
|
||||
fontcache
|
||||
typefacestyles_kerning
|
||||
lcdtext
|
||||
textblobshader
|
||||
textblob
|
||||
verttext
|
||||
|
||||
|
@ -1102,6 +1102,7 @@ private:
|
||||
friend class SkDraw;
|
||||
friend class SkGraphics; // So Term() can be called.
|
||||
friend class SkPDFDevice;
|
||||
friend class GrTextContext;
|
||||
friend class GrBitmapTextContext;
|
||||
friend class GrDistanceFieldTextContext;
|
||||
friend class GrStencilAndCoverTextContext;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "GrTextStrike_impl.h"
|
||||
#include "effects/GrCustomCoordsTextureEffect.h"
|
||||
|
||||
#include "SkAutoKern.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkDrawProcs.h"
|
||||
@ -91,97 +90,6 @@ inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPai
|
||||
fMaxVertices = 0;
|
||||
}
|
||||
|
||||
void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) {
|
||||
SkASSERT(byteLength == 0 || text != NULL);
|
||||
|
||||
// nothing to draw
|
||||
if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(paint, skPaint);
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
||||
|
||||
SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
|
||||
SkGlyphCache* cache = autoCache.getCache();
|
||||
GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
||||
|
||||
// transform our starting point
|
||||
{
|
||||
SkPoint loc;
|
||||
fContext->getMatrix().mapXY(x, y, &loc);
|
||||
x = loc.fX;
|
||||
y = loc.fY;
|
||||
}
|
||||
|
||||
// need to measure first
|
||||
if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
|
||||
SkVector stop;
|
||||
|
||||
MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
|
||||
|
||||
SkScalar stopX = stop.fX;
|
||||
SkScalar stopY = stop.fY;
|
||||
|
||||
if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
||||
stopX = SkScalarHalf(stopX);
|
||||
stopY = SkScalarHalf(stopY);
|
||||
}
|
||||
x -= stopX;
|
||||
y -= stopY;
|
||||
}
|
||||
|
||||
const char* stop = text + byteLength;
|
||||
|
||||
SkAutoKern autokern;
|
||||
|
||||
SkFixed fxMask = ~0;
|
||||
SkFixed fyMask = ~0;
|
||||
SkFixed halfSampleX, halfSampleY;
|
||||
if (cache->isSubpixel()) {
|
||||
halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
|
||||
SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
|
||||
if (kX_SkAxisAlignment == baseline) {
|
||||
fyMask = 0;
|
||||
halfSampleY = SK_FixedHalf;
|
||||
} else if (kY_SkAxisAlignment == baseline) {
|
||||
fxMask = 0;
|
||||
halfSampleX = SK_FixedHalf;
|
||||
}
|
||||
} else {
|
||||
halfSampleX = halfSampleY = SK_FixedHalf;
|
||||
}
|
||||
|
||||
SkFixed fx = SkScalarToFixed(x) + halfSampleX;
|
||||
SkFixed fy = SkScalarToFixed(y) + halfSampleY;
|
||||
|
||||
GrContext::AutoMatrix autoMatrix;
|
||||
autoMatrix.setIdentity(fContext, &fPaint);
|
||||
|
||||
while (text < stop) {
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
|
||||
|
||||
fx += autokern.adjust(glyph);
|
||||
|
||||
if (glyph.fWidth) {
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkFixedFloorToFixed(fx),
|
||||
SkFixedFloorToFixed(fy),
|
||||
fontScaler);
|
||||
}
|
||||
|
||||
fx += glyph.fAdvanceX;
|
||||
fy += glyph.fAdvanceY;
|
||||
}
|
||||
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
@ -45,8 +45,6 @@ private:
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
virtual void onDrawPosText(const GrPaint&, const SkPaint&,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "SkStrokeRec.h"
|
||||
#include "effects/GrDistanceFieldTextureEffect.h"
|
||||
|
||||
#include "SkDrawProcs.h"
|
||||
#include "SkTextMapStateProc.h"
|
||||
|
||||
SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
|
||||
"Dump the contents of the font cache before every purge.");
|
||||
|
||||
@ -207,81 +210,6 @@ static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
|
||||
}
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) {
|
||||
SkASSERT(byteLength == 0 || text != NULL);
|
||||
|
||||
// nothing to draw or can't draw
|
||||
if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
|
||||
|| fSkPaint.getRasterizer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(paint, skPaint);
|
||||
|
||||
SkScalar sizeRatio = fTextRatio;
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
||||
|
||||
SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
|
||||
SkGlyphCache* cache = autoCache.getCache();
|
||||
GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
||||
|
||||
setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
|
||||
|
||||
// need to measure first
|
||||
// TODO - generate positions and pre-load cache as well?
|
||||
const char* stop = text + byteLength;
|
||||
if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
|
||||
SkFixed stopX = 0;
|
||||
SkFixed stopY = 0;
|
||||
|
||||
const char* textPtr = text;
|
||||
while (textPtr < stop) {
|
||||
// don't need x, y here, since all subpixel variants will have the
|
||||
// same advance
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
|
||||
|
||||
stopX += glyph.fAdvanceX;
|
||||
stopY += glyph.fAdvanceY;
|
||||
}
|
||||
SkASSERT(textPtr == stop);
|
||||
|
||||
SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
|
||||
SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
|
||||
|
||||
if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
||||
alignX = SkScalarHalf(alignX);
|
||||
alignY = SkScalarHalf(alignY);
|
||||
}
|
||||
|
||||
x -= alignX;
|
||||
y -= alignY;
|
||||
}
|
||||
|
||||
SkFixed fx = SkScalarToFixed(x);
|
||||
SkFixed fy = SkScalarToFixed(y);
|
||||
SkFixed fixedScale = SkScalarToFixed(sizeRatio);
|
||||
while (text < stop) {
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
||||
|
||||
if (glyph.fWidth) {
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
fx,
|
||||
fy,
|
||||
fontScaler);
|
||||
}
|
||||
|
||||
fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
|
||||
fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
|
||||
}
|
||||
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
@ -326,7 +254,8 @@ void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
|
||||
pos += scalarsPerPosition;
|
||||
}
|
||||
} else {
|
||||
int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
|
||||
SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
|
||||
: SK_Scalar1;
|
||||
while (text < stop) {
|
||||
// the last 2 parameters are ignored
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
||||
@ -335,11 +264,14 @@ void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
|
||||
SkScalar x = offset.x() + pos[0];
|
||||
SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
|
||||
|
||||
SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX)*alignMul*fTextRatio;
|
||||
SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY)*alignMul*fTextRatio;
|
||||
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
|
||||
SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
|
||||
SkScalarToFixed(x - advanceX),
|
||||
SkScalarToFixed(y - advanceY),
|
||||
fontScaler);
|
||||
}
|
||||
pos += scalarsPerPosition;
|
||||
|
@ -50,8 +50,6 @@ private:
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
virtual void onDrawPosText(const GrPaint&, const SkPaint&,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "GrGpu.h"
|
||||
#include "GrPath.h"
|
||||
#include "GrPathRange.h"
|
||||
#include "SkAutoKern.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkDrawProcs.h"
|
||||
#include "SkGlyphCache.h"
|
||||
@ -62,96 +61,6 @@ bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
|
||||
return rec.getFormat() != SkMask::kARGB32_Format;
|
||||
}
|
||||
|
||||
void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint,
|
||||
const SkPaint& skPaint,
|
||||
const char text[],
|
||||
size_t byteLength,
|
||||
SkScalar x, SkScalar y) {
|
||||
SkASSERT(byteLength == 0 || text != NULL);
|
||||
|
||||
if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the slow path, mainly used by Skia unit tests. The other
|
||||
// backends (8888, gpu, ...) use device-space dependent glyph caches. In
|
||||
// order to match the glyph positions that the other code paths produce, we
|
||||
// must also use device-space dependent glyph cache. This has the
|
||||
// side-effect that the glyph shape outline will be in device-space,
|
||||
// too. This in turn has the side-effect that NVPR can not stroke the paths,
|
||||
// as the stroke in NVPR is defined in object-space.
|
||||
// NOTE: here we have following coincidence that works at the moment:
|
||||
// - When using the device-space glyphs, the transforms we pass to NVPR
|
||||
// instanced drawing are the global transforms, and the view transform is
|
||||
// identity. NVPR can not use non-affine transforms in the instanced
|
||||
// drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
|
||||
// will turn off the use of device-space glyphs when perspective transforms
|
||||
// are in use.
|
||||
|
||||
this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode, SkPoint::Make(0, 0));
|
||||
|
||||
// Transform our starting point.
|
||||
if (fNeedsDeviceSpaceGlyphs) {
|
||||
SkPoint loc;
|
||||
fContextInitialMatrix.mapXY(x, y, &loc);
|
||||
x = loc.fX;
|
||||
y = loc.fY;
|
||||
}
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
||||
|
||||
fTransformType = GrPathRendering::kTranslate_PathTransformType;
|
||||
|
||||
const char* stop = text + byteLength;
|
||||
|
||||
// Measure first if needed.
|
||||
if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
|
||||
SkFixed stopX = 0;
|
||||
SkFixed stopY = 0;
|
||||
|
||||
const char* textPtr = text;
|
||||
while (textPtr < stop) {
|
||||
// We don't need x, y here, since all subpixel variants will have the
|
||||
// same advance.
|
||||
const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);
|
||||
|
||||
stopX += glyph.fAdvanceX;
|
||||
stopY += glyph.fAdvanceY;
|
||||
}
|
||||
SkASSERT(textPtr == stop);
|
||||
|
||||
SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
|
||||
SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
|
||||
|
||||
if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
||||
alignX = SkScalarHalf(alignX);
|
||||
alignY = SkScalarHalf(alignY);
|
||||
}
|
||||
|
||||
x -= alignX;
|
||||
y -= alignY;
|
||||
}
|
||||
|
||||
SkAutoKern autokern;
|
||||
|
||||
SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
|
||||
|
||||
SkFixed fx = SkScalarToFixed(x);
|
||||
SkFixed fy = SkScalarToFixed(y);
|
||||
while (text < stop) {
|
||||
const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
|
||||
fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio);
|
||||
if (glyph.fWidth) {
|
||||
this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedToScalar(fy));
|
||||
}
|
||||
|
||||
fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio);
|
||||
fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio);
|
||||
}
|
||||
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint,
|
||||
const SkPaint& skPaint,
|
||||
const char text[],
|
||||
|
@ -68,9 +68,6 @@ private:
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[],
|
||||
size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
virtual void onDrawPosText(const GrPaint&, const SkPaint&,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
@ -44,16 +44,63 @@ bool GrTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) {
|
||||
|
||||
GrTextContext* textContext = this;
|
||||
do {
|
||||
if (textContext->canDraw(skPaint)) {
|
||||
textContext->onDrawText(paint, skPaint, text, byteLength, x, y);
|
||||
return true;
|
||||
}
|
||||
textContext = textContext->fFallbackTextContext;
|
||||
} while (textContext);
|
||||
SkASSERT(byteLength == 0 || text != NULL);
|
||||
|
||||
return false;
|
||||
// nothing to draw
|
||||
if (text == NULL || byteLength == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
|
||||
SkAutoGlyphCache autoCache(skPaint, &fDeviceProperties, NULL);
|
||||
SkGlyphCache* cache = autoCache.getCache();
|
||||
|
||||
SkTArray<SkScalar> positions;
|
||||
|
||||
const char* textPtr = text;
|
||||
SkFixed stopX = 0;
|
||||
SkFixed stopY = 0;
|
||||
SkFixed origin;
|
||||
switch (skPaint.getTextAlign()) {
|
||||
case SkPaint::kRight_Align: origin = SK_Fixed1; break;
|
||||
case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
|
||||
case SkPaint::kLeft_Align: origin = 0; break;
|
||||
default: SkFAIL("Invalid paint origin"); return false;
|
||||
}
|
||||
|
||||
SkAutoKern autokern;
|
||||
const char* stop = text + byteLength;
|
||||
while (textPtr < stop) {
|
||||
// don't need x, y here, since all subpixel variants will have the
|
||||
// same advance
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
|
||||
|
||||
SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
|
||||
positions.push_back(SkFixedToScalar(stopX + SkFixedMul_portable(origin, width)));
|
||||
|
||||
SkFixed height = glyph.fAdvanceY;
|
||||
positions.push_back(SkFixedToScalar(stopY + SkFixedMul_portable(origin, height)));
|
||||
|
||||
stopX += width;
|
||||
stopY += height;
|
||||
}
|
||||
SkASSERT(textPtr == stop);
|
||||
|
||||
// now adjust starting point depending on alignment
|
||||
SkScalar alignX = SkFixedToScalar(stopX);
|
||||
SkScalar alignY = SkFixedToScalar(stopY);
|
||||
if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
||||
alignX = SkScalarHalf(alignX);
|
||||
alignY = SkScalarHalf(alignY);
|
||||
} else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
|
||||
alignX = 0;
|
||||
alignY = 0;
|
||||
}
|
||||
x -= alignX;
|
||||
y -= alignY;
|
||||
SkPoint offset = SkPoint::Make(x, y);
|
||||
|
||||
return this->drawPosText(paint, skPaint, text, byteLength, positions.begin(), 2, offset);
|
||||
}
|
||||
|
||||
bool GrTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
|
@ -46,8 +46,6 @@ protected:
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) = 0;
|
||||
|
||||
virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) = 0;
|
||||
virtual void onDrawPosText(const GrPaint&, const SkPaint&,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
Loading…
Reference in New Issue
Block a user