diff options
author | joshualitt <joshualitt@chromium.org> | 2015-04-14 12:17:27 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-14 12:17:27 -0700 |
commit | 9e36c1a9306f052331550dab4728b9875127bfb5 (patch) | |
tree | dc081124538053c3d28376cb767527326da74d25 /src | |
parent | 8fe8fffdfa7464c6f7da773b8660a2043f4998e0 (diff) |
Start canonicalizing color for all A8 textblobs
BUG=skia:
Review URL: https://codereview.chromium.org/1076593002
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPaint.cpp | 6 | ||||
-rw-r--r-- | src/core/SkTextBlob.cpp | 7 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.cpp | 100 | ||||
-rw-r--r-- | src/gpu/GrAtlasTextContext.h | 21 |
4 files changed, 98 insertions, 36 deletions
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 2c1745d00b..9f76355aac 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 3d396deba5..6ea081d764 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 9dbe6312cb..59a875e422 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<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); } diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index c999e1f0af..62b5207538 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<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; |