OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkTwoPointConicalGradient.h" | 8 #include "SkTwoPointConicalGradient.h" |
9 | 9 |
10 #include "SkTwoPointConicalGradient_gpu.h" | 10 #include "SkTwoPointConicalGradient_gpu.h" |
11 | 11 |
12 static int valid_divide(float numer, float denom, float* ratio) { | 12 static int valid_divide(float numer, float denom, float* ratio) { |
13 SkASSERT(ratio); | 13 SkASSERT(ratio); |
14 if (0 == denom) { | 14 if (0 == denom) { |
15 return 0; | 15 return 0; |
16 } | 16 } |
17 *ratio = numer / denom; | 17 *ratio = numer / denom; |
18 return 1; | 18 return 1; |
19 } | 19 } |
20 | 20 |
21 // Return the number of distinct real roots, and write them into roots[] in | 21 // Return the number of distinct real roots, and write them into roots[] in |
22 // ascending order | 22 // ascending order |
23 static int find_quad_roots(float A, float B, float C, float roots[2]) { | 23 static int find_quad_roots(float A, float B, float C, float roots[2], bool desce
ndingOrder = false) { |
24 SkASSERT(roots); | 24 SkASSERT(roots); |
25 | 25 |
26 if (A == 0) { | 26 if (A == 0) { |
27 return valid_divide(-C, B, roots); | 27 return valid_divide(-C, B, roots); |
28 } | 28 } |
29 | 29 |
30 float R = B*B - 4*A*C; | 30 float R = B*B - 4*A*C; |
31 if (R < 0) { | 31 if (R < 0) { |
32 return 0; | 32 return 0; |
33 } | 33 } |
(...skipping 13 matching lines...) Expand all Loading... |
47 Q *= -0.5f; | 47 Q *= -0.5f; |
48 if (0 == Q) { | 48 if (0 == Q) { |
49 roots[0] = 0; | 49 roots[0] = 0; |
50 return 1; | 50 return 1; |
51 } | 51 } |
52 | 52 |
53 float r0 = Q / A; | 53 float r0 = Q / A; |
54 float r1 = C / Q; | 54 float r1 = C / Q; |
55 roots[0] = r0 < r1 ? r0 : r1; | 55 roots[0] = r0 < r1 ? r0 : r1; |
56 roots[1] = r0 > r1 ? r0 : r1; | 56 roots[1] = r0 > r1 ? r0 : r1; |
| 57 if (descendingOrder) { |
| 58 SkTSwap(roots[0], roots[1]); |
| 59 } |
57 return 2; | 60 return 2; |
58 } | 61 } |
59 | 62 |
60 static float lerp(float x, float dx, float t) { | 63 static float lerp(float x, float dx, float t) { |
61 return x + t * dx; | 64 return x + t * dx; |
62 } | 65 } |
63 | 66 |
64 static float sqr(float x) { return x * x; } | 67 static float sqr(float x) { return x * x; } |
65 | 68 |
66 void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0, | 69 void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0, |
67 const SkPoint& center1, SkScalar rad1) { | 70 const SkPoint& center1, SkScalar rad1, |
| 71 bool flipped) { |
68 fCenterX = SkScalarToFloat(center0.fX); | 72 fCenterX = SkScalarToFloat(center0.fX); |
69 fCenterY = SkScalarToFloat(center0.fY); | 73 fCenterY = SkScalarToFloat(center0.fY); |
70 fDCenterX = SkScalarToFloat(center1.fX) - fCenterX; | 74 fDCenterX = SkScalarToFloat(center1.fX) - fCenterX; |
71 fDCenterY = SkScalarToFloat(center1.fY) - fCenterY; | 75 fDCenterY = SkScalarToFloat(center1.fY) - fCenterY; |
72 fRadius = SkScalarToFloat(rad0); | 76 fRadius = SkScalarToFloat(rad0); |
73 fDRadius = SkScalarToFloat(rad1) - fRadius; | 77 fDRadius = SkScalarToFloat(rad1) - fRadius; |
74 | 78 |
75 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); | 79 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); |
76 fRadius2 = sqr(fRadius); | 80 fRadius2 = sqr(fRadius); |
77 fRDR = fRadius * fDRadius; | 81 fRDR = fRadius * fDRadius; |
| 82 |
| 83 fFlipped = flipped; |
78 } | 84 } |
79 | 85 |
80 void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) { | 86 void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) { |
81 fRelX = SkScalarToFloat(fx) - fCenterX; | 87 fRelX = SkScalarToFloat(fx) - fCenterX; |
82 fRelY = SkScalarToFloat(fy) - fCenterY; | 88 fRelY = SkScalarToFloat(fy) - fCenterY; |
83 fIncX = SkScalarToFloat(dfx); | 89 fIncX = SkScalarToFloat(dfx); |
84 fIncY = SkScalarToFloat(dfy); | 90 fIncY = SkScalarToFloat(dfy); |
85 fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR); | 91 fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR); |
86 fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY); | 92 fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY); |
87 } | 93 } |
88 | 94 |
89 SkFixed TwoPtRadial::nextT() { | 95 SkFixed TwoPtRadial::nextT() { |
90 float roots[2]; | 96 float roots[2]; |
91 | 97 |
92 float C = sqr(fRelX) + sqr(fRelY) - fRadius2; | 98 float C = sqr(fRelX) + sqr(fRelY) - fRadius2; |
93 int countRoots = find_quad_roots(fA, fB, C, roots); | 99 int countRoots = find_quad_roots(fA, fB, C, roots, fFlipped); |
94 | 100 |
95 fRelX += fIncX; | 101 fRelX += fIncX; |
96 fRelY += fIncY; | 102 fRelY += fIncY; |
97 fB += fDB; | 103 fB += fDB; |
98 | 104 |
99 if (0 == countRoots) { | 105 if (0 == countRoots) { |
100 return kDontDrawT; | 106 return kDontDrawT; |
101 } | 107 } |
102 | 108 |
103 // Prefer the bigger t value if both give a radius(t) > 0 | 109 // Prefer the bigger t value if both give a radius(t) > 0 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 SkFixed index = mirror_tileproc(t); | 168 SkFixed index = mirror_tileproc(t); |
163 SkASSERT(index <= 0xFFFF); | 169 SkASSERT(index <= 0xFFFF); |
164 *dstC++ = cache[toggle + | 170 *dstC++ = cache[toggle + |
165 (index >> SkGradientShaderBase::kCache32Shift)]; | 171 (index >> SkGradientShaderBase::kCache32Shift)]; |
166 } | 172 } |
167 toggle = next_dither_toggle(toggle); | 173 toggle = next_dither_toggle(toggle); |
168 } | 174 } |
169 } | 175 } |
170 | 176 |
171 void SkTwoPointConicalGradient::init() { | 177 void SkTwoPointConicalGradient::init() { |
172 fRec.init(fCenter1, fRadius1, fCenter2, fRadius2); | 178 fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad); |
173 fPtsToUnit.reset(); | 179 fPtsToUnit.reset(); |
174 } | 180 } |
175 | 181 |
176 ///////////////////////////////////////////////////////////////////// | 182 ///////////////////////////////////////////////////////////////////// |
177 | 183 |
178 SkTwoPointConicalGradient::SkTwoPointConicalGradient( | 184 SkTwoPointConicalGradient::SkTwoPointConicalGradient( |
179 const SkPoint& start, SkScalar startRadius, | 185 const SkPoint& start, SkScalar startRadius, |
180 const SkPoint& end, SkScalar endRadius, | 186 const SkPoint& end, SkScalar endRadius, |
181 const Descriptor& desc) | 187 bool flippedGrad, const Descriptor& desc) |
182 : SkGradientShaderBase(desc), | 188 : SkGradientShaderBase(desc), |
183 fCenter1(start), | 189 fCenter1(start), |
184 fCenter2(end), | 190 fCenter2(end), |
185 fRadius1(startRadius), | 191 fRadius1(startRadius), |
186 fRadius2(endRadius) { | 192 fRadius2(endRadius), |
| 193 fFlippedGrad(flippedGrad) { |
187 // this is degenerate, and should be caught by our caller | 194 // this is degenerate, and should be caught by our caller |
188 SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2); | 195 SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2); |
189 this->init(); | 196 this->init(); |
190 } | 197 } |
191 | 198 |
192 bool SkTwoPointConicalGradient::isOpaque() const { | 199 bool SkTwoPointConicalGradient::isOpaque() const { |
193 // Because areas outside the cone are left untouched, we cannot treat the | 200 // Because areas outside the cone are left untouched, we cannot treat the |
194 // shader as opaque even if the gradient itself is opaque. | 201 // shader as opaque even if the gradient itself is opaque. |
195 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 | 202 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 |
196 return false; | 203 return false; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 } | 299 } |
293 matrix->preTranslate(-fCenter1.fX, -fCenter1.fY); | 300 matrix->preTranslate(-fCenter1.fX, -fCenter1.fY); |
294 } | 301 } |
295 if (xy) { | 302 if (xy) { |
296 xy[0] = fTileMode; | 303 xy[0] = fTileMode; |
297 xy[1] = kClamp_TileMode; | 304 xy[1] = kClamp_TileMode; |
298 } | 305 } |
299 return kTwoPointConical_BitmapType; | 306 return kTwoPointConical_BitmapType; |
300 } | 307 } |
301 | 308 |
| 309 // Returns the original non-sorted version of the gradient |
302 SkShader::GradientType SkTwoPointConicalGradient::asAGradient( | 310 SkShader::GradientType SkTwoPointConicalGradient::asAGradient( |
303 GradientInfo* info) const { | 311 GradientInfo* info) const { |
304 if (info) { | 312 if (info) { |
305 commonAsAGradient(info); | 313 commonAsAGradient(info, fFlippedGrad); |
306 info->fPoint[0] = fCenter1; | 314 info->fPoint[0] = fCenter1; |
307 info->fPoint[1] = fCenter2; | 315 info->fPoint[1] = fCenter2; |
308 info->fRadius[0] = fRadius1; | 316 info->fRadius[0] = fRadius1; |
309 info->fRadius[1] = fRadius2; | 317 info->fRadius[1] = fRadius2; |
| 318 if (fFlippedGrad) { |
| 319 SkTSwap(info->fPoint[0], info->fPoint[1]); |
| 320 SkTSwap(info->fRadius[0], info->fRadius[1]); |
| 321 } |
310 } | 322 } |
311 return kConical_GradientType; | 323 return kConical_GradientType; |
312 } | 324 } |
313 | 325 |
314 SkTwoPointConicalGradient::SkTwoPointConicalGradient( | 326 SkTwoPointConicalGradient::SkTwoPointConicalGradient( |
315 SkReadBuffer& buffer) | 327 SkReadBuffer& buffer) |
316 : INHERITED(buffer), | 328 : INHERITED(buffer), |
317 fCenter1(buffer.readPoint()), | 329 fCenter1(buffer.readPoint()), |
318 fCenter2(buffer.readPoint()), | 330 fCenter2(buffer.readPoint()), |
319 fRadius1(buffer.readScalar()), | 331 fRadius1(buffer.readScalar()), |
320 fRadius2(buffer.readScalar()) { | 332 fRadius2(buffer.readScalar()) { |
| 333 if (buffer.pictureVersion() >= 24 || 0 == buffer.pictureVersion()) { |
| 334 fFlippedGrad = buffer.readBool(); |
| 335 } else { |
| 336 // V23_COMPATIBILITY_CODE |
| 337 // Sort gradient by radius size for old pictures |
| 338 if (fRadius2 < fRadius1) { |
| 339 SkTSwap(fCenter1, fCenter2); |
| 340 SkTSwap(fRadius1, fRadius2); |
| 341 this->flipGradientColors(); |
| 342 fFlippedGrad = true; |
| 343 } else { |
| 344 fFlippedGrad = false; |
| 345 } |
| 346 } |
321 this->init(); | 347 this->init(); |
322 }; | 348 }; |
323 | 349 |
324 void SkTwoPointConicalGradient::flatten( | 350 void SkTwoPointConicalGradient::flatten( |
325 SkWriteBuffer& buffer) const { | 351 SkWriteBuffer& buffer) const { |
326 this->INHERITED::flatten(buffer); | 352 this->INHERITED::flatten(buffer); |
327 buffer.writePoint(fCenter1); | 353 buffer.writePoint(fCenter1); |
328 buffer.writePoint(fCenter2); | 354 buffer.writePoint(fCenter2); |
329 buffer.writeScalar(fRadius1); | 355 buffer.writeScalar(fRadius1); |
330 buffer.writeScalar(fRadius2); | 356 buffer.writeScalar(fRadius2); |
| 357 buffer.writeBool(fFlippedGrad); |
331 } | 358 } |
332 | 359 |
333 #if SK_SUPPORT_GPU | 360 #if SK_SUPPORT_GPU |
334 | 361 |
335 GrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext* context, const Sk
Paint&) const { | 362 GrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext* context, const Sk
Paint&) const { |
336 SkASSERT(NULL != context); | 363 SkASSERT(NULL != context); |
337 SkASSERT(fPtsToUnit.isIdentity()); | 364 SkASSERT(fPtsToUnit.isIdentity()); |
338 | 365 |
339 return Gr2PtConicalGradientEffect::Create(context, *this, fTileMode); | 366 return Gr2PtConicalGradientEffect::Create(context, *this, fTileMode); |
340 } | 367 } |
(...skipping 25 matching lines...) Expand all Loading... |
366 str->appendScalar(fCenter2.fY); | 393 str->appendScalar(fCenter2.fY); |
367 str->append(") radius2: "); | 394 str->append(") radius2: "); |
368 str->appendScalar(fRadius2); | 395 str->appendScalar(fRadius2); |
369 str->append(" "); | 396 str->append(" "); |
370 | 397 |
371 this->INHERITED::toString(str); | 398 this->INHERITED::toString(str); |
372 | 399 |
373 str->append(")"); | 400 str->append(")"); |
374 } | 401 } |
375 #endif | 402 #endif |
OLD | NEW |