1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,400 @@ 1.4 +# HG changeset patch 1.5 +# User Matt Woodrow <mwoodrow@mozilla.com> 1.6 +# Date 1339988782 -43200 1.7 +# Node ID 1e9dae659ee6c992f719fd4136efbcc5410ded37 1.8 +# Parent 946750f6d95febd199fb7b748e9d2c48fd01c8a6 1.9 +[mq]: skia-windows-gradients 1.10 + 1.11 +diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp 1.12 +--- a/gfx/skia/src/effects/SkGradientShader.cpp 1.13 ++++ b/gfx/skia/src/effects/SkGradientShader.cpp 1.14 +@@ -847,16 +847,19 @@ bool Linear_Gradient::setContext(const S 1.15 + fFlags |= SkShader::kConstInY32_Flag; 1.16 + if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) { 1.17 + // only claim this if we do have a 16bit mode (i.e. none of our 1.18 + // colors have alpha), and if we are not dithering (which obviously 1.19 + // is not const in Y). 1.20 + fFlags |= SkShader::kConstInY16_Flag; 1.21 + } 1.22 + } 1.23 ++ if (fStart == fEnd) { 1.24 ++ fFlags &= ~kOpaqueAlpha_Flag; 1.25 ++ } 1.26 + return true; 1.27 + } 1.28 + 1.29 + #define NO_CHECK_ITER \ 1.30 + do { \ 1.31 + unsigned fi = fx >> Gradient_Shader::kCache32Shift; \ 1.32 + SkASSERT(fi <= 0xFF); \ 1.33 + fx += dx; \ 1.34 +@@ -976,16 +979,21 @@ void Linear_Gradient::shadeSpan(int x, i 1.35 + TileProc proc = fTileProc; 1.36 + const SkPMColor* SK_RESTRICT cache = this->getCache32(); 1.37 + #ifdef USE_DITHER_32BIT_GRADIENT 1.38 + int toggle = ((x ^ y) & 1) * kDitherStride32; 1.39 + #else 1.40 + int toggle = 0; 1.41 + #endif 1.42 + 1.43 ++ if (fStart == fEnd) { 1.44 ++ sk_bzero(dstC, count * sizeof(*dstC)); 1.45 ++ return; 1.46 ++ } 1.47 ++ 1.48 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.49 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.50 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.51 + SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 1.52 + 1.53 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.54 + SkFixed dxStorage[1]; 1.55 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 1.56 +@@ -1169,16 +1177,21 @@ void Linear_Gradient::shadeSpan16(int x, 1.57 + SkASSERT(count > 0); 1.58 + 1.59 + SkPoint srcPt; 1.60 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.61 + TileProc proc = fTileProc; 1.62 + const uint16_t* SK_RESTRICT cache = this->getCache16(); 1.63 + int toggle = ((x ^ y) & 1) * kDitherStride16; 1.64 + 1.65 ++ if (fStart == fEnd) { 1.66 ++ sk_bzero(dstC, count * sizeof(*dstC)); 1.67 ++ return; 1.68 ++ } 1.69 ++ 1.70 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.71 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.72 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.73 + SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 1.74 + 1.75 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.76 + SkFixed dxStorage[1]; 1.77 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 1.78 +@@ -1739,21 +1752,25 @@ void Radial_Gradient::shadeSpan(int x, i 1.79 + possible circles on which the point may fall. Solving for t yields 1.80 + the gradient value to use. 1.81 + 1.82 + If a<0, the start circle is entirely contained in the 1.83 + end circle, and one of the roots will be <0 or >1 (off the line 1.84 + segment). If a>0, the start circle falls at least partially 1.85 + outside the end circle (or vice versa), and the gradient 1.86 + defines a "tube" where a point may be on one circle (on the 1.87 +- inside of the tube) or the other (outside of the tube). We choose 1.88 +- one arbitrarily. 1.89 ++ inside of the tube) or the other (outside of the tube). We choose 1.90 ++ the one with the highest t value, as long as the radius that it 1.91 ++ corresponds to is >=0. In the case where neither root has a positive 1.92 ++ radius, we don't draw anything. 1.93 + 1.94 ++ XXXmattwoodrow: I've removed this for now since it breaks 1.95 ++ down when Dr == 0. Is there something else we can do instead? 1.96 + In order to keep the math to within the limits of fixed point, 1.97 +- we divide the entire quadratic by Dr^2, and replace 1.98 ++ we divide the entire quadratic by Dr, and replace 1.99 + (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving 1.100 + 1.101 + [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2 1.102 + + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t 1.103 + + [x'^2 + y'^2 - Sr^2/Dr^2] = 0 1.104 + 1.105 + (x' and y' are computed by appending the subtract and scale to the 1.106 + fDstToIndex matrix in the constructor). 1.107 +@@ -1763,99 +1780,122 @@ void Radial_Gradient::shadeSpan(int x, i 1.108 + x' and y', if x and y are linear in the span, 'B' can be computed 1.109 + incrementally with a simple delta (db below). If it is not (e.g., 1.110 + a perspective projection), it must be computed in the loop. 1.111 + 1.112 + */ 1.113 + 1.114 + namespace { 1.115 + 1.116 +-inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy, 1.117 +- SkScalar sr2d2, SkScalar foura, 1.118 +- SkScalar oneOverTwoA, bool posRoot) { 1.119 ++inline bool two_point_radial(SkScalar b, SkScalar fx, SkScalar fy, 1.120 ++ SkScalar sr2d2, SkScalar foura, 1.121 ++ SkScalar oneOverTwoA, SkScalar diffRadius, 1.122 ++ SkScalar startRadius, SkFixed& t) { 1.123 + SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2; 1.124 + if (0 == foura) { 1.125 +- return SkScalarToFixed(SkScalarDiv(-c, b)); 1.126 ++ SkScalar result = SkScalarDiv(-c, b); 1.127 ++ if (result * diffRadius + startRadius >= 0) { 1.128 ++ t = SkScalarToFixed(result); 1.129 ++ return true; 1.130 ++ } 1.131 ++ return false; 1.132 + } 1.133 + 1.134 + SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c); 1.135 + if (discrim < 0) { 1.136 +- discrim = -discrim; 1.137 ++ return false; 1.138 + } 1.139 + SkScalar rootDiscrim = SkScalarSqrt(discrim); 1.140 +- SkScalar result; 1.141 +- if (posRoot) { 1.142 +- result = SkScalarMul(-b + rootDiscrim, oneOverTwoA); 1.143 +- } else { 1.144 +- result = SkScalarMul(-b - rootDiscrim, oneOverTwoA); 1.145 ++ 1.146 ++ // Make sure the results corresponds to a positive radius. 1.147 ++ SkScalar result = SkScalarMul(-b + rootDiscrim, oneOverTwoA); 1.148 ++ if (result * diffRadius + startRadius >= 0) { 1.149 ++ t = SkScalarToFixed(result); 1.150 ++ return true; 1.151 + } 1.152 +- return SkScalarToFixed(result); 1.153 ++ result = SkScalarMul(-b - rootDiscrim, oneOverTwoA); 1.154 ++ if (result * diffRadius + startRadius >= 0) { 1.155 ++ t = SkScalarToFixed(result); 1.156 ++ return true; 1.157 ++ } 1.158 ++ 1.159 ++ return false; 1.160 + } 1.161 + 1.162 + typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx, 1.163 + SkScalar fy, SkScalar dy, 1.164 + SkScalar b, SkScalar db, 1.165 +- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot, 1.166 ++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, 1.167 ++ SkScalar fDiffRadius, SkScalar fRadius1, 1.168 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.169 + int count); 1.170 + 1.171 + void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx, 1.172 + SkScalar fy, SkScalar dy, 1.173 + SkScalar b, SkScalar db, 1.174 +- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot, 1.175 ++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, 1.176 ++ SkScalar fDiffRadius, SkScalar fRadius1, 1.177 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.178 + int count) { 1.179 + for (; count > 0; --count) { 1.180 +- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, 1.181 +- fOneOverTwoA, posRoot); 1.182 +- 1.183 +- if (t < 0) { 1.184 ++ SkFixed t; 1.185 ++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) { 1.186 ++ *(dstC++) = 0; 1.187 ++ } else if (t < 0) { 1.188 + *dstC++ = cache[-1]; 1.189 + } else if (t > 0xFFFF) { 1.190 + *dstC++ = cache[Gradient_Shader::kCache32Count * 2]; 1.191 + } else { 1.192 + SkASSERT(t <= 0xFFFF); 1.193 + *dstC++ = cache[t >> Gradient_Shader::kCache32Shift]; 1.194 + } 1.195 + 1.196 + fx += dx; 1.197 + fy += dy; 1.198 + b += db; 1.199 + } 1.200 + } 1.201 + void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx, 1.202 + SkScalar fy, SkScalar dy, 1.203 + SkScalar b, SkScalar db, 1.204 +- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot, 1.205 ++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, 1.206 ++ SkScalar fDiffRadius, SkScalar fRadius1, 1.207 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.208 + int count) { 1.209 + for (; count > 0; --count) { 1.210 +- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, 1.211 +- fOneOverTwoA, posRoot); 1.212 +- SkFixed index = mirror_tileproc(t); 1.213 +- SkASSERT(index <= 0xFFFF); 1.214 +- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift]; 1.215 ++ SkFixed t; 1.216 ++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) { 1.217 ++ *(dstC++) = 0; 1.218 ++ } else { 1.219 ++ SkFixed index = mirror_tileproc(t); 1.220 ++ SkASSERT(index <= 0xFFFF); 1.221 ++ *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)]; 1.222 ++ } 1.223 + fx += dx; 1.224 + fy += dy; 1.225 + b += db; 1.226 + } 1.227 + } 1.228 + 1.229 + void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx, 1.230 + SkScalar fy, SkScalar dy, 1.231 + SkScalar b, SkScalar db, 1.232 +- SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot, 1.233 ++ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, 1.234 ++ SkScalar fDiffRadius, SkScalar fRadius1, 1.235 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.236 + int count) { 1.237 + for (; count > 0; --count) { 1.238 +- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, 1.239 +- fOneOverTwoA, posRoot); 1.240 +- SkFixed index = repeat_tileproc(t); 1.241 +- SkASSERT(index <= 0xFFFF); 1.242 +- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift]; 1.243 ++ SkFixed t; 1.244 ++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) { 1.245 ++ *(dstC++) = 0; 1.246 ++ } else { 1.247 ++ SkFixed index = repeat_tileproc(t); 1.248 ++ SkASSERT(index <= 0xFFFF); 1.249 ++ *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)]; 1.250 ++ } 1.251 + fx += dx; 1.252 + fy += dy; 1.253 + b += db; 1.254 + } 1.255 + } 1.256 + 1.257 + 1.258 + 1.259 +@@ -1935,17 +1975,16 @@ public: 1.260 + sk_bzero(dstC, count * sizeof(*dstC)); 1.261 + return; 1.262 + } 1.263 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.264 + TileProc proc = fTileProc; 1.265 + const SkPMColor* SK_RESTRICT cache = this->getCache32(); 1.266 + 1.267 + SkScalar foura = fA * 4; 1.268 +- bool posRoot = fDiffRadius < 0; 1.269 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.270 + SkPoint srcPt; 1.271 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.272 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.273 + SkScalar dx, fx = srcPt.fX; 1.274 + SkScalar dy, fy = srcPt.fY; 1.275 + 1.276 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.277 +@@ -1954,60 +1993,69 @@ public: 1.278 + dx = SkFixedToScalar(fixedX); 1.279 + dy = SkFixedToScalar(fixedY); 1.280 + } else { 1.281 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.282 + dx = fDstToIndex.getScaleX(); 1.283 + dy = fDstToIndex.getSkewY(); 1.284 + } 1.285 + SkScalar b = (SkScalarMul(fDiff.fX, fx) + 1.286 +- SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; 1.287 ++ SkScalarMul(fDiff.fY, fy) - fStartRadius * fDiffRadius) * 2; 1.288 + SkScalar db = (SkScalarMul(fDiff.fX, dx) + 1.289 + SkScalarMul(fDiff.fY, dy)) * 2; 1.290 + 1.291 + TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat; 1.292 + if (proc == clamp_tileproc) { 1.293 + shadeProc = shadeSpan_twopoint_clamp; 1.294 + } else if (proc == mirror_tileproc) { 1.295 + shadeProc = shadeSpan_twopoint_mirror; 1.296 + } else { 1.297 + SkASSERT(proc == repeat_tileproc); 1.298 + } 1.299 + (*shadeProc)(fx, dx, fy, dy, b, db, 1.300 +- fSr2D2, foura, fOneOverTwoA, posRoot, 1.301 ++ fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, 1.302 + dstC, cache, count); 1.303 + } else { // perspective case 1.304 + SkScalar dstX = SkIntToScalar(x); 1.305 + SkScalar dstY = SkIntToScalar(y); 1.306 + for (; count > 0; --count) { 1.307 + SkPoint srcPt; 1.308 + dstProc(fDstToIndex, dstX, dstY, &srcPt); 1.309 + SkScalar fx = srcPt.fX; 1.310 + SkScalar fy = srcPt.fY; 1.311 + SkScalar b = (SkScalarMul(fDiff.fX, fx) + 1.312 + SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; 1.313 +- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, 1.314 +- fOneOverTwoA, posRoot); 1.315 +- SkFixed index = proc(t); 1.316 +- SkASSERT(index <= 0xFFFF); 1.317 +- *dstC++ = cache[index >> Gradient_Shader::kCache32Shift]; 1.318 ++ SkFixed t; 1.319 ++ if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) { 1.320 ++ *(dstC++) = 0; 1.321 ++ } else { 1.322 ++ SkFixed index = proc(t); 1.323 ++ SkASSERT(index <= 0xFFFF); 1.324 ++ *dstC++ = cache[index >> (16 - kCache32Bits)]; 1.325 ++ } 1.326 + dstX += SK_Scalar1; 1.327 + } 1.328 + } 1.329 + } 1.330 + 1.331 + virtual bool setContext(const SkBitmap& device, 1.332 + const SkPaint& paint, 1.333 + const SkMatrix& matrix) SK_OVERRIDE { 1.334 + if (!this->INHERITED::setContext(device, paint, matrix)) { 1.335 + return false; 1.336 + } 1.337 + 1.338 + // we don't have a span16 proc 1.339 + fFlags &= ~kHasSpan16_Flag; 1.340 ++ 1.341 ++ // If we might end up wanting to draw nothing as part of the gradient 1.342 ++ // then we should mark ourselves as not being opaque. 1.343 ++ if (fA >= 0 || (fDiffRadius == 0 && fCenter1 == fCenter2)) { 1.344 ++ fFlags &= ~kOpaqueAlpha_Flag; 1.345 ++ } 1.346 + return true; 1.347 + } 1.348 + 1.349 + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Two_Point_Radial_Gradient) 1.350 + 1.351 + protected: 1.352 + Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer) 1.353 + : INHERITED(buffer), 1.354 +@@ -2033,26 +2081,22 @@ private: 1.355 + const SkScalar fRadius1; 1.356 + const SkScalar fRadius2; 1.357 + SkPoint fDiff; 1.358 + SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA; 1.359 + 1.360 + void init() { 1.361 + fDiff = fCenter1 - fCenter2; 1.362 + fDiffRadius = fRadius2 - fRadius1; 1.363 +- SkScalar inv = SkScalarInvert(fDiffRadius); 1.364 +- fDiff.fX = SkScalarMul(fDiff.fX, inv); 1.365 +- fDiff.fY = SkScalarMul(fDiff.fY, inv); 1.366 +- fStartRadius = SkScalarMul(fRadius1, inv); 1.367 ++ fStartRadius = fRadius1; 1.368 + fSr2D2 = SkScalarSquare(fStartRadius); 1.369 +- fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1; 1.370 ++ fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SkScalarSquare(fDiffRadius); 1.371 + fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0; 1.372 + 1.373 + fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY); 1.374 +- fPtsToUnit.postScale(inv, inv); 1.375 + } 1.376 + }; 1.377 + 1.378 + /////////////////////////////////////////////////////////////////////////////// 1.379 + 1.380 + class Sweep_Gradient : public Gradient_Shader { 1.381 + public: 1.382 + Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[], 1.383 +@@ -2488,16 +2532,20 @@ SkShader* SkGradientShader::CreateTwoPoi 1.384 + int colorCount, 1.385 + SkShader::TileMode mode, 1.386 + SkUnitMapper* mapper) { 1.387 + if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { 1.388 + return NULL; 1.389 + } 1.390 + EXPAND_1_COLOR(colorCount); 1.391 + 1.392 ++ if (start == end && startRadius == 0) { 1.393 ++ return CreateRadial(start, endRadius, colors, pos, colorCount, mode, mapper); 1.394 ++ } 1.395 ++ 1.396 + return SkNEW_ARGS(Two_Point_Radial_Gradient, 1.397 + (start, startRadius, end, endRadius, colors, pos, 1.398 + colorCount, mode, mapper)); 1.399 + } 1.400 + 1.401 + SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, 1.402 + const SkColor colors[], 1.403 + const SkScalar pos[],