Index: src/effects/SkLumaColorFilter.cpp |
diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c9f1fb02c3a17d49c841ee69dcf38a6f29d75541 |
--- /dev/null |
+++ b/src/effects/SkLumaColorFilter.cpp |
@@ -0,0 +1,152 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkLumaColorFilter.h" |
+ |
+#include "SkColorPriv.h" |
+#include "SkString.h" |
+#include "SkUnPreMultiply.h" |
+ |
+#if SK_SUPPORT_GPU |
+#include "gl/GrGLEffect.h" |
+#include "GrContext.h" |
+#include "GrTBackendEffectFactory.h" |
+#endif |
+ |
+void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count, |
+ SkPMColor dst[]) const { |
+ const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); |
+ |
+ for (int i = 0; i < count; ++i) { |
+ SkPMColor c = src[i]; |
+ |
+ unsigned r = SkGetPackedR32(c); |
+ unsigned g = SkGetPackedG32(c); |
+ unsigned b = SkGetPackedB32(c); |
+ unsigned a = SkGetPackedA32(c); |
+ |
+ // No need to do anything for white (luminance == 1.0) |
+ if (a != r || a != g || a != b) { |
+ /* |
+ * To avoid un-premultiplying multiple components, we can start |
+ * with the luminance computed in PM space: |
+ * |
+ * Lum = i * (r / a) + j * (g / a) + k * (b / a) |
+ * Lum = (i * r + j * g + k * b) / a |
+ * Lum = Lum'(PM) / a |
+ * |
+ * Then the filter function is: |
+ * |
+ * C' = [ Lum * a, Lum * r, Lum * g, Lum * b ] |
+ * |
+ * which is equivalent to: |
+ * |
+ * C' = [ Lum'(PM), Lum * r, Lum * g, Lum * b ] |
+ */ |
+ unsigned pm_lum = SkComputeLuminance(r, g, b); |
+ unsigned lum = SkUnPreMultiply::ApplyScale(table[a], pm_lum); |
+ |
+ c = SkPackARGB32(pm_lum, |
+ SkMulDiv255Round(r, lum), |
+ SkMulDiv255Round(g, lum), |
+ SkMulDiv255Round(b, lum)); |
+ } |
+ |
+ dst[i] = c; |
+ } |
+} |
+ |
+SkColorFilter* SkLumaColorFilter::Create() { |
+ return SkNEW(SkLumaColorFilter); |
+} |
+ |
+SkLumaColorFilter::SkLumaColorFilter() |
+ : INHERITED() { |
+} |
+ |
+SkLumaColorFilter::SkLumaColorFilter(SkFlattenableReadBuffer& buffer) |
+ : INHERITED(buffer) { |
+} |
+ |
+void SkLumaColorFilter::flatten(SkFlattenableWriteBuffer&) const { |
+} |
+ |
+#ifdef SK_DEVELOPER |
+void SkLumaColorFilter::toString(SkString* str) const { |
+ str->append("SkLumaColorFilter "); |
+} |
+#endif |
+ |
+#if SK_SUPPORT_GPU |
+class LumaColorFilterEffect : public GrEffect { |
+public: |
+ static GrEffectRef* Create() { |
+ AutoEffectUnref effect(SkNEW(LumaColorFilterEffect)); |
+ return CreateEffectRef(effect); |
+ } |
+ |
+ static const char* Name() { return "Luminance-to-Alpha"; } |
+ |
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
+ return GrTBackendEffectFactory<LumaColorFilterEffect>::getInstance(); |
+ } |
+ |
+ virtual void getConstantColorComponents(GrColor* color, |
+ uint32_t* validFlags) const SK_OVERRIDE { |
+ *validFlags = 0; |
+ } |
+ |
+ class GLEffect : public GrGLEffect { |
+ public: |
+ GLEffect(const GrBackendEffectFactory& factory, |
+ const GrDrawEffect&) |
+ : INHERITED(factory) { |
+ } |
+ |
+ static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { |
+ // this class always generates the same code. |
+ return 0; |
+ } |
+ |
+ virtual void emitCode(GrGLShaderBuilder* builder, |
+ const GrDrawEffect&, |
+ EffectKey, |
+ const char* outputColor, |
+ const char* inputColor, |
+ const TransformedCoordsArray&, |
+ const TextureSamplerArray&) SK_OVERRIDE { |
+ if (NULL == inputColor) { |
+ inputColor = GrGLSLOnesVecf(4); |
+ } |
+ |
+ // The max() is to guard against 0 / 0 during unpremul when the incoming color is |
+ // transparent black. |
+ builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor); |
+ builder->fsCodeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n", |
+ SK_ITU_BT709_LUM_COEFF_R, |
+ SK_ITU_BT709_LUM_COEFF_G, |
+ SK_ITU_BT709_LUM_COEFF_B, |
+ inputColor); |
+ builder->fsCodeAppendf("\t%s = vec4(%s.rgb * luma / nonZeroAlpha, luma);\n", |
+ outputColor, inputColor); |
+ |
+ } |
+ |
+ private: |
+ typedef GrGLEffect INHERITED; |
+ }; |
+ |
+private: |
+ virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { |
+ return true; |
+ } |
+}; |
+ |
+GrEffectRef* SkLumaColorFilter::asNewEffect(GrContext*) const { |
+ return LumaColorFilterEffect::Create(); |
+} |
+#endif |