diff options
-rw-r--r-- | bench/TextBlobBench.cpp | 71 | ||||
-rw-r--r-- | gm/mixedtextblobs.cpp | 195 | ||||
-rw-r--r-- | gyp/bench.gypi | 1 | ||||
-rw-r--r-- | gyp/gmslides.gypi | 1 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.cpp | 18 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.h | 2 |
6 files changed, 281 insertions, 7 deletions
diff --git a/bench/TextBlobBench.cpp b/bench/TextBlobBench.cpp new file mode 100644 index 0000000000..1f4b2b7120 --- /dev/null +++ b/bench/TextBlobBench.cpp @@ -0,0 +1,71 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "Resources.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkTemplates.h" +#include "SkTextBlob.h" +#include "SkTypeface.h" + +#include "sk_tool_utils.h" + +/* + * A trivial test which benchmarks the performance of a textblob with a single run. + */ +class TextBlobBench : public Benchmark { +public: + TextBlobBench() + : fTypeface(sk_tool_utils::create_portable_typeface("Times", SkTypeface::kNormal)) { + // make textblob + SkPaint paint; + paint.setTypeface(fTypeface); + const char* text = "Hello blob!"; + SkTDArray<uint16_t> glyphs; + size_t len = strlen(text); + glyphs.append(paint.textToGlyphs(text, len, NULL)); + paint.textToGlyphs(text, len, glyphs.begin()); + + SkTextBlobBuilder builder; + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(paint, glyphs.count(), 10, 10, + NULL); + memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t)); + + fBlob.reset(builder.build()); + } + +protected: + const char* onGetName() { + return "TextBlobBench"; + } + + void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + + // To ensure maximum caching, we just redraw the blob at the same place everytime + for (int i = 0; i < loops; i++) { + canvas->drawTextBlob(fBlob, 0, 0, paint); + } + } + +private: + + SkAutoTUnref<const SkTextBlob> fBlob; + SkTDArray<uint16_t> fGlyphs; + SkAutoTUnref<SkTypeface> fTypeface; + + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new TextBlobBench(); ) diff --git a/gm/mixedtextblobs.cpp b/gm/mixedtextblobs.cpp new file mode 100644 index 0000000000..7aaaa52cf0 --- /dev/null +++ b/gm/mixedtextblobs.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" + +#include "Resources.h" +#include "SkCanvas.h" +#include "SkGradientShader.h" +#include "SkStream.h" +#include "SkTextBlob.h" +#include "SkTypeface.h" + +namespace skiagm { + +static void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, + SkScalar x, SkScalar y) { + SkPaint paint(origPaint); + SkTDArray<uint16_t> glyphs; + + size_t len = strlen(text); + glyphs.append(paint.textToGlyphs(text, len, NULL)); + paint.textToGlyphs(text, len, glyphs.begin()); + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + const SkTextBlobBuilder::RunBuffer& run = builder->allocRun(paint, glyphs.count(), x, y, + NULL); + memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t)); +} + +static void draw_blob(SkCanvas* canvas, const SkTextBlob* blob, const SkPaint& skPaint, + const SkRect& clipRect) { + SkPaint clipHairline; + clipHairline.setColor(SK_ColorWHITE); + clipHairline.setStyle(SkPaint::kStroke_Style); + + SkPaint paint(skPaint); + canvas->save(); + canvas->drawRect(clipRect, clipHairline); + paint.setAlpha(0x20); + canvas->drawTextBlob(blob, 0, 0, paint); + canvas->clipRect(clipRect); + paint.setAlpha(0xFF); + canvas->drawTextBlob(blob, 0, 0, paint); + canvas->restore(); +} + +class MixedTextBlobsGM : public GM { +public: + MixedTextBlobsGM() { } + +protected: + void onOnceBeforeDraw() override { + SkAutoTDelete<SkFILEStream> stream; + SkString filename; +#ifndef SK_BUILD_FOR_MAC + filename = GetResourcePath("/Funkster.ttf"); + stream.reset(new SkFILEStream(filename.c_str())); + if (stream->isValid()) { + fEmojiTypeface.reset(SkTypeface::CreateFromStream(stream.detach())); + } else { + SkDebugf("Could not find Funkster.ttf, please set --resourcePath correctly.\n"); + } + fEmojiText = "Emoji!!!"; +#else + fEmojiTypeface.reset(SkTypeface::CreateFromName("Apple Color Emoji", SkTypeface::kNormal)); + fEmojiText = "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85" // 💰🏡🎅 + "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80"; // 🍪🍕🚀 +#endif + + filename = GetResourcePath("/ReallyBigA.ttf"); + + stream.reset(new SkFILEStream(filename.c_str())); + if (stream->isValid()) { + fReallyBigATypeface.reset(SkTypeface::CreateFromStream(stream.detach())); + } + + SkTextBlobBuilder builder; + + // make textblob + // Text so large we draw as paths + SkPaint paint; + paint.setTextSize(384); + const char* text = "O"; + sk_tool_utils::set_portable_typeface(&paint); + + SkRect bounds; + paint.measureText(text, strlen(text), &bounds); + + SkScalar yOffset = bounds.height(); + add_to_text_blob(&builder, text, paint, 10, yOffset); + SkScalar corruptedAx = bounds.width(); + SkScalar corruptedAy = yOffset; + + const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; + const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; + + SkScalar xOffset = boundsHalfWidth; + yOffset = boundsHalfHeight; + + // LCD + paint.setTextSize(32); + text = "LCD!!!!!"; + paint.setSubpixelText(true); + paint.setLCDRenderText(true); + paint.measureText(text, strlen(text), &bounds); + add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.25f, + yOffset - bounds.height() * 0.5f); + yOffset += bounds.height(); + + // color emoji + paint.setSubpixelText(false); + paint.setLCDRenderText(false); + paint.setTypeface(fEmojiTypeface); + text = fEmojiText; + paint.measureText(text, strlen(text), &bounds); + add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.3f, yOffset); + + // Corrupted font + paint.setTextSize(12); + text = "aA"; + paint.setTypeface(fReallyBigATypeface); + add_to_text_blob(&builder, text, paint, corruptedAx, corruptedAy); + fBlob.reset(builder.build()); + } + + SkString onShortName() override { + return SkString("mixedtextblobs"); + } + + SkISize onISize() override { + return SkISize::Make(kWidth, kHeight); + } + + void onDraw(SkCanvas* canvas) override { + + canvas->drawColor(SK_ColorGRAY); + + SkPaint paint; + + // setup work needed to draw text with different clips + paint.setColor(SK_ColorBLACK); + canvas->translate(10, 40); + + paint.setTextSize(40); + + // compute the bounds of the text and setup some clips + SkRect bounds = fBlob->bounds(); + + const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; + const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; + const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf; + const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf; + + SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(), + boundsHalfWidth, boundsHalfHeight); + SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(), + boundsHalfWidth, boundsHalfHeight); + SkRect interiorClip = bounds; + interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight); + + const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip}; + + size_t count = sizeof(clipRects) / sizeof(SkRect); + for (size_t x = 0; x < count; ++x) { + draw_blob(canvas, fBlob, paint, clipRects[x]); + if (x == (count >> 1) - 1) { + canvas->translate(SkScalarFloorToScalar(bounds.width() + SkIntToScalar(25)), + -(x * SkScalarFloorToScalar(bounds.height() + + SkIntToScalar(25)))); + } else { + canvas->translate(0, SkScalarFloorToScalar(bounds.height() + SkIntToScalar(25))); + } + } + } + +private: + SkAutoTUnref<SkTypeface> fEmojiTypeface; + SkAutoTUnref<SkTypeface> fReallyBigATypeface; + const char* fEmojiText; + SkAutoTUnref<const SkTextBlob> fBlob; + + static const int kWidth = 1250; + static const int kHeight = 700; + + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_GM( return SkNEW(MixedTextBlobsGM); ) +} diff --git a/gyp/bench.gypi b/gyp/bench.gypi index 2efcec2e87..1eb0cbb06d 100644 --- a/gyp/bench.gypi +++ b/gyp/bench.gypi @@ -105,6 +105,7 @@ '../bench/StrokeBench.cpp', '../bench/TableBench.cpp', '../bench/TextBench.cpp', + '../bench/TextBlobBench.cpp', '../bench/TileBench.cpp', '../bench/VertBench.cpp', '../bench/WritePixelsBench.cpp', diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index c575194bee..09615fd2ba 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -142,6 +142,7 @@ '../gm/matriximagefilter.cpp', '../gm/megalooper.cpp', '../gm/mixedxfermodes.cpp', + '../gm/mixedtextblobs.cpp', '../gm/mipmap.cpp', '../gm/modecolorfilters.cpp', '../gm/morphology.cpp', diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index f1af012936..b2de1cf154 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -368,6 +368,7 @@ void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), + skPaint.getColor(), fontScaler, clipRect); } @@ -459,6 +460,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), + skPaint.getColor(), fontScaler, clipRect); } @@ -496,6 +498,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), + skPaint.getColor(), fontScaler, clipRect); } @@ -523,6 +526,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), + skPaint.getColor(), fontScaler, clipRect); } @@ -550,6 +554,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), + skPaint.getColor(), fontScaler, clipRect); } @@ -560,7 +565,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, } void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph::PackedID packed, - int vx, int vy, GrFontScaler* scaler, + int vx, int vy, GrColor color, GrFontScaler* scaler, const SkIRect& clipRect) { if (NULL == fCurrStrike) { fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); @@ -628,7 +633,6 @@ void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph r.fBottom = r.fTop + SkIntToScalar(height); run.fVertexBounds.joinNonEmptyArg(r); - GrColor color = fPaint.getColor(); run.fColor = color; intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVertexEndIndex); @@ -745,6 +749,7 @@ public: } GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); + // This will be ignored in the non A8 case bool opaqueVertexColors = GrColorIsOpaque(this->color()); SkAutoTUnref<const GrGeometryProcessor> gp( @@ -1026,16 +1031,17 @@ void GrAtlasTextContext::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrRen } GrMaskFormat format = info.fMaskFormat; - if (kARGB_GrMaskFormat == format) { - color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); - } + GrColor subRunColor = kARGB_GrMaskFormat == format ? + SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : + color; BitmapTextBatch::Geometry geometry; geometry.fBlob.reset(SkRef(blob)); geometry.fRun = run; geometry.fSubRun = subRun; geometry.fColor = color; - SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, glyphCount, + SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, subRunColor, format, + glyphCount, fContext->getBatchFontCache())); target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertexBounds); diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index 4725ee529d..eb1abbac42 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -142,7 +142,7 @@ private: BitmapTextBlob* CreateBlob(int glyphCount, int runCount); void appendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top, - GrFontScaler*, const SkIRect& clipRect); + GrColor color, GrFontScaler*, const SkIRect& clipRect); void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const GrPaint&, const GrClip&, const SkMatrix& viewMatrix, int paintAlpha); |