From 9e36c1a9306f052331550dab4728b9875127bfb5 Mon Sep 17 00:00:00 2001 From: joshualitt Date: Tue, 14 Apr 2015 12:17:27 -0700 Subject: [PATCH] Start canonicalizing color for all A8 textblobs BUG=skia: Review URL: https://codereview.chromium.org/1076593002 --- gm/mixedtextblobs.cpp | 26 +++-------- gm/textblobcolortrans.cpp | 100 +++++++++++++++++++++++++++++++++++++++++ gm/textbloblooper.cpp | 1 + gyp/gmslides.gypi | 1 + include/core/SkPaint.h | 8 ++++ include/core/SkTextBlob.h | 1 + src/core/SkPaint.cpp | 6 +-- src/core/SkTextBlob.cpp | 7 +++ src/gpu/GrAtlasTextContext.cpp | 100 ++++++++++++++++++++++++++++++----------- src/gpu/GrAtlasTextContext.h | 21 ++++++--- tools/sk_tool_utils.cpp | 17 +++++++ tools/sk_tool_utils.h | 5 +++ 12 files changed, 237 insertions(+), 56 deletions(-) create mode 100644 gm/textblobcolortrans.cpp diff --git a/gm/mixedtextblobs.cpp b/gm/mixedtextblobs.cpp index 7aaaa52..20b91ac 100644 --- a/gm/mixedtextblobs.cpp +++ b/gm/mixedtextblobs.cpp @@ -16,21 +16,6 @@ namespace skiagm { -static void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, - SkScalar x, SkScalar y) { - SkPaint paint(origPaint); - SkTDArray 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; @@ -91,7 +76,7 @@ protected: paint.measureText(text, strlen(text), &bounds); SkScalar yOffset = bounds.height(); - add_to_text_blob(&builder, text, paint, 10, yOffset); + sk_tool_utils::add_to_text_blob(&builder, text, paint, 10, yOffset); SkScalar corruptedAx = bounds.width(); SkScalar corruptedAy = yOffset; @@ -107,8 +92,8 @@ protected: 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); + sk_tool_utils::add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.25f, + yOffset - bounds.height() * 0.5f); yOffset += bounds.height(); // color emoji @@ -117,13 +102,14 @@ protected: paint.setTypeface(fEmojiTypeface); text = fEmojiText; paint.measureText(text, strlen(text), &bounds); - add_to_text_blob(&builder, text, paint, xOffset - bounds.width() * 0.3f, yOffset); + sk_tool_utils::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); + sk_tool_utils::add_to_text_blob(&builder, text, paint, corruptedAx, corruptedAy); fBlob.reset(builder.build()); } diff --git a/gm/textblobcolortrans.cpp b/gm/textblobcolortrans.cpp new file mode 100644 index 0000000..cb4686e --- /dev/null +++ b/gm/textblobcolortrans.cpp @@ -0,0 +1,100 @@ +/* + * 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 "gm.h" + +#include "Resources.h" +#include "SkCanvas.h" +#include "SkGradientShader.h" +#include "SkStream.h" +#include "SkTextBlob.h" +#include "SkTypeface.h" + +namespace skiagm { +class TextBlobColorTrans : public GM { +public: + // This gm tests that textblobs can be translated and have their colors regenerated + // correctly. With smaller atlas sizes, it can also trigger regeneration of texture coords on + // the GPU backend + TextBlobColorTrans() { } + +protected: + void onOnceBeforeDraw() override { + SkTextBlobBuilder builder; + + // make textblob + // Large text is used to trigger atlas eviction + SkPaint paint; + paint.setTextSize(256); + const char* text = "AB"; + sk_tool_utils::set_portable_typeface(&paint); + + SkRect bounds; + paint.measureText(text, strlen(text), &bounds); + + SkScalar yOffset = bounds.height(); + sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset - 30); + + // A8 + paint.setTextSize(28); + text = "The quick brown fox jumps over the lazy dog."; + paint.setSubpixelText(false); + paint.setLCDRenderText(false); + paint.measureText(text, strlen(text), &bounds); + sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset - 8); + + // build + fBlob.reset(builder.build()); + } + + SkString onShortName() override { + return SkString("textblobcolortrans"); + } + + SkISize onISize() override { + return SkISize::Make(kWidth, kHeight); + } + + void onDraw(SkCanvas* canvas) override { + + canvas->drawColor(SK_ColorGRAY); + + SkPaint paint; + canvas->translate(10, 40); + + SkRect bounds = fBlob->bounds(); + + // Colors were chosen to map to pairs of canonical colors. The GPU Backend will cache A8 + // Texture Blobs based on the canonical color they map to. Canonical colors are used to + // create masks. For A8 there are 8 of them. + SkColor colors[] = {SK_ColorCYAN, SK_ColorLTGRAY, SK_ColorYELLOW, SK_ColorWHITE}; + + size_t count = SK_ARRAY_COUNT(colors); + size_t colorIndex = 0; + for (int y = 0; y + SkScalarFloorToInt(bounds.height()) < kHeight; + y += SkScalarFloorToInt(bounds.height())) { + paint.setColor(colors[colorIndex++ % count]); + canvas->save(); + canvas->translate(0, SkIntToScalar(y)); + canvas->drawTextBlob(fBlob, 0, 0, paint); + canvas->restore(); + } + } + +private: + SkAutoTUnref fBlob; + + static const int kWidth = 675; + static const int kHeight = 1600; + + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_GM( return SkNEW(TextBlobColorTrans); ) +} diff --git a/gm/textbloblooper.cpp b/gm/textbloblooper.cpp index 253945f..2fbd30b 100644 --- a/gm/textbloblooper.cpp +++ b/gm/textbloblooper.cpp @@ -23,6 +23,7 @@ namespace skiagm { static const int kWidth = 1250; static const int kHeight = 700; +// Unlike the variant in sk_tool_utils, this version positions the glyphs on a diagonal static void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, SkScalar x, SkScalar y) { SkPaint paint(origPaint); diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index 02297c3..3f02937 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -211,6 +211,7 @@ '../gm/tallstretchedbitmaps.cpp', '../gm/textblob.cpp', '../gm/textbloblooper.cpp', + '../gm/textblobcolortrans.cpp', '../gm/textblobshader.cpp', '../gm/texturedomaineffect.cpp', '../gm/thinrects.cpp', diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 991a727..e4be06e 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -1076,6 +1076,13 @@ private: void (*proc)(SkTypeface*, const SkDescriptor*, void*), void* context, bool ignoreGamma = false) const; + /* + * The luminance color is used to determine which Gamma Canonical color to map to. This is + * really only used by backends which want to cache glyph masks, and need some way to know if + * they need to generate new masks based off a given color. + */ + SkColor computeLuminanceColor() const; + static void Term(); enum { @@ -1129,6 +1136,7 @@ private: friend class GrPathRendering; friend class GrTextContext; friend class GrGLPathRendering; + friend class SkScalerContext; friend class SkTextToPathIter; friend class SkCanonicalizePaint; }; diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h index a091f05..b1ae456 100644 --- a/include/core/SkTextBlob.h +++ b/include/core/SkTextBlob.h @@ -68,6 +68,7 @@ private: const SkPoint& offset() const; void applyFontToPaint(SkPaint*) const; GlyphPositioning positioning() const; + bool isLCD() const; private: const RunRecord* fCurrentRun; diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 2c1745d..9f76355 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1291,9 +1291,9 @@ static bool justAColor(const SkPaint& paint, SkColor* color) { return true; } -static SkColor computeLuminanceColor(const SkPaint& paint) { +SkColor SkPaint::computeLuminanceColor() const { SkColor c; - if (!justAColor(paint, &c)) { + if (!justAColor(*this, &c)) { c = SkColorSetRGB(0x7F, 0x80, 0x7F); } return c; @@ -1463,7 +1463,7 @@ void SkScalerContext::MakeRec(const SkPaint& paint, // these modify fFlags, so do them after assigning fFlags rec->setHinting(computeHinting(paint)); - rec->setLuminanceColor(computeLuminanceColor(paint)); + rec->setLuminanceColor(paint.computeLuminanceColor()); if (NULL == deviceProperties) { rec->setDeviceGamma(SK_GAMMA_EXPONENT); diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp index 3d396de..6ea081d 100644 --- a/src/core/SkTextBlob.cpp +++ b/src/core/SkTextBlob.cpp @@ -47,6 +47,9 @@ public: bool operator!=(const RunFont& other) const { return !(*this == other); } + + uint32_t flags() const { return fFlags; } + private: const static uint32_t kFlagsMask = SkPaint::kAntiAlias_Flag | @@ -343,6 +346,10 @@ void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { fCurrentRun->font().applyToPaint(paint); } +bool SkTextBlob::RunIterator::isLCD() const { + return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); +} + SkTextBlobBuilder::SkTextBlobBuilder() : fStorageSize(0) , fStorageUsed(0) diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index 9dbe631..59a875e 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -91,13 +91,47 @@ bool GrAtlasTextContext::canDraw(const GrRenderTarget*, return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); } +GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { + GrColor canonicalColor = paint.computeLuminanceColor(); + if (lcd) { + // This is the correct computation, but there are tons of cases where LCD can be overridden. + // For now we just regenerate if any run in a textblob has LCD. + // TODO figure out where all of these overrides are and see if we can incorporate that logic + // at a higher level *OR* use sRGB + SkASSERT(false); + //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor); + } else { + // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have + // gamma corrected masks anyways, nor color + U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor), + SkColorGetG(canonicalColor), + SkColorGetB(canonicalColor)); + // reduce to our finite number of bits + canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum)); + } + return canonicalColor; +} + +// TODO if this function ever shows up in profiling, then we can compute this value when the +// textblob is being built and cache it. However, for the time being textblobs mostly only have 1 +// run so this is not a big deal to compute here. +bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { + SkTextBlob::RunIterator it(blob); + for (; !it.done(); it.next()) { + if (it.isLCD()) { + return true; + } + } + return false; +} + bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, const BitmapTextBlob& blob, const SkPaint& paint, const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { - // Color can affect the mask - // TODO we can adjust the color within specific gamma slots - if (blob.fColor != paint.getColor()) { + // If we have LCD text then our canonical color will be set to transparent, in this case we have + // to regenerate the blob on any color change + if (blob.fKey.fCanonicalColor == SK_ColorTRANSPARENT && blob.fPaintColor != paint.getColor()) { return true; } @@ -180,7 +214,6 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { SkAutoTUnref cacheBlob; - SkMaskFilter::BlurRec blurRec; BitmapTextBlob::Key key; // It might be worth caching these things, but its not clear at this time @@ -191,9 +224,17 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, drawFilter); if (canCache) { + bool hasLCD = HasLCD(blob); + // TODO we want to figure out a way to be able to use the canonical color on LCD text, + // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to + // ensure we always match the same key + GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : + ComputeCanonicalColor(skPaint, hasLCD); + key.fUniqueID = blob->uniqueID(); key.fStyle = skPaint.getStyle(); key.fHasBlur = SkToBool(mf); + key.fCanonicalColor = canonicalColor; cacheBlob.reset(SkSafeRef(fCache->find(key))); } @@ -203,6 +244,11 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, SkScalar transX = 0.f; SkScalar transY = 0.f; + // Though for the time being runs in the textblob can override the paint, they only touch font + // info. + GrPaint grPaint; + SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); + if (cacheBlob) { if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, blurRec, viewMatrix, x, y)) { // We have to remake the blob because changes may invalidate our masks. @@ -211,11 +257,11 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, fCache->remove(cacheBlob); cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, kGrayTextVASize))); - this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, - clipRect); + this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y, + drawFilter, clipRect); } else { - // If we can reuse the blob, then make sure we update the blob's viewmatrix and x/y - // offsets to reflect the results of any translations we may apply in generateGeometry + // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y + // offsets cacheBlob->fViewMatrix = viewMatrix; cacheBlob->fX = x; cacheBlob->fY = y; @@ -228,26 +274,23 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, } else { cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); } - this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect); + this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y, + drawFilter, clipRect); } - // Though for the time being runs in the textblob can override the paint, they only touch font - // info. - GrPaint grPaint; - SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); - + cacheBlob->fPaintColor = skPaint.getColor(); this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint, drawFilter, clip, viewMatrix, clipBounds, x, y, transX, transY); } void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, - const SkPaint& skPaint, const SkMatrix& viewMatrix, + const SkPaint& skPaint, GrColor color, + const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipRect) { cacheBlob->fViewMatrix = viewMatrix; cacheBlob->fX = x; cacheBlob->fY = y; - cacheBlob->fColor = skPaint.getColor(); // Regenerate textblob SkPaint runPaint = skPaint; @@ -290,17 +333,17 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatrix, + this->internalDrawText(cacheBlob, run, cache, runPaint, color, viewMatrix, (const char *)it.glyphs(), textLen, x + offset.x(), y + offset.y(), clipRect); break; case SkTextBlob::kHorizontal_Positioning: - this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix, + this->internalDrawPosText(cacheBlob, run, cache, runPaint, color, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), clipRect); break; case SkTextBlob::kFull_Positioning: - this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix, + this->internalDrawPosText(cacheBlob, run, cache, runPaint, color, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), clipRect); break; @@ -331,7 +374,8 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, // setup cache SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix); - this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, x, y, clipRect); + this->internalDrawText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text, byteLength, + x, y, clipRect); SkGlyphCache::AttachCache(cache); this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewMatrix); @@ -339,6 +383,7 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, + GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect) { @@ -417,7 +462,7 @@ void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), - skPaint.getColor(), + color, fontScaler, clipRect); } @@ -442,8 +487,8 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, // setup cache SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix); - this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, pos, - scalarsPerPosition, offset, clipRect); + this->internalDrawPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text, + byteLength, pos, scalarsPerPosition, offset, clipRect); SkGlyphCache::AttachCache(cache); this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewMatrix); @@ -451,6 +496,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, SkGlyphCache* cache, const SkPaint& skPaint, + GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, @@ -508,7 +554,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), - skPaint.getColor(), + color, fontScaler, clipRect); } @@ -546,7 +592,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), - skPaint.getColor(), + color, fontScaler, clipRect); } @@ -574,7 +620,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), - skPaint.getColor(), + color, fontScaler, clipRect); } @@ -602,7 +648,7 @@ void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), - skPaint.getColor(), + color, fontScaler, clipRect); } diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index c999e1f..62b5207 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -57,8 +57,8 @@ private: * * The only thing(aside from a memcopy) required to flush a BitmapTextBlob is to ensure that * the GrAtlas will not evict anything the Blob needs. - * TODO this is currently a bug */ + // TODO Pack these bytes struct BitmapTextBlob : public SkRefCnt { SK_DECLARE_INTERNAL_LLIST_INTERFACE(BitmapTextBlob); @@ -127,8 +127,8 @@ private: mutable SkScalar fTotalXError; mutable SkScalar fTotalYError; #endif + SkColor fPaintColor; SkTArray fBigGlyphs; - GrColor fColor; // the original color on the paint SkMatrix fViewMatrix; SkScalar fX; SkScalar fY; @@ -149,10 +149,15 @@ private: struct Key { Key() { - memset(this, 0, sizeof(Key)); + sk_bzero(this, sizeof(Key)); } uint32_t fUniqueID; SkPaint::Style fStyle; + // Color may affect the gamma of the mask we generate, but in a fairly limited way. + // Each color is assigned to on of a fixed number of buckets based on its + // luminance. For each luminance bucket there is a "canonical color" that + // represents the bucket. This functionality is currently only supported for A8 + SkColor fCanonicalColor; bool fHasBlur; bool operator==(const Key& other) const { @@ -207,23 +212,27 @@ private: const GrPaint&, const GrClip&, const SkMatrix& viewMatrix); void internalDrawText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, + GrColor color, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect); void internalDrawPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, - const SkMatrix& viewMatrix, + GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipRect); // sets up the descriptor on the blob and returns a detached cache. Client must attach + inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd); inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix& viewMatrix); static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, const BitmapTextBlob&, const SkPaint&, const SkMaskFilter::BlurRec&, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, const SkMatrix& viewMatrix, + void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor, + const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipRect); + inline static bool HasLCD(const SkTextBlob*); GrBatchTextStrike* fCurrStrike; GrTextBlobCache* fCache; diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp index c3e574a..1a88086 100644 --- a/tools/sk_tool_utils.cpp +++ b/tools/sk_tool_utils.cpp @@ -12,6 +12,7 @@ #include "SkCanvas.h" #include "SkShader.h" #include "SkTestScalerContext.h" +#include "SkTextBlob.h" DEFINE_bool(portableFonts, false, "Use portable fonts"); DEFINE_bool(resourceFonts, false, "Use resource fonts"); @@ -77,4 +78,20 @@ void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) { canvas->drawPaint(paint); } +void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, + SkScalar x, SkScalar y) { + SkPaint paint(origPaint); + SkTDArray 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)); +} + + } // namespace sk_tool_utils diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h index 0299e74..d9345a6 100644 --- a/tools/sk_tool_utils.h +++ b/tools/sk_tool_utils.h @@ -19,6 +19,7 @@ class SkCanvas; class SkPaint; class SkShader; class SkTestFont; +class SkTextBlobBuilder; namespace sk_tool_utils { @@ -69,6 +70,10 @@ namespace sk_tool_utils { } }; + // A helper for inserting a drawtext call into a SkTextBlobBuilder + void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, + SkScalar x, SkScalar y); + } // namespace sk_tool_utils #endif // sk_tool_utils_DEFINED -- 2.7.4