OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
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 "SkScan.h" | 8 #include "SkScan.h" |
9 #include "SkBlitter.h" | 9 #include "SkBlitter.h" |
10 #include "SkRasterClip.h" | 10 #include "SkRasterClip.h" |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 int idx = SkScalarCeilToInt(dx); | 207 int idx = SkScalarCeilToInt(dx); |
208 int idy = SkScalarCeilToInt(dy); | 208 int idy = SkScalarCeilToInt(dy); |
209 // use the cheap approx for distance | 209 // use the cheap approx for distance |
210 if (idx > idy) { | 210 if (idx > idy) { |
211 return idx + (idy >> 1); | 211 return idx + (idy >> 1); |
212 } else { | 212 } else { |
213 return idy + (idx >> 1); | 213 return idy + (idx >> 1); |
214 } | 214 } |
215 } | 215 } |
216 | 216 |
217 static void hairquad(const SkPoint pts[3], const SkRegion* clip, | 217 static void hair_quad(const SkPoint pts[3], const SkRegion* clip, |
218 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
) { | 218 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
) { |
219 SkASSERT(level <= kMaxQuadSubdivideLevel); | 219 SkASSERT(level <= kMaxQuadSubdivideLevel); |
220 | 220 |
221 SkQuadCoeff coeff(pts); | 221 SkQuadCoeff coeff(pts); |
222 | 222 |
223 const int lines = 1 << level; | 223 const int lines = 1 << level; |
224 Sk2s t(0); | 224 Sk2s t(0); |
225 Sk2s dt(SK_Scalar1 / lines); | 225 Sk2s dt(SK_Scalar1 / lines); |
226 | 226 |
227 SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; | 227 SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; |
228 SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); | 228 SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); |
229 | 229 |
230 tmp[0] = pts[0]; | 230 tmp[0] = pts[0]; |
231 Sk2s A = coeff.fA; | 231 Sk2s A = coeff.fA; |
232 Sk2s B = coeff.fB; | 232 Sk2s B = coeff.fB; |
233 Sk2s C = coeff.fC; | 233 Sk2s C = coeff.fC; |
234 for (int i = 1; i < lines; ++i) { | 234 for (int i = 1; i < lines; ++i) { |
235 t = t + dt; | 235 t = t + dt; |
236 ((A * t + B) * t + C).store(&tmp[i]); | 236 ((A * t + B) * t + C).store(&tmp[i]); |
237 } | 237 } |
238 tmp[lines] = pts[2]; | 238 tmp[lines] = pts[2]; |
239 lineproc(tmp, lines + 1, clip, blitter); | 239 lineproc(tmp, lines + 1, clip, blitter); |
240 } | 240 } |
241 | 241 |
| 242 static SkRect compute_nocheck_quad_bounds(const SkPoint pts[3]) { |
| 243 SkASSERT(SkScalarsAreFinite(&pts[0].fX, 6)); |
| 244 |
| 245 Sk2s min = Sk2s::Load(pts); |
| 246 Sk2s max = min; |
| 247 for (int i = 1; i < 3; ++i) { |
| 248 Sk2s pair = Sk2s::Load(pts+i); |
| 249 min = Sk2s::Min(min, pair); |
| 250 max = Sk2s::Max(max, pair); |
| 251 } |
| 252 return { min[0], min[1], max[0], max[1] }; |
| 253 } |
| 254 |
| 255 static bool is_inverted(const SkRect& r) { |
| 256 return r.fLeft > r.fRight || r.fTop > r.fBottom; |
| 257 } |
| 258 |
| 259 // Can't call SkRect::intersects, since it cares about empty, and we don't (sinc
e we tracking |
| 260 // something to be stroked, so empty can still draw something (e.g. horizontal l
ine) |
| 261 static bool geometric_overlap(const SkRect& a, const SkRect& b) { |
| 262 SkASSERT(!is_inverted(a) && !is_inverted(b)); |
| 263 return a.fLeft < b.fRight && b.fLeft < a.fRight && |
| 264 a.fTop < b.fBottom && b.fTop < a.fBottom; |
| 265 } |
| 266 |
| 267 // Can't call SkRect::contains, since it cares about empty, and we don't (since
we tracking |
| 268 // something to be stroked, so empty can still draw something (e.g. horizontal l
ine) |
| 269 static bool geometric_contains(const SkRect& outer, const SkRect& inner) { |
| 270 SkASSERT(!is_inverted(outer) && !is_inverted(inner)); |
| 271 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft && |
| 272 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop; |
| 273 } |
| 274 |
| 275 static inline void hairquad(const SkPoint pts[3], const SkRegion* clip, const Sk
Rect* insetClip, const SkRect* outsetClip, |
| 276 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) { |
| 277 if (insetClip) { |
| 278 SkASSERT(outsetClip); |
| 279 SkRect bounds = compute_nocheck_quad_bounds(pts); |
| 280 if (!geometric_overlap(*outsetClip, bounds)) { |
| 281 return; |
| 282 } else if (geometric_contains(*insetClip, bounds)) { |
| 283 clip = nullptr; |
| 284 } |
| 285 } |
| 286 |
| 287 hair_quad(pts, clip, blitter, level, lineproc); |
| 288 } |
| 289 |
242 static inline Sk2s abs(const Sk2s& value) { | 290 static inline Sk2s abs(const Sk2s& value) { |
243 return Sk2s::Max(value, Sk2s(0)-value); | 291 return Sk2s::Max(value, Sk2s(0)-value); |
244 } | 292 } |
245 | 293 |
246 static inline SkScalar max_component(const Sk2s& value) { | 294 static inline SkScalar max_component(const Sk2s& value) { |
247 SkScalar components[2]; | 295 SkScalar components[2]; |
248 value.store(components); | 296 value.store(components); |
249 return SkTMax(components[0], components[1]); | 297 return SkTMax(components[0], components[1]); |
250 } | 298 } |
251 | 299 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 Sk2s min = Sk2s::Load(pts); | 370 Sk2s min = Sk2s::Load(pts); |
323 Sk2s max = min; | 371 Sk2s max = min; |
324 for (int i = 1; i < 4; ++i) { | 372 for (int i = 1; i < 4; ++i) { |
325 Sk2s pair = Sk2s::Load(pts+i); | 373 Sk2s pair = Sk2s::Load(pts+i); |
326 min = Sk2s::Min(min, pair); | 374 min = Sk2s::Min(min, pair); |
327 max = Sk2s::Max(max, pair); | 375 max = Sk2s::Max(max, pair); |
328 } | 376 } |
329 return { min[0], min[1], max[0], max[1] }; | 377 return { min[0], min[1], max[0], max[1] }; |
330 } | 378 } |
331 | 379 |
332 static bool is_inverted(const SkRect& r) { | |
333 return r.fLeft > r.fRight || r.fTop > r.fBottom; | |
334 } | |
335 | |
336 // Can't call SkRect::intersects, since it cares about empty, and we don't (sinc
e we tracking | |
337 // something to be stroked, so empty can still draw something (e.g. horizontal l
ine) | |
338 static bool geometric_overlap(const SkRect& a, const SkRect& b) { | |
339 SkASSERT(!is_inverted(a) && !is_inverted(b)); | |
340 return a.fLeft < b.fRight && b.fLeft < a.fRight && | |
341 a.fTop < b.fBottom && b.fTop < a.fBottom; | |
342 } | |
343 | |
344 // Can't call SkRect::contains, since it cares about empty, and we don't (since
we tracking | |
345 // something to be stroked, so empty can still draw something (e.g. horizontal l
ine) | |
346 static bool geometric_contains(const SkRect& outer, const SkRect& inner) { | |
347 SkASSERT(!is_inverted(outer) && !is_inverted(inner)); | |
348 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft && | |
349 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop; | |
350 } | |
351 | |
352 //#define SK_SHOW_HAIRCLIP_STATS | |
353 #ifdef SK_SHOW_HAIRCLIP_STATS | |
354 static int gKillClip, gRejectClip, gClipCount; | |
355 #endif | |
356 | |
357 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const S
kRect* insetClip, const SkRect* outsetClip, | 380 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const S
kRect* insetClip, const SkRect* outsetClip, |
358 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { | 381 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { |
359 if (insetClip) { | 382 if (insetClip) { |
360 SkASSERT(outsetClip); | 383 SkASSERT(outsetClip); |
361 #ifdef SK_SHOW_HAIRCLIP_STATS | |
362 gClipCount += 1; | |
363 #endif | |
364 SkRect bounds = compute_nocheck_cubic_bounds(pts); | 384 SkRect bounds = compute_nocheck_cubic_bounds(pts); |
365 if (!geometric_overlap(*outsetClip, bounds)) { | 385 if (!geometric_overlap(*outsetClip, bounds)) { |
366 #ifdef SK_SHOW_HAIRCLIP_STATS | |
367 gRejectClip += 1; | |
368 #endif | |
369 return; | 386 return; |
370 } else if (geometric_contains(*insetClip, bounds)) { | 387 } else if (geometric_contains(*insetClip, bounds)) { |
371 clip = nullptr; | 388 clip = nullptr; |
372 #ifdef SK_SHOW_HAIRCLIP_STATS | |
373 gKillClip += 1; | |
374 #endif | |
375 } | 389 } |
376 #ifdef SK_SHOW_HAIRCLIP_STATS | |
377 if (0 == gClipCount % 256) | |
378 SkDebugf("kill %g reject %g total %d\n", 1.0*gKillClip / gClipCount,
1.0*gRejectClip/gClipCount, gClipCount); | |
379 #endif | |
380 } | 390 } |
381 | 391 |
382 if (quick_cubic_niceness_check(pts)) { | 392 if (quick_cubic_niceness_check(pts)) { |
383 hair_cubic(pts, clip, blitter, lineproc); | 393 hair_cubic(pts, clip, blitter, lineproc); |
384 } else { | 394 } else { |
385 SkPoint tmp[13]; | 395 SkPoint tmp[13]; |
386 SkScalar tValues[3]; | 396 SkScalar tValues[3]; |
387 | 397 |
388 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); | 398 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); |
389 for (int i = 0; i < count; i++) { | 399 for (int i = 0; i < count; i++) { |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 insetStorage.inset(1, 1); | 515 insetStorage.inset(1, 1); |
506 if (is_inverted(insetStorage)) { | 516 if (is_inverted(insetStorage)) { |
507 /* | 517 /* |
508 * our bounds checks assume the rects are never inverted. If in
setting has | 518 * our bounds checks assume the rects are never inverted. If in
setting has |
509 * created that, we assume that the area is too small to safely
perform a | 519 * created that, we assume that the area is too small to safely
perform a |
510 * quick-accept, so we just mark the rect as empty (so the quic
k-accept check | 520 * quick-accept, so we just mark the rect as empty (so the quic
k-accept check |
511 * will always fail. | 521 * will always fail. |
512 */ | 522 */ |
513 insetStorage.setEmpty(); // just so we don't pass an inverted
rect | 523 insetStorage.setEmpty(); // just so we don't pass an inverted
rect |
514 } | 524 } |
515 insetClip = &insetStorage; | 525 if (rclip.isRect()) { |
| 526 insetClip = &insetStorage; |
| 527 } |
516 outsetClip = &outsetStorage; | 528 outsetClip = &outsetStorage; |
517 } | 529 } |
518 } | 530 } |
519 | 531 |
520 SkPath::RawIter iter(path); | 532 SkPath::RawIter iter(path); |
521 SkPoint pts[4], firstPt, lastPt; | 533 SkPoint pts[4], firstPt, lastPt; |
522 SkPath::Verb verb, prevVerb; | 534 SkPath::Verb verb, prevVerb; |
523 SkAutoConicToQuads converter; | 535 SkAutoConicToQuads converter; |
524 | 536 |
525 if (SkPaint::kButt_Cap != capStyle) { | 537 if (SkPaint::kButt_Cap != capStyle) { |
526 prevVerb = SkPath::kDone_Verb; | 538 prevVerb = SkPath::kDone_Verb; |
527 } | 539 } |
528 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 540 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
529 switch (verb) { | 541 switch (verb) { |
530 case SkPath::kMove_Verb: | 542 case SkPath::kMove_Verb: |
531 firstPt = lastPt = pts[0]; | 543 firstPt = lastPt = pts[0]; |
532 break; | 544 break; |
533 case SkPath::kLine_Verb: | 545 case SkPath::kLine_Verb: |
534 if (SkPaint::kButt_Cap != capStyle) { | 546 if (SkPaint::kButt_Cap != capStyle) { |
535 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2); | 547 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2); |
536 } | 548 } |
537 lineproc(pts, 2, clip, blitter); | 549 lineproc(pts, 2, clip, blitter); |
538 lastPt = pts[1]; | 550 lastPt = pts[1]; |
539 break; | 551 break; |
540 case SkPath::kQuad_Verb: | 552 case SkPath::kQuad_Verb: |
541 if (SkPaint::kButt_Cap != capStyle) { | 553 if (SkPaint::kButt_Cap != capStyle) { |
542 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); | 554 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); |
543 } | 555 } |
544 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); | 556 hairquad(pts, clip, insetClip, outsetClip, blitter, compute_quad
_level(pts), lineproc); |
545 lastPt = pts[2]; | 557 lastPt = pts[2]; |
546 break; | 558 break; |
547 case SkPath::kConic_Verb: { | 559 case SkPath::kConic_Verb: { |
548 if (SkPaint::kButt_Cap != capStyle) { | 560 if (SkPaint::kButt_Cap != capStyle) { |
549 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); | 561 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); |
550 } | 562 } |
551 // how close should the quads be to the original conic? | 563 // how close should the quads be to the original conic? |
552 const SkScalar tol = SK_Scalar1 / 4; | 564 const SkScalar tol = SK_Scalar1 / 4; |
553 const SkPoint* quadPts = converter.computeQuads(pts, | 565 const SkPoint* quadPts = converter.computeQuads(pts, |
554 iter.conicWeight(), tol); | 566 iter.conicWeight(), tol); |
555 for (int i = 0; i < converter.countQuads(); ++i) { | 567 for (int i = 0; i < converter.countQuads(); ++i) { |
556 int level = compute_quad_level(quadPts); | 568 int level = compute_quad_level(quadPts); |
557 hairquad(quadPts, clip, blitter, level, lineproc); | 569 hairquad(quadPts, clip, insetClip, outsetClip, blitter, leve
l, lineproc); |
558 quadPts += 2; | 570 quadPts += 2; |
559 } | 571 } |
560 lastPt = pts[2]; | 572 lastPt = pts[2]; |
561 break; | 573 break; |
562 } | 574 } |
563 case SkPath::kCubic_Verb: { | 575 case SkPath::kCubic_Verb: { |
564 if (SkPaint::kButt_Cap != capStyle) { | 576 if (SkPaint::kButt_Cap != capStyle) { |
565 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4); | 577 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4); |
566 } | 578 } |
567 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSu
bdivideLevel, lineproc); | 579 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSu
bdivideLevel, lineproc); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 | 691 |
680 SkAAClipBlitterWrapper wrap; | 692 SkAAClipBlitterWrapper wrap; |
681 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 693 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { |
682 wrap.init(clip, blitter); | 694 wrap.init(clip, blitter); |
683 blitter = wrap.getBlitter(); | 695 blitter = wrap.getBlitter(); |
684 clipRgn = &wrap.getRgn(); | 696 clipRgn = &wrap.getRgn(); |
685 } | 697 } |
686 AntiHairLineRgn(pts, count, clipRgn, blitter); | 698 AntiHairLineRgn(pts, count, clipRgn, blitter); |
687 } | 699 } |
688 } | 700 } |
OLD | NEW |