gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # HG changeset patch
michael@0 2 # User Matt Woodrow <mwoodrow@mozilla.com>
michael@0 3 # Date 1339988782 -43200
michael@0 4 # Node ID 1e9dae659ee6c992f719fd4136efbcc5410ded37
michael@0 5 # Parent 946750f6d95febd199fb7b748e9d2c48fd01c8a6
michael@0 6 [mq]: skia-windows-gradients
michael@0 7
michael@0 8 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
michael@0 9 --- a/gfx/skia/src/effects/SkGradientShader.cpp
michael@0 10 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
michael@0 11 @@ -847,16 +847,19 @@ bool Linear_Gradient::setContext(const S
michael@0 12 fFlags |= SkShader::kConstInY32_Flag;
michael@0 13 if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
michael@0 14 // only claim this if we do have a 16bit mode (i.e. none of our
michael@0 15 // colors have alpha), and if we are not dithering (which obviously
michael@0 16 // is not const in Y).
michael@0 17 fFlags |= SkShader::kConstInY16_Flag;
michael@0 18 }
michael@0 19 }
michael@0 20 + if (fStart == fEnd) {
michael@0 21 + fFlags &= ~kOpaqueAlpha_Flag;
michael@0 22 + }
michael@0 23 return true;
michael@0 24 }
michael@0 25
michael@0 26 #define NO_CHECK_ITER \
michael@0 27 do { \
michael@0 28 unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
michael@0 29 SkASSERT(fi <= 0xFF); \
michael@0 30 fx += dx; \
michael@0 31 @@ -976,16 +979,21 @@ void Linear_Gradient::shadeSpan(int x, i
michael@0 32 TileProc proc = fTileProc;
michael@0 33 const SkPMColor* SK_RESTRICT cache = this->getCache32();
michael@0 34 #ifdef USE_DITHER_32BIT_GRADIENT
michael@0 35 int toggle = ((x ^ y) & 1) * kDitherStride32;
michael@0 36 #else
michael@0 37 int toggle = 0;
michael@0 38 #endif
michael@0 39
michael@0 40 + if (fStart == fEnd) {
michael@0 41 + sk_bzero(dstC, count * sizeof(*dstC));
michael@0 42 + return;
michael@0 43 + }
michael@0 44 +
michael@0 45 if (fDstToIndexClass != kPerspective_MatrixClass) {
michael@0 46 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 47 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
michael@0 48 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
michael@0 49
michael@0 50 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
michael@0 51 SkFixed dxStorage[1];
michael@0 52 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
michael@0 53 @@ -1169,16 +1177,21 @@ void Linear_Gradient::shadeSpan16(int x,
michael@0 54 SkASSERT(count > 0);
michael@0 55
michael@0 56 SkPoint srcPt;
michael@0 57 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
michael@0 58 TileProc proc = fTileProc;
michael@0 59 const uint16_t* SK_RESTRICT cache = this->getCache16();
michael@0 60 int toggle = ((x ^ y) & 1) * kDitherStride16;
michael@0 61
michael@0 62 + if (fStart == fEnd) {
michael@0 63 + sk_bzero(dstC, count * sizeof(*dstC));
michael@0 64 + return;
michael@0 65 + }
michael@0 66 +
michael@0 67 if (fDstToIndexClass != kPerspective_MatrixClass) {
michael@0 68 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 69 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
michael@0 70 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
michael@0 71
michael@0 72 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
michael@0 73 SkFixed dxStorage[1];
michael@0 74 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
michael@0 75 @@ -1739,21 +1752,25 @@ void Radial_Gradient::shadeSpan(int x, i
michael@0 76 possible circles on which the point may fall. Solving for t yields
michael@0 77 the gradient value to use.
michael@0 78
michael@0 79 If a<0, the start circle is entirely contained in the
michael@0 80 end circle, and one of the roots will be <0 or >1 (off the line
michael@0 81 segment). If a>0, the start circle falls at least partially
michael@0 82 outside the end circle (or vice versa), and the gradient
michael@0 83 defines a "tube" where a point may be on one circle (on the
michael@0 84 - inside of the tube) or the other (outside of the tube). We choose
michael@0 85 - one arbitrarily.
michael@0 86 + inside of the tube) or the other (outside of the tube). We choose
michael@0 87 + the one with the highest t value, as long as the radius that it
michael@0 88 + corresponds to is >=0. In the case where neither root has a positive
michael@0 89 + radius, we don't draw anything.
michael@0 90
michael@0 91 + XXXmattwoodrow: I've removed this for now since it breaks
michael@0 92 + down when Dr == 0. Is there something else we can do instead?
michael@0 93 In order to keep the math to within the limits of fixed point,
michael@0 94 - we divide the entire quadratic by Dr^2, and replace
michael@0 95 + we divide the entire quadratic by Dr, and replace
michael@0 96 (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
michael@0 97
michael@0 98 [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
michael@0 99 + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
michael@0 100 + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
michael@0 101
michael@0 102 (x' and y' are computed by appending the subtract and scale to the
michael@0 103 fDstToIndex matrix in the constructor).
michael@0 104 @@ -1763,99 +1780,122 @@ void Radial_Gradient::shadeSpan(int x, i
michael@0 105 x' and y', if x and y are linear in the span, 'B' can be computed
michael@0 106 incrementally with a simple delta (db below). If it is not (e.g.,
michael@0 107 a perspective projection), it must be computed in the loop.
michael@0 108
michael@0 109 */
michael@0 110
michael@0 111 namespace {
michael@0 112
michael@0 113 -inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
michael@0 114 - SkScalar sr2d2, SkScalar foura,
michael@0 115 - SkScalar oneOverTwoA, bool posRoot) {
michael@0 116 +inline bool two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
michael@0 117 + SkScalar sr2d2, SkScalar foura,
michael@0 118 + SkScalar oneOverTwoA, SkScalar diffRadius,
michael@0 119 + SkScalar startRadius, SkFixed& t) {
michael@0 120 SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
michael@0 121 if (0 == foura) {
michael@0 122 - return SkScalarToFixed(SkScalarDiv(-c, b));
michael@0 123 + SkScalar result = SkScalarDiv(-c, b);
michael@0 124 + if (result * diffRadius + startRadius >= 0) {
michael@0 125 + t = SkScalarToFixed(result);
michael@0 126 + return true;
michael@0 127 + }
michael@0 128 + return false;
michael@0 129 }
michael@0 130
michael@0 131 SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
michael@0 132 if (discrim < 0) {
michael@0 133 - discrim = -discrim;
michael@0 134 + return false;
michael@0 135 }
michael@0 136 SkScalar rootDiscrim = SkScalarSqrt(discrim);
michael@0 137 - SkScalar result;
michael@0 138 - if (posRoot) {
michael@0 139 - result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
michael@0 140 - } else {
michael@0 141 - result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
michael@0 142 +
michael@0 143 + // Make sure the results corresponds to a positive radius.
michael@0 144 + SkScalar result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
michael@0 145 + if (result * diffRadius + startRadius >= 0) {
michael@0 146 + t = SkScalarToFixed(result);
michael@0 147 + return true;
michael@0 148 }
michael@0 149 - return SkScalarToFixed(result);
michael@0 150 + result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
michael@0 151 + if (result * diffRadius + startRadius >= 0) {
michael@0 152 + t = SkScalarToFixed(result);
michael@0 153 + return true;
michael@0 154 + }
michael@0 155 +
michael@0 156 + return false;
michael@0 157 }
michael@0 158
michael@0 159 typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
michael@0 160 SkScalar fy, SkScalar dy,
michael@0 161 SkScalar b, SkScalar db,
michael@0 162 - SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
michael@0 163 + SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
michael@0 164 + SkScalar fDiffRadius, SkScalar fRadius1,
michael@0 165 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
michael@0 166 int count);
michael@0 167
michael@0 168 void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
michael@0 169 SkScalar fy, SkScalar dy,
michael@0 170 SkScalar b, SkScalar db,
michael@0 171 - SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
michael@0 172 + SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
michael@0 173 + SkScalar fDiffRadius, SkScalar fRadius1,
michael@0 174 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
michael@0 175 int count) {
michael@0 176 for (; count > 0; --count) {
michael@0 177 - SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
michael@0 178 - fOneOverTwoA, posRoot);
michael@0 179 -
michael@0 180 - if (t < 0) {
michael@0 181 + SkFixed t;
michael@0 182 + if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
michael@0 183 + *(dstC++) = 0;
michael@0 184 + } else if (t < 0) {
michael@0 185 *dstC++ = cache[-1];
michael@0 186 } else if (t > 0xFFFF) {
michael@0 187 *dstC++ = cache[Gradient_Shader::kCache32Count * 2];
michael@0 188 } else {
michael@0 189 SkASSERT(t <= 0xFFFF);
michael@0 190 *dstC++ = cache[t >> Gradient_Shader::kCache32Shift];
michael@0 191 }
michael@0 192
michael@0 193 fx += dx;
michael@0 194 fy += dy;
michael@0 195 b += db;
michael@0 196 }
michael@0 197 }
michael@0 198 void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
michael@0 199 SkScalar fy, SkScalar dy,
michael@0 200 SkScalar b, SkScalar db,
michael@0 201 - SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
michael@0 202 + SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
michael@0 203 + SkScalar fDiffRadius, SkScalar fRadius1,
michael@0 204 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
michael@0 205 int count) {
michael@0 206 for (; count > 0; --count) {
michael@0 207 - SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
michael@0 208 - fOneOverTwoA, posRoot);
michael@0 209 - SkFixed index = mirror_tileproc(t);
michael@0 210 - SkASSERT(index <= 0xFFFF);
michael@0 211 - *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
michael@0 212 + SkFixed t;
michael@0 213 + if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
michael@0 214 + *(dstC++) = 0;
michael@0 215 + } else {
michael@0 216 + SkFixed index = mirror_tileproc(t);
michael@0 217 + SkASSERT(index <= 0xFFFF);
michael@0 218 + *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
michael@0 219 + }
michael@0 220 fx += dx;
michael@0 221 fy += dy;
michael@0 222 b += db;
michael@0 223 }
michael@0 224 }
michael@0 225
michael@0 226 void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
michael@0 227 SkScalar fy, SkScalar dy,
michael@0 228 SkScalar b, SkScalar db,
michael@0 229 - SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
michael@0 230 + SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
michael@0 231 + SkScalar fDiffRadius, SkScalar fRadius1,
michael@0 232 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
michael@0 233 int count) {
michael@0 234 for (; count > 0; --count) {
michael@0 235 - SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
michael@0 236 - fOneOverTwoA, posRoot);
michael@0 237 - SkFixed index = repeat_tileproc(t);
michael@0 238 - SkASSERT(index <= 0xFFFF);
michael@0 239 - *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
michael@0 240 + SkFixed t;
michael@0 241 + if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
michael@0 242 + *(dstC++) = 0;
michael@0 243 + } else {
michael@0 244 + SkFixed index = repeat_tileproc(t);
michael@0 245 + SkASSERT(index <= 0xFFFF);
michael@0 246 + *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
michael@0 247 + }
michael@0 248 fx += dx;
michael@0 249 fy += dy;
michael@0 250 b += db;
michael@0 251 }
michael@0 252 }
michael@0 253
michael@0 254
michael@0 255
michael@0 256 @@ -1935,17 +1975,16 @@ public:
michael@0 257 sk_bzero(dstC, count * sizeof(*dstC));
michael@0 258 return;
michael@0 259 }
michael@0 260 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
michael@0 261 TileProc proc = fTileProc;
michael@0 262 const SkPMColor* SK_RESTRICT cache = this->getCache32();
michael@0 263
michael@0 264 SkScalar foura = fA * 4;
michael@0 265 - bool posRoot = fDiffRadius < 0;
michael@0 266 if (fDstToIndexClass != kPerspective_MatrixClass) {
michael@0 267 SkPoint srcPt;
michael@0 268 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 269 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
michael@0 270 SkScalar dx, fx = srcPt.fX;
michael@0 271 SkScalar dy, fy = srcPt.fY;
michael@0 272
michael@0 273 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
michael@0 274 @@ -1954,60 +1993,69 @@ public:
michael@0 275 dx = SkFixedToScalar(fixedX);
michael@0 276 dy = SkFixedToScalar(fixedY);
michael@0 277 } else {
michael@0 278 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
michael@0 279 dx = fDstToIndex.getScaleX();
michael@0 280 dy = fDstToIndex.getSkewY();
michael@0 281 }
michael@0 282 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
michael@0 283 - SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
michael@0 284 + SkScalarMul(fDiff.fY, fy) - fStartRadius * fDiffRadius) * 2;
michael@0 285 SkScalar db = (SkScalarMul(fDiff.fX, dx) +
michael@0 286 SkScalarMul(fDiff.fY, dy)) * 2;
michael@0 287
michael@0 288 TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
michael@0 289 if (proc == clamp_tileproc) {
michael@0 290 shadeProc = shadeSpan_twopoint_clamp;
michael@0 291 } else if (proc == mirror_tileproc) {
michael@0 292 shadeProc = shadeSpan_twopoint_mirror;
michael@0 293 } else {
michael@0 294 SkASSERT(proc == repeat_tileproc);
michael@0 295 }
michael@0 296 (*shadeProc)(fx, dx, fy, dy, b, db,
michael@0 297 - fSr2D2, foura, fOneOverTwoA, posRoot,
michael@0 298 + fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1,
michael@0 299 dstC, cache, count);
michael@0 300 } else { // perspective case
michael@0 301 SkScalar dstX = SkIntToScalar(x);
michael@0 302 SkScalar dstY = SkIntToScalar(y);
michael@0 303 for (; count > 0; --count) {
michael@0 304 SkPoint srcPt;
michael@0 305 dstProc(fDstToIndex, dstX, dstY, &srcPt);
michael@0 306 SkScalar fx = srcPt.fX;
michael@0 307 SkScalar fy = srcPt.fY;
michael@0 308 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
michael@0 309 SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
michael@0 310 - SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
michael@0 311 - fOneOverTwoA, posRoot);
michael@0 312 - SkFixed index = proc(t);
michael@0 313 - SkASSERT(index <= 0xFFFF);
michael@0 314 - *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
michael@0 315 + SkFixed t;
michael@0 316 + if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
michael@0 317 + *(dstC++) = 0;
michael@0 318 + } else {
michael@0 319 + SkFixed index = proc(t);
michael@0 320 + SkASSERT(index <= 0xFFFF);
michael@0 321 + *dstC++ = cache[index >> (16 - kCache32Bits)];
michael@0 322 + }
michael@0 323 dstX += SK_Scalar1;
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 virtual bool setContext(const SkBitmap& device,
michael@0 329 const SkPaint& paint,
michael@0 330 const SkMatrix& matrix) SK_OVERRIDE {
michael@0 331 if (!this->INHERITED::setContext(device, paint, matrix)) {
michael@0 332 return false;
michael@0 333 }
michael@0 334
michael@0 335 // we don't have a span16 proc
michael@0 336 fFlags &= ~kHasSpan16_Flag;
michael@0 337 +
michael@0 338 + // If we might end up wanting to draw nothing as part of the gradient
michael@0 339 + // then we should mark ourselves as not being opaque.
michael@0 340 + if (fA >= 0 || (fDiffRadius == 0 && fCenter1 == fCenter2)) {
michael@0 341 + fFlags &= ~kOpaqueAlpha_Flag;
michael@0 342 + }
michael@0 343 return true;
michael@0 344 }
michael@0 345
michael@0 346 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Two_Point_Radial_Gradient)
michael@0 347
michael@0 348 protected:
michael@0 349 Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
michael@0 350 : INHERITED(buffer),
michael@0 351 @@ -2033,26 +2081,22 @@ private:
michael@0 352 const SkScalar fRadius1;
michael@0 353 const SkScalar fRadius2;
michael@0 354 SkPoint fDiff;
michael@0 355 SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
michael@0 356
michael@0 357 void init() {
michael@0 358 fDiff = fCenter1 - fCenter2;
michael@0 359 fDiffRadius = fRadius2 - fRadius1;
michael@0 360 - SkScalar inv = SkScalarInvert(fDiffRadius);
michael@0 361 - fDiff.fX = SkScalarMul(fDiff.fX, inv);
michael@0 362 - fDiff.fY = SkScalarMul(fDiff.fY, inv);
michael@0 363 - fStartRadius = SkScalarMul(fRadius1, inv);
michael@0 364 + fStartRadius = fRadius1;
michael@0 365 fSr2D2 = SkScalarSquare(fStartRadius);
michael@0 366 - fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
michael@0 367 + fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SkScalarSquare(fDiffRadius);
michael@0 368 fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
michael@0 369
michael@0 370 fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
michael@0 371 - fPtsToUnit.postScale(inv, inv);
michael@0 372 }
michael@0 373 };
michael@0 374
michael@0 375 ///////////////////////////////////////////////////////////////////////////////
michael@0 376
michael@0 377 class Sweep_Gradient : public Gradient_Shader {
michael@0 378 public:
michael@0 379 Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
michael@0 380 @@ -2488,16 +2532,20 @@ SkShader* SkGradientShader::CreateTwoPoi
michael@0 381 int colorCount,
michael@0 382 SkShader::TileMode mode,
michael@0 383 SkUnitMapper* mapper) {
michael@0 384 if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
michael@0 385 return NULL;
michael@0 386 }
michael@0 387 EXPAND_1_COLOR(colorCount);
michael@0 388
michael@0 389 + if (start == end && startRadius == 0) {
michael@0 390 + return CreateRadial(start, endRadius, colors, pos, colorCount, mode, mapper);
michael@0 391 + }
michael@0 392 +
michael@0 393 return SkNEW_ARGS(Two_Point_Radial_Gradient,
michael@0 394 (start, startRadius, end, endRadius, colors, pos,
michael@0 395 colorCount, mode, mapper));
michael@0 396 }
michael@0 397
michael@0 398 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
michael@0 399 const SkColor colors[],
michael@0 400 const SkScalar pos[],

mercurial