| OLD | NEW | 
|---|
| 1 |  | 
| 2 /* | 1 /* | 
| 3  * Copyright 2006 The Android Open Source Project | 2  * Copyright 2006 The Android Open Source Project | 
| 4  * | 3  * | 
| 5  * 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 | 
| 6  * found in the LICENSE file. | 5  * found in the LICENSE file. | 
| 7  */ | 6  */ | 
| 8 | 7 | 
| 9 |  | 
| 10 #include "SkScan.h" | 8 #include "SkScan.h" | 
| 11 #include "SkBlitter.h" | 9 #include "SkBlitter.h" | 
| 12 #include "SkRasterClip.h" | 10 #include "SkRasterClip.h" | 
| 13 #include "SkFDot6.h" | 11 #include "SkFDot6.h" | 
| 14 #include "SkLineClipper.h" | 12 #include "SkLineClipper.h" | 
| 15 | 13 | 
| 16 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, | 14 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, | 
| 17                      SkBlitter* blitter) { | 15                      SkBlitter* blitter) { | 
| 18     SkASSERT(x < stopx); | 16     SkASSERT(x < stopx); | 
| 19 | 17 | 
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 185     blitter->blitH(r.fLeft, r.fTop, width);                     // top | 183     blitter->blitH(r.fLeft, r.fTop, width);                     // top | 
| 186     blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2);      // left | 184     blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2);      // left | 
| 187     blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right | 185     blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right | 
| 188     blitter->blitH(r.fLeft, r.fBottom - 1, width);              // bottom | 186     blitter->blitH(r.fLeft, r.fBottom - 1, width);              // bottom | 
| 189 } | 187 } | 
| 190 | 188 | 
| 191 /////////////////////////////////////////////////////////////////////////////// | 189 /////////////////////////////////////////////////////////////////////////////// | 
| 192 | 190 | 
| 193 #include "SkPath.h" | 191 #include "SkPath.h" | 
| 194 #include "SkGeometry.h" | 192 #include "SkGeometry.h" | 
|  | 193 #include "SkNx.h" | 
|  | 194 | 
|  | 195 #define kMaxCubicSubdivideLevel 6 | 
|  | 196 #define kMaxQuadSubdivideLevel  5 | 
| 195 | 197 | 
| 196 static int compute_int_quad_dist(const SkPoint pts[3]) { | 198 static int compute_int_quad_dist(const SkPoint pts[3]) { | 
| 197     // compute the vector between the control point ([1]) and the middle of the | 199     // compute the vector between the control point ([1]) and the middle of the | 
| 198     // line connecting the start and end ([0] and [2]) | 200     // line connecting the start and end ([0] and [2]) | 
| 199     SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; | 201     SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; | 
| 200     SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; | 202     SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; | 
| 201     // we want everyone to be positive | 203     // we want everyone to be positive | 
| 202     dx = SkScalarAbs(dx); | 204     dx = SkScalarAbs(dx); | 
| 203     dy = SkScalarAbs(dy); | 205     dy = SkScalarAbs(dy); | 
| 204     // convert to whole pixel values (use ceiling to be conservative) | 206     // convert to whole pixel values (use ceiling to be conservative) | 
| 205     int idx = SkScalarCeilToInt(dx); | 207     int idx = SkScalarCeilToInt(dx); | 
| 206     int idy = SkScalarCeilToInt(dy); | 208     int idy = SkScalarCeilToInt(dy); | 
| 207     // use the cheap approx for distance | 209     // use the cheap approx for distance | 
| 208     if (idx > idy) { | 210     if (idx > idy) { | 
| 209         return idx + (idy >> 1); | 211         return idx + (idy >> 1); | 
| 210     } else { | 212     } else { | 
| 211         return idy + (idx >> 1); | 213         return idy + (idx >> 1); | 
| 212     } | 214     } | 
| 213 } | 215 } | 
| 214 | 216 | 
| 215 static void hairquad(const SkPoint pts[3], const SkRegion* clip, | 217 static void hairquad(const SkPoint pts[3], const SkRegion* clip, | 
| 216                      SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
     ) { | 218                      SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
     ) { | 
|  | 219     SkASSERT(level <= kMaxQuadSubdivideLevel); | 
|  | 220 | 
|  | 221 #ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 | 
| 217     if (level > 0) { | 222     if (level > 0) { | 
| 218         SkPoint tmp[5]; | 223         SkPoint tmp[5]; | 
| 219 | 224 | 
| 220         SkChopQuadAtHalf(pts, tmp); | 225         SkChopQuadAtHalf(pts, tmp); | 
| 221         hairquad(tmp, clip, blitter, level - 1, lineproc); | 226         hairquad(tmp, clip, blitter, level - 1, lineproc); | 
| 222         hairquad(&tmp[2], clip, blitter, level - 1, lineproc); | 227         hairquad(&tmp[2], clip, blitter, level - 1, lineproc); | 
| 223     } else { | 228     } else { | 
| 224         SkPoint tmp[] = { pts[0], pts[2] }; | 229         SkPoint tmp[] = { pts[0], pts[2] }; | 
| 225         lineproc(tmp, 2, clip, blitter); | 230         lineproc(tmp, 2, clip, blitter); | 
| 226     } | 231     } | 
|  | 232 #else | 
|  | 233     SkPoint coeff[3]; | 
|  | 234     SkQuadToCoeff(pts, coeff); | 
|  | 235 | 
|  | 236     const int lines = 1 << level; | 
|  | 237     Sk2s t(0); | 
|  | 238     Sk2s dt(SK_Scalar1 / lines); | 
|  | 239 | 
|  | 240     SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; | 
|  | 241     SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); | 
|  | 242 | 
|  | 243     tmp[0] = pts[0]; | 
|  | 244     Sk2s A = Sk2s::Load(&coeff[0].fX); | 
|  | 245     Sk2s B = Sk2s::Load(&coeff[1].fX); | 
|  | 246     Sk2s C = Sk2s::Load(&coeff[2].fX); | 
|  | 247     for (int i = 1; i < lines; ++i) { | 
|  | 248         t += dt; | 
|  | 249         ((A * t + B) * t + C).store(&tmp[i].fX); | 
|  | 250     } | 
|  | 251     tmp[lines] = pts[2]; | 
|  | 252     lineproc(tmp, lines + 1, clip, blitter); | 
|  | 253 #endif | 
| 227 } | 254 } | 
| 228 | 255 | 
| 229 static void haircubic(const SkPoint pts[4], const SkRegion* clip, | 256 #ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2 | 
|  | 257 static inline Sk2s abs(const Sk2s& value) { | 
|  | 258     return Sk2s::Max(value, -value); | 
|  | 259 } | 
|  | 260 | 
|  | 261 static inline SkScalar max_component(const Sk2s& value) { | 
|  | 262     SkScalar components[2]; | 
|  | 263     value.store(components); | 
|  | 264     return SkTMax(components[0], components[1]); | 
|  | 265 } | 
|  | 266 | 
|  | 267 static inline int compute_cubic_segs(const SkPoint pts[4]) { | 
|  | 268     Sk2s p0 = from_point(pts[0]); | 
|  | 269     Sk2s p1 = from_point(pts[1]); | 
|  | 270     Sk2s p2 = from_point(pts[2]); | 
|  | 271     Sk2s p3 = from_point(pts[3]); | 
|  | 272 | 
|  | 273     const Sk2s oneThird(1.0f / 3.0f); | 
|  | 274     const Sk2s twoThird(2.0f / 3.0f); | 
|  | 275 | 
|  | 276     Sk2s p13 = oneThird * p3 + twoThird * p0; | 
|  | 277     Sk2s p23 = oneThird * p0 + twoThird * p3; | 
|  | 278 | 
|  | 279     SkScalar diff = max_component(Sk2s::Max(abs(p1 - p13), abs(p2 - p23))); | 
|  | 280     SkScalar tol = SK_Scalar1 / 8; | 
|  | 281 | 
|  | 282     for (int i = 0; i < kMaxCubicSubdivideLevel; ++i) { | 
|  | 283         if (diff < tol) { | 
|  | 284             return 1 << i; | 
|  | 285         } | 
|  | 286         tol *= 4; | 
|  | 287     } | 
|  | 288     return 1 << kMaxCubicSubdivideLevel; | 
|  | 289 } | 
|  | 290 | 
|  | 291 static bool lt_90(SkPoint p0, SkPoint pivot, SkPoint p2) { | 
|  | 292     return SkVector::DotProduct(p0 - pivot, p2 - pivot) >= 0; | 
|  | 293 } | 
|  | 294 | 
|  | 295 // The off-curve points are "inside" the limits of the on-curve pts | 
|  | 296 static bool quick_cubic_niceness_check(const SkPoint pts[4]) { | 
|  | 297     return lt_90(pts[1], pts[0], pts[3]) && | 
|  | 298            lt_90(pts[2], pts[0], pts[3]) && | 
|  | 299            lt_90(pts[1], pts[3], pts[0]) && | 
|  | 300            lt_90(pts[2], pts[3], pts[0]); | 
|  | 301 } | 
|  | 302 | 
|  | 303 static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bl
     itter, | 
|  | 304                        SkScan::HairRgnProc lineproc) { | 
|  | 305     const int lines = compute_cubic_segs(pts); | 
|  | 306     SkASSERT(lines > 0); | 
|  | 307     if (1 == lines) { | 
|  | 308         SkPoint tmp[2] = { pts[0], pts[3] }; | 
|  | 309         lineproc(tmp, 2, clip, blitter); | 
|  | 310         return; | 
|  | 311     } | 
|  | 312 | 
|  | 313     SkPoint coeff[4]; | 
|  | 314     SkCubicToCoeff(pts, coeff); | 
|  | 315 | 
|  | 316     const Sk2s dt(SK_Scalar1 / lines); | 
|  | 317     Sk2s t(0); | 
|  | 318 | 
|  | 319     SkPoint tmp[(1 << kMaxCubicSubdivideLevel) + 1]; | 
|  | 320     SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); | 
|  | 321 | 
|  | 322     tmp[0] = pts[0]; | 
|  | 323     Sk2s A = Sk2s::Load(&coeff[0].fX); | 
|  | 324     Sk2s B = Sk2s::Load(&coeff[1].fX); | 
|  | 325     Sk2s C = Sk2s::Load(&coeff[2].fX); | 
|  | 326     Sk2s D = Sk2s::Load(&coeff[3].fX); | 
|  | 327     for (int i = 1; i < lines; ++i) { | 
|  | 328         t += dt; | 
|  | 329         (((A * t + B) * t + C) * t + D).store(&tmp[i].fX); | 
|  | 330     } | 
|  | 331     tmp[lines] = pts[3]; | 
|  | 332     lineproc(tmp, lines + 1, clip, blitter); | 
|  | 333 } | 
|  | 334 #endif | 
|  | 335 | 
|  | 336 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, | 
| 230                       SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
     c) { | 337                       SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
     c) { | 
|  | 338 #ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 | 
| 231     if (level > 0) { | 339     if (level > 0) { | 
| 232         SkPoint tmp[7]; | 340         SkPoint tmp[7]; | 
| 233 | 341 | 
| 234         SkChopCubicAt(pts, tmp, SK_Scalar1/2); | 342         SkChopCubicAt(pts, tmp, SK_Scalar1/2); | 
| 235         haircubic(tmp, clip, blitter, level - 1, lineproc); | 343         haircubic(tmp, clip, blitter, level - 1, lineproc); | 
| 236         haircubic(&tmp[3], clip, blitter, level - 1, lineproc); | 344         haircubic(&tmp[3], clip, blitter, level - 1, lineproc); | 
| 237     } else { | 345     } else { | 
| 238         SkPoint tmp[] = { pts[0], pts[3] }; | 346         SkPoint tmp[] = { pts[0], pts[3] }; | 
| 239         lineproc(tmp, 2, clip, blitter); | 347         lineproc(tmp, 2, clip, blitter); | 
| 240     } | 348     } | 
|  | 349 #else | 
|  | 350     if (quick_cubic_niceness_check(pts)) { | 
|  | 351         hair_cubic(pts, clip, blitter, lineproc); | 
|  | 352     } else { | 
|  | 353         SkPoint  tmp[13]; | 
|  | 354         SkScalar tValues[3]; | 
|  | 355 | 
|  | 356         int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); | 
|  | 357         for (int i = 0; i < count; i++) { | 
|  | 358             hair_cubic(&tmp[i * 3], clip, blitter, lineproc); | 
|  | 359         } | 
|  | 360     } | 
|  | 361 #endif | 
| 241 } | 362 } | 
| 242 | 363 | 
| 243 #define kMaxCubicSubdivideLevel 6 |  | 
| 244 #define kMaxQuadSubdivideLevel  5 |  | 
| 245 |  | 
| 246 static int compute_quad_level(const SkPoint pts[3]) { | 364 static int compute_quad_level(const SkPoint pts[3]) { | 
| 247     int d = compute_int_quad_dist(pts); | 365     int d = compute_int_quad_dist(pts); | 
| 248     /*  quadratics approach the line connecting their start and end points | 366     /*  quadratics approach the line connecting their start and end points | 
| 249      4x closer with each subdivision, so we compute the number of | 367      4x closer with each subdivision, so we compute the number of | 
| 250      subdivisions to be the minimum need to get that distance to be less | 368      subdivisions to be the minimum need to get that distance to be less | 
| 251      than a pixel. | 369      than a pixel. | 
| 252      */ | 370      */ | 
| 253     int level = (33 - SkCLZ(d)) >> 1; | 371     int level = (33 - SkCLZ(d)) >> 1; | 
| 254     // sanity check on level (from the previous version) | 372     // sanity check on level (from the previous version) | 
| 255     if (level > kMaxQuadSubdivideLevel) { | 373     if (level > kMaxQuadSubdivideLevel) { | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 304                 const SkScalar tol = SK_Scalar1 / 4; | 422                 const SkScalar tol = SK_Scalar1 / 4; | 
| 305                 const SkPoint* quadPts = converter.computeQuads(pts, | 423                 const SkPoint* quadPts = converter.computeQuads(pts, | 
| 306                                                        iter.conicWeight(), tol); | 424                                                        iter.conicWeight(), tol); | 
| 307                 for (int i = 0; i < converter.countQuads(); ++i) { | 425                 for (int i = 0; i < converter.countQuads(); ++i) { | 
| 308                     int level = compute_quad_level(quadPts); | 426                     int level = compute_quad_level(quadPts); | 
| 309                     hairquad(quadPts, clip, blitter, level, lineproc); | 427                     hairquad(quadPts, clip, blitter, level, lineproc); | 
| 310                     quadPts += 2; | 428                     quadPts += 2; | 
| 311                 } | 429                 } | 
| 312                 break; | 430                 break; | 
| 313             } | 431             } | 
| 314             case SkPath::kCubic_Verb: | 432             case SkPath::kCubic_Verb: { | 
| 315                 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
     ; | 433                 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
     ; | 
| 316                 break; | 434             } break; | 
| 317             case SkPath::kClose_Verb: | 435             case SkPath::kClose_Verb: | 
| 318                 break; | 436                 break; | 
| 319             case SkPath::kDone_Verb: | 437             case SkPath::kDone_Verb: | 
| 320                 break; | 438                 break; | 
| 321         } | 439         } | 
| 322     } | 440     } | 
| 323 } | 441 } | 
| 324 | 442 | 
| 325 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
     litter) { | 443 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
     litter) { | 
| 326     hair_path(path, clip, blitter, SkScan::HairLineRgn); | 444     hair_path(path, clip, blitter, SkScan::HairLineRgn); | 
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 400 | 518 | 
| 401         SkAAClipBlitterWrapper wrap; | 519         SkAAClipBlitterWrapper wrap; | 
| 402         if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 520         if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 
| 403             wrap.init(clip, blitter); | 521             wrap.init(clip, blitter); | 
| 404             blitter = wrap.getBlitter(); | 522             blitter = wrap.getBlitter(); | 
| 405             clipRgn = &wrap.getRgn(); | 523             clipRgn = &wrap.getRgn(); | 
| 406         } | 524         } | 
| 407         AntiHairLineRgn(pts, count, clipRgn, blitter); | 525         AntiHairLineRgn(pts, count, clipRgn, blitter); | 
| 408     } | 526     } | 
| 409 } | 527 } | 
| OLD | NEW | 
|---|