aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/TextBlobBench.cpp71
-rw-r--r--gm/mixedtextblobs.cpp195
-rw-r--r--gyp/bench.gypi1
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--src/gpu/GrAtlasTextContext.cpp18
-rw-r--r--src/gpu/GrAtlasTextContext.h2
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);