add gamma maskfilter, especially nice when applied after a blur
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 29 Oct 2009 15:19:10 +0000 (15:19 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 29 Oct 2009 15:19:10 +0000 (15:19 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@411 2bbb7eff-a529-9590-31e7-b0007b416f81

include/effects/SkGammaMaskFilter.h [new file with mode: 0644]
src/effects/SkGammaMaskFilter.cpp [new file with mode: 0644]

diff --git a/include/effects/SkGammaMaskFilter.h b/include/effects/SkGammaMaskFilter.h
new file mode 100644 (file)
index 0000000..fdff43d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkGammaMaskFilter_DEFINED
+#define SkGammaMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+#include "SkScalar.h"
+
+/** \class SkGammaMaskFilter
+    Applies a table lookup on each of the alpha values in the mask.
+    An arbitrary table can be assigned, or a gamma (pow) table is computed
+    based on the specified exponent.
+ */
+class SkGammaMaskFilter : public SkMaskFilter {
+public:
+    SkGammaMaskFilter();
+    SkGammaMaskFilter(SkScalar gamma);
+    SkGammaMaskFilter(const uint8_t table[256]);
+    virtual ~SkGammaMaskFilter();
+
+    void setGamma(SkScalar gamma);
+    void setGammaTable(const uint8_t table[256]);
+
+    // overrides from SkMaskFilter
+    virtual SkMask::Format getFormat();
+    virtual bool filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*);
+    
+    // overrides from SkFlattenable
+    virtual void flatten(SkFlattenableWriteBuffer& wb);
+    virtual Factory getFactory();
+
+protected:
+    SkGammaMaskFilter(SkFlattenableReadBuffer& rb);
+    static SkFlattenable* Factory(SkFlattenableReadBuffer&);
+
+private:
+    uint8_t fTable[256];
+    
+    typedef SkMaskFilter INHERITED;
+};
+
+#endif
+
diff --git a/src/effects/SkGammaMaskFilter.cpp b/src/effects/SkGammaMaskFilter.cpp
new file mode 100644 (file)
index 0000000..ebf13fc
--- /dev/null
@@ -0,0 +1,95 @@
+#include "SkGammaMaskFilter.h"
+
+SkGammaMaskFilter::SkGammaMaskFilter() {
+    for (int i = 0; i < 256; i++) {
+        fTable[i] = i;
+    }
+}
+
+SkGammaMaskFilter::SkGammaMaskFilter(SkScalar gamma) {
+    this->setGamma(gamma);
+}
+
+SkGammaMaskFilter::SkGammaMaskFilter(const uint8_t table[256]) {
+    this->setGammaTable(table);
+}
+
+SkGammaMaskFilter::~SkGammaMaskFilter() {}
+
+void SkGammaMaskFilter::setGamma(SkScalar gamma) {
+    float x = 0;
+    const float dx = 1 / 255.0f;
+    for (int i = 0; i < 256; i++) {
+        fTable[i] = SkPin32(SkScalarRound(powf(x, gamma) * 255), 0, 255);
+        x += dx;
+    }
+}
+
+void SkGammaMaskFilter::setGammaTable(const uint8_t table[256]) {
+    memcpy(fTable, table, 256);
+}
+
+SkMask::Format SkGammaMaskFilter::getFormat() {
+    return SkMask::kA8_Format;
+}
+
+bool SkGammaMaskFilter::filterMask(SkMask* dst, const SkMask& src,
+                                 const SkMatrix&, SkIPoint* margin) {
+    if (src.fFormat != SkMask::kA8_Format) {
+        return false;
+    }
+
+    dst->fBounds = src.fBounds;
+    dst->fRowBytes = SkAlign4(dst->fBounds.width());
+    dst->fFormat = SkMask::kA8_Format;
+    dst->fImage = NULL;
+    
+    if (src.fImage) {
+        dst->fImage = SkMask::AllocImage(dst->computeImageSize());
+        
+        const uint8_t* srcP = src.fImage;
+        uint8_t* dstP = dst->fImage;
+        const uint8_t* table = fTable;
+        int dstWidth = dst->fBounds.width();
+        int extraZeros = dst->fRowBytes - dstWidth;
+        
+        for (int y = dst->fBounds.height() - 1; y >= 0; --y) {
+            for (int x = dstWidth - 1; x >= 0; --x) {
+                dstP[x] = table[srcP[x]];
+            }
+            srcP += src.fRowBytes;
+            // we can't just inc dstP by rowbytes, because if it has any
+            // padding between its width and its rowbytes, we need to zero those
+            // so that the bitters can read those safely if that is faster for
+            // them
+            dstP += dstWidth;
+            for (int i = extraZeros - 1; i >= 0; --i) {
+                *dstP++ = 0;
+            }
+        }
+    }
+
+    if (margin) {
+        margin->set(0, 0);
+    }
+    return true;
+}
+
+void SkGammaMaskFilter::flatten(SkFlattenableWriteBuffer& wb) {
+    this->INHERITED::flatten(wb);
+    wb.writePad(fTable, 256);
+}
+
+SkGammaMaskFilter::SkGammaMaskFilter(SkFlattenableReadBuffer& rb)
+        : INHERITED(rb) {
+    rb.read(fTable, 256);
+}
+
+SkFlattenable* SkGammaMaskFilter::Factory(SkFlattenableReadBuffer& rb) {
+    return SkNEW_ARGS(SkGammaMaskFilter, (rb));
+}
+
+SkFlattenable::Factory SkGammaMaskFilter::getFactory() {
+    return SkGammaMaskFilter::Factory;
+}
+