Start canonicalizing color for all A8 textblobs
authorjoshualitt <joshualitt@chromium.org>
Tue, 14 Apr 2015 19:17:27 +0000 (12:17 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Apr 2015 19:17:27 +0000 (12:17 -0700)
BUG=skia:

Review URL: https://codereview.chromium.org/1076593002

12 files changed:
gm/mixedtextblobs.cpp
gm/textblobcolortrans.cpp [new file with mode: 0644]
gm/textbloblooper.cpp
gyp/gmslides.gypi
include/core/SkPaint.h
include/core/SkTextBlob.h
src/core/SkPaint.cpp
src/core/SkTextBlob.cpp
src/gpu/GrAtlasTextContext.cpp
src/gpu/GrAtlasTextContext.h
tools/sk_tool_utils.cpp
tools/sk_tool_utils.h

index 7aaaa52..20b91ac 100644 (file)
 
 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;
@@ -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 (file)
index 0000000..cb4686e
--- /dev/null
@@ -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<const SkTextBlob> fBlob;
+
+    static const int kWidth = 675;
+    static const int kHeight = 1600;
+
+    typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM( return SkNEW(TextBlobColorTrans); )
+}
index 253945f..2fbd30b 100644 (file)
@@ -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);
index 02297c3..3f02937 100644 (file)
         '../gm/tallstretchedbitmaps.cpp',
         '../gm/textblob.cpp',
         '../gm/textbloblooper.cpp',
+        '../gm/textblobcolortrans.cpp',
         '../gm/textblobshader.cpp',
         '../gm/texturedomaineffect.cpp',
         '../gm/thinrects.cpp',
index 991a727..e4be06e 100644 (file)
@@ -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;
 };
index a091f05..b1ae456 100644 (file)
@@ -68,6 +68,7 @@ private:
         const SkPoint& offset() const;
         void applyFontToPaint(SkPaint*) const;
         GlyphPositioning positioning() const;
+        bool isLCD() const;
 
     private:
         const RunRecord* fCurrentRun;
index 2c1745d..9f76355 100644 (file)
@@ -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);
index 3d396de..6ea081d 100644 (file)
@@ -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)
index 9dbe631..59a875e 100644 (file)
@@ -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<BitmapTextBlob> 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);
                 }
index c999e1f..62b5207 100644 (file)
@@ -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<BigGlyph> 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;
index c3e574a..1a88086 100644 (file)
@@ -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<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));
+}
+
+
 }  // namespace sk_tool_utils
index 0299e74..d9345a6 100644 (file)
@@ -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