OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2009 The Android Open Source Project | 3 * Copyright 2009 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkEdgeClipper.h" | 10 #include "SkEdgeClipper.h" |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 } | 218 } |
219 | 219 |
220 *fCurrVerb = SkPath::kDone_Verb; | 220 *fCurrVerb = SkPath::kDone_Verb; |
221 fCurrPoint = fPoints; | 221 fCurrPoint = fPoints; |
222 fCurrVerb = fVerbs; | 222 fCurrVerb = fVerbs; |
223 return SkPath::kDone_Verb != fVerbs[0]; | 223 return SkPath::kDone_Verb != fVerbs[0]; |
224 } | 224 } |
225 | 225 |
226 /////////////////////////////////////////////////////////////////////////////// | 226 /////////////////////////////////////////////////////////////////////////////// |
227 | 227 |
228 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
229 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, | |
230 SkScalar D, SkScalar t) { | |
231 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); | |
232 } | |
233 | |
234 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the | |
235 t value such that cubic(t) = target | |
236 */ | |
237 static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, | |
238 SkScalar target, SkScalar* t) { | |
239 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3); | |
240 SkASSERT(c0 < target && target < c3); | |
241 | |
242 SkScalar D = c0 - target; | |
243 SkScalar A = c3 + 3*(c1 - c2) - c0; | |
244 SkScalar B = 3*(c2 - c1 - c1 + c0); | |
245 SkScalar C = 3*(c1 - c0); | |
246 | |
247 const SkScalar TOLERANCE = SK_Scalar1 / 4096; | |
248 SkScalar minT = 0; | |
249 SkScalar maxT = SK_Scalar1; | |
250 SkScalar mid; | |
251 | |
252 // This is a lot of iterations. Is there a faster way? | |
253 for (int i = 0; i < 24; i++) { | |
254 mid = SkScalarAve(minT, maxT); | |
255 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid); | |
256 if (delta < 0) { | |
257 minT = mid; | |
258 delta = -delta; | |
259 } else { | |
260 maxT = mid; | |
261 } | |
262 if (delta < TOLERANCE) { | |
263 break; | |
264 } | |
265 } | |
266 *t = mid; | |
267 // SkDebugf("-- evalCubicAt %d delta %g\n", i, eval_cubic_coeff(A, B, C, D, *
t)); | |
268 return true; | |
269 } | |
270 | |
271 static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) { | |
272 return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t); | |
273 } | |
274 | |
275 static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) { | |
276 return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t); | |
277 } | |
278 #endif | |
279 | |
280 // Modify pts[] in place so that it is clipped in Y to the clip rect | 228 // Modify pts[] in place so that it is clipped in Y to the clip rect |
281 static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { | 229 static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { |
282 | 230 |
283 // are we partially above | 231 // are we partially above |
284 if (pts[0].fY < clip.fTop) { | 232 if (pts[0].fY < clip.fTop) { |
285 SkPoint tmp[7]; | 233 SkPoint tmp[7]; |
286 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
287 SkScalar t; | |
288 if (chopMonoCubicAtY(pts, clip.fTop, &t)) { | |
289 SkChopCubicAt(pts, tmp, t); | |
290 #else | |
291 if (SkChopMonoCubicAtY(pts, clip.fTop, tmp)) { | 234 if (SkChopMonoCubicAtY(pts, clip.fTop, tmp)) { |
292 #endif | |
293 // tmp[3, 4].fY should all be to the below clip.fTop. | 235 // tmp[3, 4].fY should all be to the below clip.fTop. |
294 // Since we can't trust the numerics of | 236 // Since we can't trust the numerics of |
295 // the chopper, we force those conditions now | 237 // the chopper, we force those conditions now |
296 tmp[3].fY = clip.fTop; | 238 tmp[3].fY = clip.fTop; |
297 clamp_ge(tmp[4].fY, clip.fTop); | 239 clamp_ge(tmp[4].fY, clip.fTop); |
298 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
299 clamp_ge(tmp[5].fY, clip.fTop); | |
300 #endif | |
301 | 240 |
302 pts[0] = tmp[3]; | 241 pts[0] = tmp[3]; |
303 pts[1] = tmp[4]; | 242 pts[1] = tmp[4]; |
304 pts[2] = tmp[5]; | 243 pts[2] = tmp[5]; |
305 } else { | 244 } else { |
306 // if chopMonoCubicAtY failed, then we may have hit inexact numerics | 245 // if chopMonoCubicAtY failed, then we may have hit inexact numerics |
307 // so we just clamp against the top | 246 // so we just clamp against the top |
308 for (int i = 0; i < 4; i++) { | 247 for (int i = 0; i < 4; i++) { |
309 clamp_ge(pts[i].fY, clip.fTop); | 248 clamp_ge(pts[i].fY, clip.fTop); |
310 } | 249 } |
311 } | 250 } |
312 } | 251 } |
313 | 252 |
314 // are we partially below | 253 // are we partially below |
315 if (pts[3].fY > clip.fBottom) { | 254 if (pts[3].fY > clip.fBottom) { |
316 SkPoint tmp[7]; | 255 SkPoint tmp[7]; |
317 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
318 SkScalar t; | |
319 if (chopMonoCubicAtY(pts, clip.fBottom, &t)) { | |
320 SkChopCubicAt(pts, tmp, t); | |
321 #else | |
322 if (SkChopMonoCubicAtY(pts, clip.fBottom, tmp)) { | 256 if (SkChopMonoCubicAtY(pts, clip.fBottom, tmp)) { |
323 #endif | |
324 tmp[3].fY = clip.fBottom; | 257 tmp[3].fY = clip.fBottom; |
325 clamp_le(tmp[2].fY, clip.fBottom); | 258 clamp_le(tmp[2].fY, clip.fBottom); |
326 | 259 |
327 pts[1] = tmp[1]; | 260 pts[1] = tmp[1]; |
328 pts[2] = tmp[2]; | 261 pts[2] = tmp[2]; |
329 pts[3] = tmp[3]; | 262 pts[3] = tmp[3]; |
330 } else { | 263 } else { |
331 // if chopMonoCubicAtY failed, then we may have hit inexact numerics | 264 // if chopMonoCubicAtY failed, then we may have hit inexact numerics |
332 // so we just clamp against the bottom | 265 // so we just clamp against the bottom |
333 for (int i = 0; i < 4; i++) { | 266 for (int i = 0; i < 4; i++) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 if (pts[0].fX >= clip.fRight) { // wholly to the right | 298 if (pts[0].fX >= clip.fRight) { // wholly to the right |
366 if (!this->canCullToTheRight()) { | 299 if (!this->canCullToTheRight()) { |
367 this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); | 300 this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); |
368 } | 301 } |
369 return; | 302 return; |
370 } | 303 } |
371 | 304 |
372 // are we partially to the left | 305 // are we partially to the left |
373 if (pts[0].fX < clip.fLeft) { | 306 if (pts[0].fX < clip.fLeft) { |
374 SkPoint tmp[7]; | 307 SkPoint tmp[7]; |
375 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
376 SkScalar t; | |
377 if (chopMonoCubicAtX(pts, clip.fLeft, &t)) { | |
378 SkChopCubicAt(pts, tmp, t); | |
379 #else | |
380 if (SkChopMonoCubicAtX(pts, clip.fLeft, tmp)) { | 308 if (SkChopMonoCubicAtX(pts, clip.fLeft, tmp)) { |
381 #endif | |
382 this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse); | 309 this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse); |
383 | 310 |
384 // tmp[3, 4].fX should all be to the right of clip.fLeft. | 311 // tmp[3, 4].fX should all be to the right of clip.fLeft. |
385 // Since we can't trust the numerics of | 312 // Since we can't trust the numerics of |
386 // the chopper, we force those conditions now | 313 // the chopper, we force those conditions now |
387 tmp[3].fX = clip.fLeft; | 314 tmp[3].fX = clip.fLeft; |
388 clamp_ge(tmp[4].fX, clip.fLeft); | 315 clamp_ge(tmp[4].fX, clip.fLeft); |
389 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
390 clamp_ge(tmp[5].fX, clip.fLeft); | |
391 #endif | |
392 | 316 |
393 pts[0] = tmp[3]; | 317 pts[0] = tmp[3]; |
394 pts[1] = tmp[4]; | 318 pts[1] = tmp[4]; |
395 pts[2] = tmp[5]; | 319 pts[2] = tmp[5]; |
396 } else { | 320 } else { |
397 // if chopMonocubicAtY failed, then we may have hit inexact numerics | 321 // if chopMonocubicAtY failed, then we may have hit inexact numerics |
398 // so we just clamp against the left | 322 // so we just clamp against the left |
399 this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse); | 323 this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse); |
400 return; | 324 return; |
401 } | 325 } |
402 } | 326 } |
403 | 327 |
404 // are we partially to the right | 328 // are we partially to the right |
405 if (pts[3].fX > clip.fRight) { | 329 if (pts[3].fX > clip.fRight) { |
406 SkPoint tmp[7]; | 330 SkPoint tmp[7]; |
407 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
408 SkScalar t; | |
409 if (chopMonoCubicAtX(pts, clip.fRight, &t)) { | |
410 SkChopCubicAt(pts, tmp, t); | |
411 #else | |
412 if (SkChopMonoCubicAtX(pts, clip.fRight, tmp)) { | 331 if (SkChopMonoCubicAtX(pts, clip.fRight, tmp)) { |
413 #endif | |
414 tmp[3].fX = clip.fRight; | 332 tmp[3].fX = clip.fRight; |
415 clamp_le(tmp[2].fX, clip.fRight); | 333 clamp_le(tmp[2].fX, clip.fRight); |
416 #ifdef SK_SUPPORT_LEGACY_CUBIC_CHOPPER | |
417 clamp_le(tmp[1].fX, clip.fRight); | |
418 #endif | |
419 | 334 |
420 this->appendCubic(tmp, reverse); | 335 this->appendCubic(tmp, reverse); |
421 this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse); | 336 this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse); |
422 } else { | 337 } else { |
423 // if chopMonoCubicAtX failed, then we may have hit inexact numerics | 338 // if chopMonoCubicAtX failed, then we may have hit inexact numerics |
424 // so we just clamp against the right | 339 // so we just clamp against the right |
425 this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); | 340 this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); |
426 } | 341 } |
427 } else { // wholly inside the clip | 342 } else { // wholly inside the clip |
428 this->appendCubic(pts, reverse); | 343 this->appendCubic(pts, reverse); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 assert_monotonic(&pts[0].fY, count); | 464 assert_monotonic(&pts[0].fY, count); |
550 } | 465 } |
551 } | 466 } |
552 | 467 |
553 void sk_assert_monotonic_x(const SkPoint pts[], int count) { | 468 void sk_assert_monotonic_x(const SkPoint pts[], int count) { |
554 if (count > 1) { | 469 if (count > 1) { |
555 assert_monotonic(&pts[0].fX, count); | 470 assert_monotonic(&pts[0].fX, count); |
556 } | 471 } |
557 } | 472 } |
558 #endif | 473 #endif |
OLD | NEW |