Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / gradients / SkSweepGradient.cpp
index c38205b..a539216 100644 (file)
@@ -8,8 +8,7 @@
 
 #include "SkSweepGradient.h"
 
-SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy,
-                                 const Descriptor& desc)
+SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
     : SkGradientShaderBase(desc)
     , fCenter(SkPoint::Make(cx, cy))
 {
@@ -42,188 +41,29 @@ SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
     return kSweep_GradientType;
 }
 
-SkSweepGradient::SkSweepGradient(SkFlattenableReadBuffer& buffer)
+SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer)
     : INHERITED(buffer),
       fCenter(buffer.readPoint()) {
 }
 
-void SkSweepGradient::flatten(SkFlattenableWriteBuffer& buffer) const {
+void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
     buffer.writePoint(fCenter);
 }
 
-#ifndef SK_SCALAR_IS_FLOAT
-#ifdef COMPUTE_SWEEP_TABLE
-#define PI  3.14159265
-static bool gSweepTableReady;
-static uint8_t gSweepTable[65];
-
-/*  Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
-    We scale the results to [0..32]
-*/
-static const uint8_t* build_sweep_table() {
-    if (!gSweepTableReady) {
-        const int N = 65;
-        const double DENOM = N - 1;
-
-        for (int i = 0; i < N; i++)
-        {
-            double arg = i / DENOM;
-            double v = atan(arg);
-            int iv = (int)round(v * DENOM * 2 / PI);
-//            printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
-            printf("%d, ", iv);
-            gSweepTable[i] = iv;
-        }
-        gSweepTableReady = true;
-    }
-    return gSweepTable;
+size_t SkSweepGradient::contextSize() const {
+    return sizeof(SweepGradientContext);
 }
-#else
-static const uint8_t gSweepTable[] = {
-    0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
-    10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
-    19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
-    26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
-    32
-};
-static const uint8_t* build_sweep_table() { return gSweepTable; }
-#endif
-#endif
-
-// divide numer/denom, with a bias of 6bits. Assumes numer <= denom
-// and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
-// Same as (but faster than) SkFixedDiv(numer, denom) >> 10
-
-//unsigned div_64(int numer, int denom);
-#ifndef SK_SCALAR_IS_FLOAT
-static unsigned div_64(int numer, int denom) {
-    SkASSERT(numer <= denom);
-    SkASSERT(numer > 0);
-    SkASSERT(denom > 0);
-
-    int nbits = SkCLZ(numer);
-    int dbits = SkCLZ(denom);
-    int bits = 6 - nbits + dbits;
-    SkASSERT(bits <= 6);
-
-    if (bits < 0) {  // detect underflow
-        return 0;
-    }
-
-    denom <<= dbits - 1;
-    numer <<= nbits - 1;
-
-    unsigned result = 0;
 
-    // do the first one
-    if ((numer -= denom) >= 0) {
-        result = 1;
-    } else {
-        numer += denom;
-    }
-
-    // Now fall into our switch statement if there are more bits to compute
-    if (bits > 0) {
-        // make room for the rest of the answer bits
-        result <<= bits;
-        switch (bits) {
-        case 6:
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 32;
-            else
-                numer += denom;
-        case 5:
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 16;
-            else
-                numer += denom;
-        case 4:
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 8;
-            else
-                numer += denom;
-        case 3:
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 4;
-            else
-                numer += denom;
-        case 2:
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 2;
-            else
-                numer += denom;
-        case 1:
-        default:    // not strictly need, but makes GCC make better ARM code
-            if ((numer = (numer << 1) - denom) >= 0)
-                result |= 1;
-            else
-                numer += denom;
-        }
-    }
-    return result;
+SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
+    return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, rec));
 }
-#endif
-
-// Given x,y in the first quadrant, return 0..63 for the angle [0..90]
-#ifndef SK_SCALAR_IS_FLOAT
-static unsigned atan_0_90(SkFixed y, SkFixed x) {
-#ifdef SK_DEBUG
-    {
-        static bool gOnce;
-        if (!gOnce) {
-            gOnce = true;
-            SkASSERT(div_64(55, 55) == 64);
-            SkASSERT(div_64(128, 256) == 32);
-            SkASSERT(div_64(2326528, 4685824) == 31);
-            SkASSERT(div_64(753664, 5210112) == 9);
-            SkASSERT(div_64(229376, 4882432) == 3);
-            SkASSERT(div_64(2, 64) == 2);
-            SkASSERT(div_64(1, 64) == 1);
-            // test that we handle underflow correctly
-            SkASSERT(div_64(12345, 0x54321234) == 0);
-        }
-    }
-#endif
-
-    SkASSERT(y > 0 && x > 0);
-    const uint8_t* table = build_sweep_table();
-
-    unsigned result;
-    bool swap = (x < y);
-    if (swap) {
-        // first part of the atan(v) = PI/2 - atan(1/v) identity
-        // since our div_64 and table want v <= 1, where v = y/x
-        SkTSwap<SkFixed>(x, y);
-    }
-
-    result = div_64(y, x);
 
-#ifdef SK_DEBUG
-    {
-        unsigned result2 = SkDivBits(y, x, 6);
-        SkASSERT(result2 == result ||
-                 (result == 1 && result2 == 0));
-    }
-#endif
-
-    SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
-    result = table[result];
-
-    if (swap) {
-        // complete the atan(v) = PI/2 - atan(1/v) identity
-        result = 64 - result;
-        // pin to 63
-        result -= result >> 6;
-    }
-
-    SkASSERT(result <= 63);
-    return result;
-}
-#endif
+SkSweepGradient::SweepGradientContext::SweepGradientContext(
+        const SkSweepGradient& shader, const ContextRec& rec)
+    : INHERITED(shader, rec) {}
 
 //  returns angle in a circle [0..2PI) -> [0..255]
-#ifdef SK_SCALAR_IS_FLOAT
 static unsigned SkATan2_255(float y, float x) {
     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
     static const float g255Over2PI = 40.584510488433314f;
@@ -239,68 +79,12 @@ static unsigned SkATan2_255(float y, float x) {
     SkASSERT(ir >= 0 && ir <= 255);
     return ir;
 }
-#else
-static unsigned SkATan2_255(SkFixed y, SkFixed x) {
-    if (x == 0) {
-        if (y == 0) {
-            return 0;
-        }
-        return y < 0 ? 192 : 64;
-    }
-    if (y == 0) {
-        return x < 0 ? 128 : 0;
-    }
-
-    /*  Find the right quadrant for x,y
-        Since atan_0_90 only handles the first quadrant, we rotate x,y
-        appropriately before calling it, and then add the right amount
-        to account for the real quadrant.
-        quadrant 0 : add 0                  | x > 0 && y > 0
-        quadrant 1 : add 64 (90 degrees)    | x < 0 && y > 0
-        quadrant 2 : add 128 (180 degrees)  | x < 0 && y < 0
-        quadrant 3 : add 192 (270 degrees)  | x > 0 && y < 0
-
-        map x<0 to (1 << 6)
-        map y<0 to (3 << 6)
-        add = map_x ^ map_y
-    */
-    int xsign = x >> 31;
-    int ysign = y >> 31;
-    int add = ((-xsign) ^ (ysign & 3)) << 6;
-
-#ifdef SK_DEBUG
-    if (0 == add)
-        SkASSERT(x > 0 && y > 0);
-    else if (64 == add)
-        SkASSERT(x < 0 && y > 0);
-    else if (128 == add)
-        SkASSERT(x < 0 && y < 0);
-    else if (192 == add)
-        SkASSERT(x > 0 && y < 0);
-    else
-        SkDEBUGFAIL("bad value for add");
-#endif
-
-    /*  This ^ trick makes x, y positive, and the swap<> handles quadrants
-        where we need to rotate x,y by 90 or -90
-    */
-    x = (x ^ xsign) - xsign;
-    y = (y ^ ysign) - ysign;
-    if (add & 64) {             // quads 1 or 3 need to swap x,y
-        SkTSwap<SkFixed>(x, y);
-    }
-
-    unsigned result = add + atan_0_90(y, x);
-    SkASSERT(result < 256);
-    return result;
-}
-#endif
 
-void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
-                               int count) {
+void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
+                                                      int count) {
     SkMatrix::MapXYProc proc = fDstToIndexProc;
     const SkMatrix&     matrix = fDstToIndex;
-    const SkPMColor* SK_RESTRICT cache = this->getCache32();
+    const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
     int                 toggle = init_dither_toggle(x, y);
     SkPoint             srcPt;
 
@@ -338,11 +122,11 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
     }
 }
 
-void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
-                                 int count) {
+void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
+                                                        int count) {
     SkMatrix::MapXYProc proc = fDstToIndexProc;
     const SkMatrix&     matrix = fDstToIndex;
-    const uint16_t* SK_RESTRICT cache = this->getCache16();
+    const uint16_t* SK_RESTRICT cache = fCache->getCache16();
     int                 toggle = init_dither_toggle16(x, y);
     SkPoint             srcPt;
 
@@ -389,6 +173,8 @@ void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
+#include "SkGr.h"
 
 class GrGLSweepGradient : public GrGLGradientEffect {
 public:
@@ -399,14 +185,14 @@ public:
 
     virtual void emitCode(GrGLShaderBuilder*,
                           const GrDrawEffect&,
-                          EffectKey,
+                          const GrEffectKey&,
                           const char* outputColor,
                           const char* inputColor,
                           const TransformedCoordsArray&,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
-        return GenBaseGradientKey(drawEffect);
+    static void GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&, GrEffectKeyBuilder* b) {
+        b->add32(GenBaseGradientKey(drawEffect));
     }
 
 private:
@@ -419,11 +205,8 @@ private:
 
 class GrSweepGradient : public GrGradientEffect {
 public:
-    static GrEffectRef* Create(GrContext* ctx,
-                               const SkSweepGradient& shader,
-                               const SkMatrix& matrix) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
-        return CreateEffectRef(effect);
+    static GrEffect* Create(GrContext* ctx, const SkSweepGradient& shader, const SkMatrix& m) {
+        return SkNEW_ARGS(GrSweepGradient, (ctx, shader, m));
     }
     virtual ~GrSweepGradient() { }
 
@@ -448,7 +231,7 @@ private:
 
 GR_DEFINE_EFFECT_TEST(GrSweepGradient);
 
-GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
+GrEffect* GrSweepGradient::TestCreate(SkRandom* random,
                                          GrContext* context,
                                          const GrDrawTargetCaps&,
                                          GrTexture**) {
@@ -462,47 +245,76 @@ GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
                                                                 colors, stops, colorCount));
     SkPaint paint;
-    return shader->asNewEffect(context, paint);
+    GrEffect* effect;
+    GrColor paintColor;
+    SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
+    return effect;
 }
 
 /////////////////////////////////////////////////////////////////////
 
 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
                                  const GrDrawEffect&,
-                                 EffectKey key,
+                                 const GrEffectKey& key,
                                  const char* outputColor,
                                  const char* inputColor,
                                  const TransformedCoordsArray& coords,
                                  const TextureSamplerArray& samplers) {
-    this->emitUniforms(builder, key);
+    uint32_t baseKey = key.get32(0);
+    this->emitUniforms(builder, baseKey);
     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
+    const GrGLContextInfo ctxInfo = builder->ctxInfo();
     SkString t;
-    t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords2D.c_str(), coords2D.c_str());
-    this->emitColor(builder, t.c_str(), key,
-                          outputColor, inputColor, samplers);
+    // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
+    // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
+    // thus must us -1.0 * %s.x to work correctly
+    if (kIntel_GrGLVendor != ctxInfo.vendor()){
+        t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
+                 coords2D.c_str(), coords2D.c_str());
+    } else {
+        t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
+                 coords2D.c_str(), coords2D.c_str());
+    }
+    this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers);
 }
 
 /////////////////////////////////////////////////////////////////////
 
-GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const {
+bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
+                                  const SkMatrix* localMatrix, GrColor* paintColor,
+                                  GrEffect** effect)  const {
+    
     SkMatrix matrix;
     if (!this->getLocalMatrix().invert(&matrix)) {
-        return NULL;
+        return false;
+    }
+    if (localMatrix) {
+        SkMatrix inv;
+        if (!localMatrix->invert(&inv)) {
+            return false;
+        }
+        matrix.postConcat(inv);
     }
     matrix.postConcat(fPtsToUnit);
-    return GrSweepGradient::Create(context, *this, matrix);
+    
+    *effect = GrSweepGradient::Create(context, *this, matrix);
+    *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
+    
+    return true;
 }
 
 #else
 
-GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const {
+bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
+                                  const SkMatrix* localMatrix, GrColor* paintColor,
+                                  GrEffect** effect)  const {
     SkDEBUGFAIL("Should not call in GPU-less build");
-    return NULL;
+    return false;
 }
 
 #endif
 
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkSweepGradient::toString(SkString* str) const {
     str->append("SkSweepGradient: (");