aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2014-08-22 08:30:20 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-22 08:30:20 -0700
commit8367b8cb7a6b2f163ee41365323cb219b7049b15 (patch)
treea9a6eca606018fce8729acec734985388ccfe428
parent5b2c2c6fd09752641b14766678d62fe50b4e3ef3 (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.cpp87
-rw-r--r--include/core/SkColorShader.h8
-rw-r--r--include/core/SkShader.h19
-rw-r--r--src/core/SkPaint.cpp6
-rw-r--r--src/core/SkShader.cpp18
-rw-r--r--src/effects/gradients/SkGradientShader.cpp22
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h2
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