aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2014-10-16 08:04:39 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-10-16 08:04:39 -0700
commitaab626c3670205d02ca42bb34a540f550cb75dc2 (patch)
treeab72f4db55616866cbe977d3aff87a6051374db3
parent7851a56895c9c076f73a835a7dd51d3c6180c16f (diff)
Revert of Change drawText() to generate positions and send to drawPosText() (patchset #4 id:60001 of https://codereview.chromium.org/653133004/)
Reason for revert: A large number of GMs on Ubuntu12 are failing. The text layout on GPU is visibly different than that for 8888. Original issue's description: > 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 > > Committed: https://skia.googlesource.com/skia/+/7851a56895c9c076f73a835a7dd51d3c6180c16f TBR=cdalton.nvidia@gmail.com,bungeman@google.com,reed@google.com NOTREECHECKS=true NOTRY=true BUG=skia:2778 Review URL: https://codereview.chromium.org/659993003
-rw-r--r--expectations/gm/ignored-tests.txt12
-rw-r--r--include/core/SkPaint.h1
-rwxr-xr-xsrc/gpu/GrBitmapTextContext.cpp92
-rw-r--r--src/gpu/GrBitmapTextContext.h2
-rwxr-xr-xsrc/gpu/GrDistanceFieldTextContext.cpp88
-rw-r--r--src/gpu/GrDistanceFieldTextContext.h2
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.cpp91
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.h3
-rw-r--r--src/gpu/GrTextContext.cpp65
-rw-r--r--src/gpu/GrTextContext.h2
10 files changed, 279 insertions, 79 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 6469aa6e28..5793ba217b 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -54,15 +54,3 @@ 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
-
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 21ad3eab20..9f477d867b 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -1102,7 +1102,6 @@ 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;
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index a1196dc494..fa70d3270b 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -16,6 +16,7 @@
#include "GrTextStrike_impl.h"
#include "effects/GrCustomCoordsTextureEffect.h"
+#include "SkAutoKern.h"
#include "SkColorPriv.h"
#include "SkDraw.h"
#include "SkDrawProcs.h"
@@ -90,6 +91,97 @@ 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,
diff --git a/src/gpu/GrBitmapTextContext.h b/src/gpu/GrBitmapTextContext.h
index 7a73b7b109..7a93820a16 100644
--- a/src/gpu/GrBitmapTextContext.h
+++ b/src/gpu/GrBitmapTextContext.h
@@ -45,6 +45,8 @@ 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,
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index ce2b1759bc..9fa0c1d7b8 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -28,9 +28,6 @@
#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.");
@@ -210,6 +207,81 @@ 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,
@@ -254,8 +326,7 @@ void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
pos += scalarsPerPosition;
}
} else {
- SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
- : SK_Scalar1;
+ int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
while (text < stop) {
// the last 2 parameters are ignored
const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
@@ -264,14 +335,11 @@ 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 - advanceX),
- SkScalarToFixed(y - advanceY),
+ SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
+ SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
fontScaler);
}
pos += scalarsPerPosition;
diff --git a/src/gpu/GrDistanceFieldTextContext.h b/src/gpu/GrDistanceFieldTextContext.h
index b1cf5593e1..6fa2d6f173 100644
--- a/src/gpu/GrDistanceFieldTextContext.h
+++ b/src/gpu/GrDistanceFieldTextContext.h
@@ -50,6 +50,8 @@ 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,
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 9b4c4d7754..b53ff797fa 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -11,6 +11,7 @@
#include "GrGpu.h"
#include "GrPath.h"
#include "GrPathRange.h"
+#include "SkAutoKern.h"
#include "SkDraw.h"
#include "SkDrawProcs.h"
#include "SkGlyphCache.h"
@@ -61,6 +62,96 @@ 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[],
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index 5985c20192..40d38c2375 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -68,6 +68,9 @@ 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,
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 869706e652..94c05a7124 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -44,63 +44,16 @@ bool GrTextContext::drawText(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) {
- 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);
+ GrTextContext* textContext = this;
+ do {
+ if (textContext->canDraw(skPaint)) {
+ textContext->onDrawText(paint, skPaint, text, byteLength, x, y);
+ return true;
+ }
+ textContext = textContext->fFallbackTextContext;
+ } while (textContext);
- return this->drawPosText(paint, skPaint, text, byteLength, positions.begin(), 2, offset);
+ return false;
}
bool GrTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
diff --git a/src/gpu/GrTextContext.h b/src/gpu/GrTextContext.h
index ec24fa7760..95344dd39f 100644
--- a/src/gpu/GrTextContext.h
+++ b/src/gpu/GrTextContext.h
@@ -46,6 +46,8 @@ 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,