summaryrefslogtreecommitdiffstats
path: root/gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch')
-rw-r--r--gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch400
1 files changed, 400 insertions, 0 deletions
diff --git a/gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch b/gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch
new file mode 100644
index 000000000..e00fd8602
--- /dev/null
+++ b/gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch
@@ -0,0 +1,400 @@
+# HG changeset patch
+# User Matt Woodrow <mwoodrow@mozilla.com>
+# Date 1339988782 -43200
+# Node ID 1e9dae659ee6c992f719fd4136efbcc5410ded37
+# Parent 946750f6d95febd199fb7b748e9d2c48fd01c8a6
+[mq]: skia-windows-gradients
+
+diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
+--- a/gfx/skia/src/effects/SkGradientShader.cpp
++++ b/gfx/skia/src/effects/SkGradientShader.cpp
+@@ -847,16 +847,19 @@ bool Linear_Gradient::setContext(const S
+ fFlags |= SkShader::kConstInY32_Flag;
+ if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
+ // only claim this if we do have a 16bit mode (i.e. none of our
+ // colors have alpha), and if we are not dithering (which obviously
+ // is not const in Y).
+ fFlags |= SkShader::kConstInY16_Flag;
+ }
+ }
++ if (fStart == fEnd) {
++ fFlags &= ~kOpaqueAlpha_Flag;
++ }
+ return true;
+ }
+
+ #define NO_CHECK_ITER \
+ do { \
+ unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
+ SkASSERT(fi <= 0xFF); \
+ fx += dx; \
+@@ -976,16 +979,21 @@ void Linear_Gradient::shadeSpan(int x, i
+ TileProc proc = fTileProc;
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
+ #ifdef USE_DITHER_32BIT_GRADIENT
+ int toggle = ((x ^ y) & 1) * kDitherStride32;
+ #else
+ int toggle = 0;
+ #endif
+
++ if (fStart == fEnd) {
++ sk_bzero(dstC, count * sizeof(*dstC));
++ return;
++ }
++
+ if (fDstToIndexClass != kPerspective_MatrixClass) {
+ dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+ SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+ SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+
+ if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+ SkFixed dxStorage[1];
+ (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
+@@ -1169,16 +1177,21 @@ void Linear_Gradient::shadeSpan16(int x,
+ SkASSERT(count > 0);
+
+ SkPoint srcPt;
+ SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+ TileProc proc = fTileProc;
+ const uint16_t* SK_RESTRICT cache = this->getCache16();
+ int toggle = ((x ^ y) & 1) * kDitherStride16;
+
++ if (fStart == fEnd) {
++ sk_bzero(dstC, count * sizeof(*dstC));
++ return;
++ }
++
+ if (fDstToIndexClass != kPerspective_MatrixClass) {
+ dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+ SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+ SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+
+ if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+ SkFixed dxStorage[1];
+ (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
+@@ -1739,21 +1752,25 @@ void Radial_Gradient::shadeSpan(int x, i
+ possible circles on which the point may fall. Solving for t yields
+ the gradient value to use.
+
+ If a<0, the start circle is entirely contained in the
+ end circle, and one of the roots will be <0 or >1 (off the line
+ segment). If a>0, the start circle falls at least partially
+ outside the end circle (or vice versa), and the gradient
+ defines a "tube" where a point may be on one circle (on the
+- inside of the tube) or the other (outside of the tube). We choose
+- one arbitrarily.
++ inside of the tube) or the other (outside of the tube). We choose
++ the one with the highest t value, as long as the radius that it
++ corresponds to is >=0. In the case where neither root has a positive
++ radius, we don't draw anything.
+
++ XXXmattwoodrow: I've removed this for now since it breaks
++ down when Dr == 0. Is there something else we can do instead?
+ In order to keep the math to within the limits of fixed point,
+- we divide the entire quadratic by Dr^2, and replace
++ we divide the entire quadratic by Dr, and replace
+ (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
+
+ [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
+ + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
+ + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
+
+ (x' and y' are computed by appending the subtract and scale to the
+ fDstToIndex matrix in the constructor).
+@@ -1763,99 +1780,122 @@ void Radial_Gradient::shadeSpan(int x, i
+ x' and y', if x and y are linear in the span, 'B' can be computed
+ incrementally with a simple delta (db below). If it is not (e.g.,
+ a perspective projection), it must be computed in the loop.
+
+ */
+
+ namespace {
+
+-inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
+- SkScalar sr2d2, SkScalar foura,
+- SkScalar oneOverTwoA, bool posRoot) {
++inline bool two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
++ SkScalar sr2d2, SkScalar foura,
++ SkScalar oneOverTwoA, SkScalar diffRadius,
++ SkScalar startRadius, SkFixed& t) {
+ SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
+ if (0 == foura) {
+- return SkScalarToFixed(SkScalarDiv(-c, b));
++ SkScalar result = SkScalarDiv(-c, b);
++ if (result * diffRadius + startRadius >= 0) {
++ t = SkScalarToFixed(result);
++ return true;
++ }
++ return false;
+ }
+
+ SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
+ if (discrim < 0) {
+- discrim = -discrim;
++ return false;
+ }
+ SkScalar rootDiscrim = SkScalarSqrt(discrim);
+- SkScalar result;
+- if (posRoot) {
+- result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
+- } else {
+- result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
++
++ // Make sure the results corresponds to a positive radius.
++ SkScalar result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
++ if (result * diffRadius + startRadius >= 0) {
++ t = SkScalarToFixed(result);
++ return true;
+ }
+- return SkScalarToFixed(result);
++ result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
++ if (result * diffRadius + startRadius >= 0) {
++ t = SkScalarToFixed(result);
++ return true;
++ }
++
++ return false;
+ }
+
+ typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
++ SkScalar fDiffRadius, SkScalar fRadius1,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count);
+
+ void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
++ SkScalar fDiffRadius, SkScalar fRadius1,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+- fOneOverTwoA, posRoot);
+-
+- if (t < 0) {
++ SkFixed t;
++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
++ *(dstC++) = 0;
++ } else if (t < 0) {
+ *dstC++ = cache[-1];
+ } else if (t > 0xFFFF) {
+ *dstC++ = cache[Gradient_Shader::kCache32Count * 2];
+ } else {
+ SkASSERT(t <= 0xFFFF);
+ *dstC++ = cache[t >> Gradient_Shader::kCache32Shift];
+ }
+
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+ }
+ void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
++ SkScalar fDiffRadius, SkScalar fRadius1,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+- fOneOverTwoA, posRoot);
+- SkFixed index = mirror_tileproc(t);
+- SkASSERT(index <= 0xFFFF);
+- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
++ SkFixed t;
++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
++ *(dstC++) = 0;
++ } else {
++ SkFixed index = mirror_tileproc(t);
++ SkASSERT(index <= 0xFFFF);
++ *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
++ }
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+ }
+
+ void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
++ SkScalar fDiffRadius, SkScalar fRadius1,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+- fOneOverTwoA, posRoot);
+- SkFixed index = repeat_tileproc(t);
+- SkASSERT(index <= 0xFFFF);
+- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
++ SkFixed t;
++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
++ *(dstC++) = 0;
++ } else {
++ SkFixed index = repeat_tileproc(t);
++ SkASSERT(index <= 0xFFFF);
++ *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
++ }
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+ }
+
+
+
+@@ -1935,17 +1975,16 @@ public:
+ sk_bzero(dstC, count * sizeof(*dstC));
+ return;
+ }
+ SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+ TileProc proc = fTileProc;
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
+
+ SkScalar foura = fA * 4;
+- bool posRoot = fDiffRadius < 0;
+ if (fDstToIndexClass != kPerspective_MatrixClass) {
+ SkPoint srcPt;
+ dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+ SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+ SkScalar dx, fx = srcPt.fX;
+ SkScalar dy, fy = srcPt.fY;
+
+ if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+@@ -1954,60 +1993,69 @@ public:
+ dx = SkFixedToScalar(fixedX);
+ dy = SkFixedToScalar(fixedY);
+ } else {
+ SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+ dx = fDstToIndex.getScaleX();
+ dy = fDstToIndex.getSkewY();
+ }
+ SkScalar b = (SkScalarMul(fDiff.fX, fx) +
+- SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
++ SkScalarMul(fDiff.fY, fy) - fStartRadius * fDiffRadius) * 2;
+ SkScalar db = (SkScalarMul(fDiff.fX, dx) +
+ SkScalarMul(fDiff.fY, dy)) * 2;
+
+ TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
+ if (proc == clamp_tileproc) {
+ shadeProc = shadeSpan_twopoint_clamp;
+ } else if (proc == mirror_tileproc) {
+ shadeProc = shadeSpan_twopoint_mirror;
+ } else {
+ SkASSERT(proc == repeat_tileproc);
+ }
+ (*shadeProc)(fx, dx, fy, dy, b, db,
+- fSr2D2, foura, fOneOverTwoA, posRoot,
++ fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1,
+ dstC, cache, count);
+ } else { // perspective case
+ SkScalar dstX = SkIntToScalar(x);
+ SkScalar dstY = SkIntToScalar(y);
+ for (; count > 0; --count) {
+ SkPoint srcPt;
+ dstProc(fDstToIndex, dstX, dstY, &srcPt);
+ SkScalar fx = srcPt.fX;
+ SkScalar fy = srcPt.fY;
+ SkScalar b = (SkScalarMul(fDiff.fX, fx) +
+ SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
+- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+- fOneOverTwoA, posRoot);
+- SkFixed index = proc(t);
+- SkASSERT(index <= 0xFFFF);
+- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
++ SkFixed t;
++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
++ *(dstC++) = 0;
++ } else {
++ SkFixed index = proc(t);
++ SkASSERT(index <= 0xFFFF);
++ *dstC++ = cache[index >> (16 - kCache32Bits)];
++ }
+ dstX += SK_Scalar1;
+ }
+ }
+ }
+
+ virtual bool setContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix) SK_OVERRIDE {
+ if (!this->INHERITED::setContext(device, paint, matrix)) {
+ return false;
+ }
+
+ // we don't have a span16 proc
+ fFlags &= ~kHasSpan16_Flag;
++
++ // If we might end up wanting to draw nothing as part of the gradient
++ // then we should mark ourselves as not being opaque.
++ if (fA >= 0 || (fDiffRadius == 0 && fCenter1 == fCenter2)) {
++ fFlags &= ~kOpaqueAlpha_Flag;
++ }
+ return true;
+ }
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Two_Point_Radial_Gradient)
+
+ protected:
+ Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer),
+@@ -2033,26 +2081,22 @@ private:
+ const SkScalar fRadius1;
+ const SkScalar fRadius2;
+ SkPoint fDiff;
+ SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
+
+ void init() {
+ fDiff = fCenter1 - fCenter2;
+ fDiffRadius = fRadius2 - fRadius1;
+- SkScalar inv = SkScalarInvert(fDiffRadius);
+- fDiff.fX = SkScalarMul(fDiff.fX, inv);
+- fDiff.fY = SkScalarMul(fDiff.fY, inv);
+- fStartRadius = SkScalarMul(fRadius1, inv);
++ fStartRadius = fRadius1;
+ fSr2D2 = SkScalarSquare(fStartRadius);
+- fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
++ fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SkScalarSquare(fDiffRadius);
+ fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
+
+ fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
+- fPtsToUnit.postScale(inv, inv);
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ class Sweep_Gradient : public Gradient_Shader {
+ public:
+ Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
+@@ -2488,16 +2532,20 @@ SkShader* SkGradientShader::CreateTwoPoi
+ int colorCount,
+ SkShader::TileMode mode,
+ SkUnitMapper* mapper) {
+ if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
+ return NULL;
+ }
+ EXPAND_1_COLOR(colorCount);
+
++ if (start == end && startRadius == 0) {
++ return CreateRadial(start, endRadius, colors, pos, colorCount, mode, mapper);
++ }
++
+ return SkNEW_ARGS(Two_Point_Radial_Gradient,
+ (start, startRadius, end, endRadius, colors, pos,
+ colorCount, mode, mapper));
+ }
+
+ SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
+ const SkColor colors[],
+ const SkScalar pos[],