diff options
author | reed <reed@google.com> | 2014-08-22 08:30:20 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-22 08:30:20 -0700 |
commit | 8367b8cb7a6b2f163ee41365323cb219b7049b15 (patch) | |
tree | a9a6eca606018fce8729acec734985388ccfe428 | |
parent | 5b2c2c6fd09752641b14766678d62fe50b4e3ef3 (diff) |
extend SkShader to report a luminance-color to be used for gamma correction
BUG=skia:590
R=bungeman@google.com
Author: reed@google.com
Review URL: https://codereview.chromium.org/492963002
-rw-r--r-- | gm/gammatext.cpp | 87 | ||||
-rw-r--r-- | include/core/SkColorShader.h | 8 | ||||
-rw-r--r-- | include/core/SkShader.h | 19 | ||||
-rw-r--r-- | src/core/SkPaint.cpp | 6 | ||||
-rw-r--r-- | src/core/SkShader.cpp | 18 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 22 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 2 |
7 files changed, 150 insertions, 12 deletions
diff --git a/gm/gammatext.cpp b/gm/gammatext.cpp index cdc37fac93..54b0765783 100644 --- a/gm/gammatext.cpp +++ b/gm/gammatext.cpp @@ -99,8 +99,6 @@ static void cgDrawText(CGContextRef cg, const void* text, size_t len, } #endif -namespace skiagm { - /** Test a set of clipping problems discovered while writing blitAntiRect, and test all the code paths through the clipping blitters. @@ -110,7 +108,7 @@ namespace skiagm { #define HEIGHT 480 -class GammaTextGM : public GM { +class GammaTextGM : public skiagm::GM { public: GammaTextGM() { @@ -199,12 +197,89 @@ protected: } private: - typedef GM INHERITED; + typedef skiagm::GM INHERITED; }; +DEF_GM( return new GammaTextGM; ) + ////////////////////////////////////////////////////////////////////////////// -static GM* MyFactory(void*) { return new GammaTextGM; } -static GMRegistry reg(MyFactory); +static SkShader* make_gradient(SkColor c) { + const SkPoint pts[] = { { 0, 0 }, { 240, 0 } }; + SkColor colors[2]; + colors[0] = c; + colors[1] = SkColorSetA(c, 0); + return SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode); +} + +static void set_face(SkPaint* paint) { + SkTypeface* face = SkTypeface::CreateFromName("serif", SkTypeface::kItalic); + SkSafeUnref(paint->setTypeface(face)); +} +static void draw_pair(SkCanvas* canvas, SkPaint* paint, SkShader* shader) { + const char text[] = "Now is the time for all good"; + const size_t len = strlen(text); + + paint->setShader(NULL); + canvas->drawText(text, len, 10, 20, *paint); + paint->setShader(SkShader::CreateColorShader(paint->getColor()))->unref(); + canvas->drawText(text, len, 10, 40, *paint); + paint->setShader(shader); + canvas->drawText(text, len, 10, 60, *paint); } + +class GammaShaderTextGM : public skiagm::GM { + SkShader* fShaders[3]; + SkColor fColors[3]; + +public: + GammaShaderTextGM() { + const SkColor colors[] = { SK_ColorBLACK, SK_ColorRED, SK_ColorBLUE }; + for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { + fShaders[i] = NULL; + fColors[i] = colors[i]; + } + } + + virtual ~GammaShaderTextGM() { + for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { + SkSafeUnref(fShaders[i]); + } + } + +protected: + virtual SkString onShortName() { + return SkString("gammagradienttext"); + } + + virtual SkISize onISize() { + return SkISize::Make(300, 300); + } + + virtual void onOnceBeforeDraw() { + for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { + fShaders[i] = make_gradient(fColors[i]); + } + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setLCDRenderText(true); + paint.setTextSize(18); + set_face(&paint); + + for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { + paint.setColor(fColors[i]); + draw_pair(canvas, &paint, fShaders[i]); + canvas->translate(0, 80); + } + } + +private: + typedef skiagm::GM INHERITED; +}; + +DEF_GM( return new GammaShaderTextGM; ) + diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h index 4ff7d2b01d..55d980b64e 100644 --- a/include/core/SkColorShader.h +++ b/include/core/SkColorShader.h @@ -1,4 +1,3 @@ - /* * Copyright 2007 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkColorShader_DEFINED #define SkColorShader_DEFINED @@ -67,9 +65,13 @@ protected: SkColorShader(SkReadBuffer&); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; virtual Context* onCreateContext(const ContextRec&, void* storage) const SK_OVERRIDE; + virtual bool onAsLuminanceColor(SkColor* lum) const SK_OVERRIDE { + *lum = fColor; + return true; + } private: - SkColor fColor; // ignored if fInheritColor is true + SkColor fColor; typedef SkShader INHERITED; }; diff --git a/include/core/SkShader.h b/include/core/SkShader.h index 1e71577bf1..8530023671 100644 --- a/include/core/SkShader.h +++ b/include/core/SkShader.h @@ -386,6 +386,16 @@ public: const SkMatrix* localMatrixOrNull, GrColor* paintColor, GrEffect** effect) const; + /** + * If the shader can represent its "average" luminance in a single color, return true and + * if color is not NULL, return that color. If it cannot, return false and ignore the color + * parameter. + * + * Note: if this returns true, the returned color will always be opaque, as only the RGB + * components are used to compute luminance. + */ + bool asLuminanceColor(SkColor*) const; + #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK /** * If the shader is a custom shader which has data the caller might want, call this function @@ -402,6 +412,12 @@ public: */ static SkShader* CreateEmptyShader(); + /** + * Call this to create a new shader that just draws the specified color. This should always + * draw the same as a paint with this color (and no shader). + */ + static SkShader* CreateColorShader(SkColor); + /** Call this to create a new shader that will draw with the specified bitmap. * * If the bitmap cannot be used (e.g. has no pixels, or its dimensions @@ -474,6 +490,9 @@ protected: */ virtual Context* onCreateContext(const ContextRec&, void* storage) const; + virtual bool onAsLuminanceColor(SkColor*) const { + return false; + } private: // This is essentially const, but not officially so it can be modified in // constructors. diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 89a8cd0872..954680b8dc 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1497,10 +1497,12 @@ static SkPaint::Hinting computeHinting(const SkPaint& paint) { // return true if the paint is just a single color (i.e. not a shader). If its // a shader, then we can't compute a const luminance for it :( static bool justAColor(const SkPaint& paint, SkColor* color) { - if (paint.getShader()) { + SkColor c = paint.getColor(); + + SkShader* shader = paint.getShader(); + if (shader && !shader->asLuminanceColor(&c)) { return false; } - SkColor c = paint.getColor(); if (paint.getColorFilter()) { c = paint.getColorFilter()->filterColor(c); } diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 85707d77bc..67fa122732 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -6,6 +6,7 @@ */ #include "SkBitmapProcShader.h" +#include "SkColorShader.h" #include "SkEmptyShader.h" #include "SkReadBuffer.h" #include "SkMallocPixelRef.h" @@ -81,6 +82,18 @@ bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse return m->invert(totalInverse); } +bool SkShader::asLuminanceColor(SkColor* colorPtr) const { + SkColor storage; + if (NULL == colorPtr) { + colorPtr = &storage; + } + if (this->onAsLuminanceColor(colorPtr)) { + *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque + return true; + } + return false; +} + SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const { if (!this->computeTotalInverse(rec, NULL)) { return NULL; @@ -224,6 +237,10 @@ SkShader* SkShader::CreateEmptyShader() { return SkNEW(SkEmptyShader); } +SkShader* SkShader::CreateColorShader(SkColor color) { + return SkNEW_ARGS(SkColorShader, (color)); +} + SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, const SkMatrix* localMatrix) { return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL); @@ -245,7 +262,6 @@ void SkShader::toString(SkString* str) const { ////////////////////////////////////////////////////////////////////////////// -#include "SkColorShader.h" #include "SkUtils.h" SkColorShader::SkColorShader(SkColor c) diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index 4f60cfee66..9d6e856aad 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -326,6 +326,28 @@ bool SkGradientShaderBase::isOpaque() const { return fColorsAreOpaque; } +static unsigned rounded_divide(unsigned numer, unsigned denom) { + return (numer + (denom >> 1)) / denom; +} + +bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const { + // we just compute an average color. + // possibly we could weight this based on the proportional width for each color + // assuming they are not evenly distributed in the fPos array. + int r = 0; + int g = 0; + int b = 0; + const int n = fColorCount; + for (int i = 0; i < n; ++i) { + SkColor c = fOrigColors[i]; + r += SkColorGetR(c); + g += SkColorGetG(c); + b += SkColorGetB(c); + } + *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n)); + return true; +} + SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( const SkGradientShaderBase& shader, const ContextRec& rec) : INHERITED(shader, rec) diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h index 8f14bbf6e0..3ae59f5e97 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -237,6 +237,8 @@ protected: void commonAsAGradient(GradientInfo*, bool flipGrad = false) const; + virtual bool onAsLuminanceColor(SkColor*) const SK_OVERRIDE; + /* * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively. * Count is the number of colors in the gradient |