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 |
| 14 //#define SK_SUPPORT_LEGACY_HAIRCUBIC |
| 15 |
16 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, | 16 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, |
17 SkBlitter* blitter) { | 17 SkBlitter* blitter) { |
18 SkASSERT(x < stopx); | 18 SkASSERT(x < stopx); |
19 | 19 |
20 do { | 20 do { |
21 blitter->blitH(x, fy >> 16, 1); | 21 blitter->blitH(x, fy >> 16, 1); |
22 fy += dy; | 22 fy += dy; |
23 } while (++x < stopx); | 23 } while (++x < stopx); |
24 } | 24 } |
25 | 25 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left | 186 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left |
187 blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right | 187 blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right |
188 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom | 188 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom |
189 } | 189 } |
190 | 190 |
191 /////////////////////////////////////////////////////////////////////////////// | 191 /////////////////////////////////////////////////////////////////////////////// |
192 | 192 |
193 #include "SkPath.h" | 193 #include "SkPath.h" |
194 #include "SkGeometry.h" | 194 #include "SkGeometry.h" |
195 | 195 |
| 196 #define kMaxCubicSubdivideLevel 6 |
| 197 #define kMaxQuadSubdivideLevel 5 |
| 198 |
196 static int compute_int_quad_dist(const SkPoint pts[3]) { | 199 static int compute_int_quad_dist(const SkPoint pts[3]) { |
197 // compute the vector between the control point ([1]) and the middle of the | 200 // compute the vector between the control point ([1]) and the middle of the |
198 // line connecting the start and end ([0] and [2]) | 201 // line connecting the start and end ([0] and [2]) |
199 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; | 202 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; | 203 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; |
201 // we want everyone to be positive | 204 // we want everyone to be positive |
202 dx = SkScalarAbs(dx); | 205 dx = SkScalarAbs(dx); |
203 dy = SkScalarAbs(dy); | 206 dy = SkScalarAbs(dy); |
204 // convert to whole pixel values (use ceiling to be conservative) | 207 // convert to whole pixel values (use ceiling to be conservative) |
205 int idx = SkScalarCeilToInt(dx); | 208 int idx = SkScalarCeilToInt(dx); |
(...skipping 13 matching lines...) Expand all Loading... |
219 | 222 |
220 SkChopQuadAtHalf(pts, tmp); | 223 SkChopQuadAtHalf(pts, tmp); |
221 hairquad(tmp, clip, blitter, level - 1, lineproc); | 224 hairquad(tmp, clip, blitter, level - 1, lineproc); |
222 hairquad(&tmp[2], clip, blitter, level - 1, lineproc); | 225 hairquad(&tmp[2], clip, blitter, level - 1, lineproc); |
223 } else { | 226 } else { |
224 SkPoint tmp[] = { pts[0], pts[2] }; | 227 SkPoint tmp[] = { pts[0], pts[2] }; |
225 lineproc(tmp, 2, clip, blitter); | 228 lineproc(tmp, 2, clip, blitter); |
226 } | 229 } |
227 } | 230 } |
228 | 231 |
229 static void haircubic(const SkPoint pts[4], const SkRegion* clip, | 232 #ifndef SK_SUPPORT_LEGACY_HAIRCUBIC |
| 233 static inline Sk2s abs(const Sk2s& value) { |
| 234 return Sk2s::Max(value, -value); |
| 235 } |
| 236 |
| 237 static inline SkScalar max_component(const Sk2s& value) { |
| 238 SkScalar components[2]; |
| 239 value.store(components); |
| 240 return SkTMax(components[0], components[1]); |
| 241 } |
| 242 |
| 243 static inline int compute_cubic_segs(const SkPoint pts[4]) { |
| 244 Sk2s p0 = from_point(pts[0]); |
| 245 Sk2s p1 = from_point(pts[1]); |
| 246 Sk2s p2 = from_point(pts[2]); |
| 247 Sk2s p3 = from_point(pts[3]); |
| 248 |
| 249 const Sk2s oneThird(1.0f / 3.0f); |
| 250 const Sk2s twoThird(2.0f / 3.0f); |
| 251 |
| 252 Sk2s p13 = oneThird * p3 + twoThird * p0; |
| 253 Sk2s p23 = oneThird * p0 + twoThird * p3; |
| 254 |
| 255 SkScalar diff = max_component(Sk2s::Max(abs(p1 - p13), abs(p2 - p23))); |
| 256 SkScalar tol = SK_Scalar1 / 8; |
| 257 |
| 258 for (int i = 0; i < kMaxCubicSubdivideLevel; ++i) { |
| 259 if (diff < tol) { |
| 260 return 1 << i; |
| 261 } |
| 262 tol *= 4; |
| 263 } |
| 264 return 1 << kMaxCubicSubdivideLevel; |
| 265 } |
| 266 |
| 267 static bool lt_90(SkPoint p0, SkPoint pivot, SkPoint p2) { |
| 268 return SkVector::DotProduct(p0 - pivot, p2 - pivot) >= 0; |
| 269 } |
| 270 |
| 271 // The off-curve points are "inside" the limits of the on-curve pts |
| 272 static bool quick_cubic_niceness_check(const SkPoint pts[4]) { |
| 273 return lt_90(pts[1], pts[0], pts[3]) && |
| 274 lt_90(pts[2], pts[0], pts[3]) && |
| 275 lt_90(pts[1], pts[3], pts[0]) && |
| 276 lt_90(pts[2], pts[3], pts[0]); |
| 277 } |
| 278 |
| 279 static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bl
itter, |
| 280 LineProc lineproc) { |
| 281 const int nLines = compute_cubic_segs(pts); |
| 282 SkASSERT(nLines > 0); |
| 283 if (1 == nLines) { |
| 284 lineproc(pts[0], pts[3], clip, blitter); |
| 285 return; |
| 286 } |
| 287 |
| 288 SkPoint coeff[4]; |
| 289 SkCubicToPoly(pts, coeff); |
| 290 |
| 291 const SkScalar deltaT = SK_Scalar1 / nLines; |
| 292 SkScalar currT = deltaT; |
| 293 |
| 294 SkPoint startPt = pts[0]; |
| 295 // to ensure we exactly end at the last cubic pt, we don't rely on the stepp
er |
| 296 // which could accumulate error in currT += deltaT... |
| 297 for (int i = 0; i < nLines - 1; ++i) { |
| 298 SkPoint endPt = SkEvalCubicPolyAt(coeff, currT); |
| 299 lineproc(startPt, endPt, clip, blitter); |
| 300 startPt = endPt; |
| 301 currT += deltaT; |
| 302 } |
| 303 lineproc(startPt, pts[3], clip, blitter); |
| 304 } |
| 305 #endif |
| 306 |
| 307 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, |
230 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { | 308 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { |
| 309 #ifdef SK_SUPPORT_LEGACY_HAIRCUBIC |
231 if (level > 0) { | 310 if (level > 0) { |
232 SkPoint tmp[7]; | 311 SkPoint tmp[7]; |
233 | 312 |
234 SkChopCubicAt(pts, tmp, SK_Scalar1/2); | 313 SkChopCubicAt(pts, tmp, SK_Scalar1/2); |
235 haircubic(tmp, clip, blitter, level - 1, lineproc); | 314 haircubic(tmp, clip, blitter, level - 1, lineproc); |
236 haircubic(&tmp[3], clip, blitter, level - 1, lineproc); | 315 haircubic(&tmp[3], clip, blitter, level - 1, lineproc); |
237 } else { | 316 } else { |
238 SkPoint tmp[] = { pts[0], pts[3] }; | 317 SkPoint tmp[] = { pts[0], pts[3] }; |
239 lineproc(tmp, 2, clip, blitter); | 318 lineproc(tmp, 2, clip, blitter); |
240 } | 319 } |
| 320 #else |
| 321 if (quick_cubic_niceness_check(pts)) { |
| 322 hair_cubic(pts, clip, blitter, lineproc); |
| 323 } else { |
| 324 SkPoint tmp[13]; |
| 325 SkScalar tValues[3]; |
| 326 |
| 327 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); |
| 328 for (int i = 0; i < count; i++) { |
| 329 hair_cubic(&tmp[i * 3], clip, blitter, lineproc); |
| 330 } |
| 331 } |
| 332 #endif |
241 } | 333 } |
242 | 334 |
243 #define kMaxCubicSubdivideLevel 6 | |
244 #define kMaxQuadSubdivideLevel 5 | |
245 | |
246 static int compute_quad_level(const SkPoint pts[3]) { | 335 static int compute_quad_level(const SkPoint pts[3]) { |
247 int d = compute_int_quad_dist(pts); | 336 int d = compute_int_quad_dist(pts); |
248 /* quadratics approach the line connecting their start and end points | 337 /* quadratics approach the line connecting their start and end points |
249 4x closer with each subdivision, so we compute the number of | 338 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 | 339 subdivisions to be the minimum need to get that distance to be less |
251 than a pixel. | 340 than a pixel. |
252 */ | 341 */ |
253 int level = (33 - SkCLZ(d)) >> 1; | 342 int level = (33 - SkCLZ(d)) >> 1; |
254 // sanity check on level (from the previous version) | 343 // sanity check on level (from the previous version) |
255 if (level > kMaxQuadSubdivideLevel) { | 344 if (level > kMaxQuadSubdivideLevel) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 const SkScalar tol = SK_Scalar1 / 4; | 393 const SkScalar tol = SK_Scalar1 / 4; |
305 const SkPoint* quadPts = converter.computeQuads(pts, | 394 const SkPoint* quadPts = converter.computeQuads(pts, |
306 iter.conicWeight(), tol); | 395 iter.conicWeight(), tol); |
307 for (int i = 0; i < converter.countQuads(); ++i) { | 396 for (int i = 0; i < converter.countQuads(); ++i) { |
308 int level = compute_quad_level(quadPts); | 397 int level = compute_quad_level(quadPts); |
309 hairquad(quadPts, clip, blitter, level, lineproc); | 398 hairquad(quadPts, clip, blitter, level, lineproc); |
310 quadPts += 2; | 399 quadPts += 2; |
311 } | 400 } |
312 break; | 401 break; |
313 } | 402 } |
314 case SkPath::kCubic_Verb: | 403 case SkPath::kCubic_Verb: { |
315 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
; | 404 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
; |
316 break; | 405 } break; |
317 case SkPath::kClose_Verb: | 406 case SkPath::kClose_Verb: |
318 break; | 407 break; |
319 case SkPath::kDone_Verb: | 408 case SkPath::kDone_Verb: |
320 break; | 409 break; |
321 } | 410 } |
322 } | 411 } |
323 } | 412 } |
324 | 413 |
325 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
litter) { | 414 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
litter) { |
326 hair_path(path, clip, blitter, SkScan::HairLineRgn); | 415 hair_path(path, clip, blitter, SkScan::HairLineRgn); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 | 489 |
401 SkAAClipBlitterWrapper wrap; | 490 SkAAClipBlitterWrapper wrap; |
402 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 491 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { |
403 wrap.init(clip, blitter); | 492 wrap.init(clip, blitter); |
404 blitter = wrap.getBlitter(); | 493 blitter = wrap.getBlitter(); |
405 clipRgn = &wrap.getRgn(); | 494 clipRgn = &wrap.getRgn(); |
406 } | 495 } |
407 AntiHairLineRgn(pts, count, clipRgn, blitter); | 496 AntiHairLineRgn(pts, count, clipRgn, blitter); |
408 } | 497 } |
409 } | 498 } |
OLD | NEW |