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 struct TwoPtRadialContext { | |
11 const TwoPtRadial& fRec; | |
12 float fRelX, fRelY; | |
13 const float fIncX, fIncY; | |
14 float fB; | |
15 const float fDB; | |
16 | |
17 TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, | |
18 SkScalar dfx, SkScalar dfy); | |
19 SkFixed nextT(); | |
20 }; | |
21 | |
10 static int valid_divide(float numer, float denom, float* ratio) { | 22 static int valid_divide(float numer, float denom, float* ratio) { |
11 SkASSERT(ratio); | 23 SkASSERT(ratio); |
12 if (0 == denom) { | 24 if (0 == denom) { |
13 return 0; | 25 return 0; |
14 } | 26 } |
15 *ratio = numer / denom; | 27 *ratio = numer / denom; |
16 return 1; | 28 return 1; |
17 } | 29 } |
18 | 30 |
19 // Return the number of distinct real roots, and write them into roots[] in | 31 // Return the number of distinct real roots, and write them into roots[] in |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 fDCenterX = SkScalarToFloat(center1.fX) - fCenterX; | 80 fDCenterX = SkScalarToFloat(center1.fX) - fCenterX; |
69 fDCenterY = SkScalarToFloat(center1.fY) - fCenterY; | 81 fDCenterY = SkScalarToFloat(center1.fY) - fCenterY; |
70 fRadius = SkScalarToFloat(rad0); | 82 fRadius = SkScalarToFloat(rad0); |
71 fDRadius = SkScalarToFloat(rad1) - fRadius; | 83 fDRadius = SkScalarToFloat(rad1) - fRadius; |
72 | 84 |
73 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); | 85 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); |
74 fRadius2 = sqr(fRadius); | 86 fRadius2 = sqr(fRadius); |
75 fRDR = fRadius * fDRadius; | 87 fRDR = fRadius * fDRadius; |
76 } | 88 } |
77 | 89 |
78 void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) { | 90 TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkSc alar fy, |
79 fRelX = SkScalarToFloat(fx) - fCenterX; | 91 SkScalar dfx, SkScalar dfy) |
80 fRelY = SkScalarToFloat(fy) - fCenterY; | 92 : fRec(rec) |
81 fIncX = SkScalarToFloat(dfx); | 93 , fRelX(SkScalarToFloat(fx) - rec.fCenterX) |
82 fIncY = SkScalarToFloat(dfy); | 94 , fRelY(SkScalarToFloat(fy) - rec.fCenterY) |
83 fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR); | 95 , fIncX(SkScalarToFloat(dfx)) |
84 fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY); | 96 , fIncY(SkScalarToFloat(dfy)) |
85 } | 97 , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR)) |
98 , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {} | |
86 | 99 |
87 SkFixed TwoPtRadial::nextT() { | 100 SkFixed TwoPtRadialContext::nextT() { |
88 float roots[2]; | 101 float roots[2]; |
89 | 102 |
90 float C = sqr(fRelX) + sqr(fRelY) - fRadius2; | 103 float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2; |
91 int countRoots = find_quad_roots(fA, fB, C, roots); | 104 int countRoots = find_quad_roots(fRec.fA, fB, C, roots); |
92 | 105 |
93 fRelX += fIncX; | 106 fRelX += fIncX; |
94 fRelY += fIncY; | 107 fRelY += fIncY; |
95 fB += fDB; | 108 fB += fDB; |
96 | 109 |
97 if (0 == countRoots) { | 110 if (0 == countRoots) { |
98 return kDontDrawT; | 111 return TwoPtRadial::kDontDrawT; |
99 } | 112 } |
100 | 113 |
101 // Prefer the bigger t value if both give a radius(t) > 0 | 114 // Prefer the bigger t value if both give a radius(t) > 0 |
102 // find_quad_roots returns the values sorted, so we start with the last | 115 // find_quad_roots returns the values sorted, so we start with the last |
103 float t = roots[countRoots - 1]; | 116 float t = roots[countRoots - 1]; |
104 float r = lerp(fRadius, fDRadius, t); | 117 float r = lerp(fRec.fRadius, fRec.fDRadius, t); |
105 if (r <= 0) { | 118 if (r <= 0) { |
106 t = roots[0]; // might be the same as roots[countRoots-1] | 119 t = roots[0]; // might be the same as roots[countRoots-1] |
107 r = lerp(fRadius, fDRadius, t); | 120 r = lerp(fRec.fRadius, fRec.fDRadius, t); |
108 if (r <= 0) { | 121 if (r <= 0) { |
109 return kDontDrawT; | 122 return TwoPtRadial::kDontDrawT; |
110 } | 123 } |
111 } | 124 } |
112 return SkFloatToFixed(t); | 125 return SkFloatToFixed(t); |
113 } | 126 } |
114 | 127 |
115 typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC, | 128 typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC, |
116 const SkPMColor* cache, int toggle, int coun t); | 129 const SkPMColor* cache, int toggle, int coun t); |
117 | 130 |
118 static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 131 static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, |
119 const SkPMColor* SK_RESTRICT cache, int toggle, | 132 const SkPMColor* SK_RESTRICT cache, int toggle, |
120 int count) { | 133 int count) { |
121 for (; count > 0; --count) { | 134 for (; count > 0; --count) { |
122 SkFixed t = rec->nextT(); | 135 SkFixed t = rec->nextT(); |
123 if (TwoPtRadial::DontDrawT(t)) { | 136 if (TwoPtRadial::DontDrawT(t)) { |
124 *dstC++ = 0; | 137 *dstC++ = 0; |
125 } else { | 138 } else { |
126 SkFixed index = SkClampMax(t, 0xFFFF); | 139 SkFixed index = SkClampMax(t, 0xFFFF); |
127 SkASSERT(index <= 0xFFFF); | 140 SkASSERT(index <= 0xFFFF); |
128 *dstC++ = cache[toggle + | 141 *dstC++ = cache[toggle + |
129 (index >> SkGradientShaderBase::kCache32Shift)]; | 142 (index >> SkGradientShaderBase::kCache32Shift)]; |
130 } | 143 } |
131 toggle = next_dither_toggle(toggle); | 144 toggle = next_dither_toggle(toggle); |
132 } | 145 } |
133 } | 146 } |
134 | 147 |
135 static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 148 static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC , |
136 const SkPMColor* SK_RESTRICT cache, int toggle, | 149 const SkPMColor* SK_RESTRICT cache, int toggle, |
137 int count) { | 150 int count) { |
138 for (; count > 0; --count) { | 151 for (; count > 0; --count) { |
139 SkFixed t = rec->nextT(); | 152 SkFixed t = rec->nextT(); |
140 if (TwoPtRadial::DontDrawT(t)) { | 153 if (TwoPtRadial::DontDrawT(t)) { |
141 *dstC++ = 0; | 154 *dstC++ = 0; |
142 } else { | 155 } else { |
143 SkFixed index = repeat_tileproc(t); | 156 SkFixed index = repeat_tileproc(t); |
144 SkASSERT(index <= 0xFFFF); | 157 SkASSERT(index <= 0xFFFF); |
145 *dstC++ = cache[toggle + | 158 *dstC++ = cache[toggle + |
146 (index >> SkGradientShaderBase::kCache32Shift)]; | 159 (index >> SkGradientShaderBase::kCache32Shift)]; |
147 } | 160 } |
148 toggle = next_dither_toggle(toggle); | 161 toggle = next_dither_toggle(toggle); |
149 } | 162 } |
150 } | 163 } |
151 | 164 |
152 static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 165 static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC , |
153 const SkPMColor* SK_RESTRICT cache, int toggle, | 166 const SkPMColor* SK_RESTRICT cache, int toggle, |
154 int count) { | 167 int count) { |
155 for (; count > 0; --count) { | 168 for (; count > 0; --count) { |
156 SkFixed t = rec->nextT(); | 169 SkFixed t = rec->nextT(); |
157 if (TwoPtRadial::DontDrawT(t)) { | 170 if (TwoPtRadial::DontDrawT(t)) { |
158 *dstC++ = 0; | 171 *dstC++ = 0; |
159 } else { | 172 } else { |
160 SkFixed index = mirror_tileproc(t); | 173 SkFixed index = mirror_tileproc(t); |
161 SkASSERT(index <= 0xFFFF); | 174 SkASSERT(index <= 0xFFFF); |
162 *dstC++ = cache[toggle + | 175 *dstC++ = cache[toggle + |
(...skipping 24 matching lines...) Expand all Loading... | |
187 this->init(); | 200 this->init(); |
188 } | 201 } |
189 | 202 |
190 bool SkTwoPointConicalGradient::isOpaque() const { | 203 bool SkTwoPointConicalGradient::isOpaque() const { |
191 // Because areas outside the cone are left untouched, we cannot treat the | 204 // Because areas outside the cone are left untouched, we cannot treat the |
192 // shader as opaque even if the gradient itself is opaque. | 205 // shader as opaque even if the gradient itself is opaque. |
193 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 | 206 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 |
194 return false; | 207 return false; |
195 } | 208 } |
196 | 209 |
197 void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, | 210 size_t SkTwoPointConicalGradient::contextSize() const { |
198 int count) { | 211 return sizeof(TwoPointConicalGradientContext); |
212 } | |
213 | |
214 SkShader::Context* SkTwoPointConicalGradient::createContext(const SkBitmap& devi ce, const SkPaint& paint, | |
scroggo
2014/04/03 15:35:54
nit: 100 chars.
Dominik Grewe
2014/04/04 10:59:41
Done.
| |
215 const SkMatrix& matrix, void* storage) const { | |
216 if (!this->validContext(device, paint, matrix)) { | |
217 return NULL; | |
218 } | |
219 | |
220 return SkNEW_PLACEMENT_ARGS(storage, TwoPointConicalGradientContext, (*this, device, paint, matrix)); | |
scroggo
2014/04/03 15:35:54
100 chars.
Dominik Grewe
2014/04/04 10:59:41
Done.
| |
221 } | |
222 | |
223 SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradie ntContext( | |
224 const SkTwoPointConicalGradient& shader, const SkBitmap& device, | |
225 const SkPaint& paint, const SkMatrix& matrix) | |
226 : INHERITED(shader, device, paint, matrix) | |
227 { | |
228 // we don't have a span16 proc | |
229 fFlags &= ~kHasSpan16_Flag; | |
230 | |
231 // in general, we might discard based on computed-radius, so clear | |
232 // this flag (todo: sometimes we can detect that we never discard...) | |
233 fFlags &= ~kOpaqueAlpha_Flag; | |
234 } | |
235 | |
236 void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan( | |
237 int x, int y, SkPMColor* dstCParam, int count) { | |
238 const SkTwoPointConicalGradient& twoPointConicalGradient = | |
239 static_cast<const SkTwoPointConicalGradient&>(fShader); | |
240 | |
199 int toggle = init_dither_toggle(x, y); | 241 int toggle = init_dither_toggle(x, y); |
200 | 242 |
201 SkASSERT(count > 0); | 243 SkASSERT(count > 0); |
202 | 244 |
203 SkPMColor* SK_RESTRICT dstC = dstCParam; | 245 SkPMColor* SK_RESTRICT dstC = dstCParam; |
204 | 246 |
205 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 247 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
206 | 248 |
207 const SkPMColor* SK_RESTRICT cache = this->getCache32(); | 249 const SkPMColor* SK_RESTRICT cache = fCache.getCache32(twoPointConicalGradie nt); |
208 | 250 |
209 TwoPointConicalProc shadeProc = twopoint_repeat; | 251 TwoPointConicalProc shadeProc = twopoint_repeat; |
210 if (SkShader::kClamp_TileMode == fTileMode) { | 252 if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) { |
211 shadeProc = twopoint_clamp; | 253 shadeProc = twopoint_clamp; |
212 } else if (SkShader::kMirror_TileMode == fTileMode) { | 254 } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) { |
213 shadeProc = twopoint_mirror; | 255 shadeProc = twopoint_mirror; |
214 } else { | 256 } else { |
215 SkASSERT(SkShader::kRepeat_TileMode == fTileMode); | 257 SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode ); |
216 } | 258 } |
217 | 259 |
218 if (fDstToIndexClass != kPerspective_MatrixClass) { | 260 if (fDstToIndexClass != kPerspective_MatrixClass) { |
219 SkPoint srcPt; | 261 SkPoint srcPt; |
220 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 262 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
221 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 263 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
222 SkScalar dx, fx = srcPt.fX; | 264 SkScalar dx, fx = srcPt.fX; |
223 SkScalar dy, fy = srcPt.fY; | 265 SkScalar dy, fy = srcPt.fY; |
224 | 266 |
225 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 267 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
226 SkFixed fixedX, fixedY; | 268 SkFixed fixedX, fixedY; |
227 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); | 269 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); |
228 dx = SkFixedToScalar(fixedX); | 270 dx = SkFixedToScalar(fixedX); |
229 dy = SkFixedToScalar(fixedY); | 271 dy = SkFixedToScalar(fixedY); |
230 } else { | 272 } else { |
231 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 273 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
232 dx = fDstToIndex.getScaleX(); | 274 dx = fDstToIndex.getScaleX(); |
233 dy = fDstToIndex.getSkewY(); | 275 dy = fDstToIndex.getSkewY(); |
234 } | 276 } |
235 | 277 |
236 fRec.setup(fx, fy, dx, dy); | 278 TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy); |
237 (*shadeProc)(&fRec, dstC, cache, toggle, count); | 279 (*shadeProc)(&rec, dstC, cache, toggle, count); |
238 } else { // perspective case | 280 } else { // perspective case |
239 SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; | 281 SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; |
240 SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; | 282 SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; |
241 for (; count > 0; --count) { | 283 for (; count > 0; --count) { |
242 SkPoint srcPt; | 284 SkPoint srcPt; |
243 dstProc(fDstToIndex, dstX, dstY, &srcPt); | 285 dstProc(fDstToIndex, dstX, dstY, &srcPt); |
244 fRec.setup(srcPt.fX, srcPt.fY, 0, 0); | 286 TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt .fY, 0, 0); |
245 (*shadeProc)(&fRec, dstC, cache, toggle, 1); | 287 (*shadeProc)(&rec, dstC, cache, toggle, 1); |
246 | 288 |
247 dstX += SK_Scalar1; | 289 dstX += SK_Scalar1; |
248 toggle = next_dither_toggle(toggle); | 290 toggle = next_dither_toggle(toggle); |
249 dstC += 1; | 291 dstC += 1; |
250 } | 292 } |
251 } | 293 } |
252 } | 294 } |
253 | 295 |
254 bool SkTwoPointConicalGradient::setContext(const SkBitmap& device, | |
255 const SkPaint& paint, | |
256 const SkMatrix& matrix) { | |
257 if (!this->INHERITED::setContext(device, paint, matrix)) { | |
258 return false; | |
259 } | |
260 | |
261 // we don't have a span16 proc | |
262 fFlags &= ~kHasSpan16_Flag; | |
263 | |
264 // in general, we might discard based on computed-radius, so clear | |
265 // this flag (todo: sometimes we can detect that we never discard...) | |
266 fFlags &= ~kOpaqueAlpha_Flag; | |
267 | |
268 return true; | |
269 } | |
270 | |
271 SkShader::BitmapType SkTwoPointConicalGradient::asABitmap( | 296 SkShader::BitmapType SkTwoPointConicalGradient::asABitmap( |
272 SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { | 297 SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { |
273 SkPoint diff = fCenter2 - fCenter1; | 298 SkPoint diff = fCenter2 - fCenter1; |
274 SkScalar diffLen = 0; | 299 SkScalar diffLen = 0; |
275 | 300 |
276 if (bitmap) { | 301 if (bitmap) { |
277 this->getGradientTableBitmap(bitmap); | 302 this->getGradientTableBitmap(bitmap); |
278 } | 303 } |
279 if (matrix) { | 304 if (matrix) { |
280 diffLen = diff.length(); | 305 diffLen = diff.length(); |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
728 str->appendScalar(fCenter2.fY); | 753 str->appendScalar(fCenter2.fY); |
729 str->append(") radius2: "); | 754 str->append(") radius2: "); |
730 str->appendScalar(fRadius2); | 755 str->appendScalar(fRadius2); |
731 str->append(" "); | 756 str->append(" "); |
732 | 757 |
733 this->INHERITED::toString(str); | 758 this->INHERITED::toString(str); |
734 | 759 |
735 str->append(")"); | 760 str->append(")"); |
736 } | 761 } |
737 #endif | 762 #endif |
OLD | NEW |