diff options
author | jvanverth <jvanverth@google.com> | 2014-10-16 08:04:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-16 08:04:39 -0700 |
commit | aab626c3670205d02ca42bb34a540f550cb75dc2 (patch) | |
tree | ab72f4db55616866cbe977d3aff87a6051374db3 | |
parent | 7851a56895c9c076f73a835a7dd51d3c6180c16f (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.txt | 12 | ||||
-rw-r--r-- | include/core/SkPaint.h | 1 | ||||
-rwxr-xr-x | src/gpu/GrBitmapTextContext.cpp | 92 | ||||
-rw-r--r-- | src/gpu/GrBitmapTextContext.h | 2 | ||||
-rwxr-xr-x | src/gpu/GrDistanceFieldTextContext.cpp | 88 | ||||
-rw-r--r-- | src/gpu/GrDistanceFieldTextContext.h | 2 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.cpp | 91 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.h | 3 | ||||
-rw-r--r-- | src/gpu/GrTextContext.cpp | 65 | ||||
-rw-r--r-- | src/gpu/GrTextContext.h | 2 |
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, |