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