OLD | NEW |
| 1 |
1 /* | 2 /* |
2 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
3 * | 4 * |
4 * 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 |
5 * found in the LICENSE file. | 6 * found in the LICENSE file. |
6 */ | 7 */ |
7 | 8 |
| 9 |
8 #include "SkScan.h" | 10 #include "SkScan.h" |
9 #include "SkBlitter.h" | 11 #include "SkBlitter.h" |
10 #include "SkRasterClip.h" | 12 #include "SkRasterClip.h" |
11 #include "SkFDot6.h" | 13 #include "SkFDot6.h" |
12 #include "SkLineClipper.h" | 14 #include "SkLineClipper.h" |
13 | 15 |
14 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, | 16 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, |
15 SkBlitter* blitter) { | 17 SkBlitter* blitter) { |
16 SkASSERT(x < stopx); | 18 SkASSERT(x < stopx); |
17 | 19 |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 blitter->blitH(r.fLeft, r.fTop, width); // top | 185 blitter->blitH(r.fLeft, r.fTop, width); // top |
184 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left | 186 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left |
185 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 |
186 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom | 188 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom |
187 } | 189 } |
188 | 190 |
189 /////////////////////////////////////////////////////////////////////////////// | 191 /////////////////////////////////////////////////////////////////////////////// |
190 | 192 |
191 #include "SkPath.h" | 193 #include "SkPath.h" |
192 #include "SkGeometry.h" | 194 #include "SkGeometry.h" |
193 #include "SkNx.h" | |
194 | |
195 #define kMaxCubicSubdivideLevel 6 | |
196 #define kMaxQuadSubdivideLevel 5 | |
197 | 195 |
198 static int compute_int_quad_dist(const SkPoint pts[3]) { | 196 static int compute_int_quad_dist(const SkPoint pts[3]) { |
199 // compute the vector between the control point ([1]) and the middle of the | 197 // compute the vector between the control point ([1]) and the middle of the |
200 // line connecting the start and end ([0] and [2]) | 198 // line connecting the start and end ([0] and [2]) |
201 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; | 199 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; |
202 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; | 200 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; |
203 // we want everyone to be positive | 201 // we want everyone to be positive |
204 dx = SkScalarAbs(dx); | 202 dx = SkScalarAbs(dx); |
205 dy = SkScalarAbs(dy); | 203 dy = SkScalarAbs(dy); |
206 // convert to whole pixel values (use ceiling to be conservative) | 204 // convert to whole pixel values (use ceiling to be conservative) |
207 int idx = SkScalarCeilToInt(dx); | 205 int idx = SkScalarCeilToInt(dx); |
208 int idy = SkScalarCeilToInt(dy); | 206 int idy = SkScalarCeilToInt(dy); |
209 // use the cheap approx for distance | 207 // use the cheap approx for distance |
210 if (idx > idy) { | 208 if (idx > idy) { |
211 return idx + (idy >> 1); | 209 return idx + (idy >> 1); |
212 } else { | 210 } else { |
213 return idy + (idx >> 1); | 211 return idy + (idx >> 1); |
214 } | 212 } |
215 } | 213 } |
216 | 214 |
217 static void hairquad(const SkPoint pts[3], const SkRegion* clip, | 215 static void hairquad(const SkPoint pts[3], const SkRegion* clip, |
218 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
) { | 216 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc
) { |
219 SkASSERT(level <= kMaxQuadSubdivideLevel); | |
220 | |
221 #ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 | |
222 if (level > 0) { | 217 if (level > 0) { |
223 SkPoint tmp[5]; | 218 SkPoint tmp[5]; |
224 | 219 |
225 SkChopQuadAtHalf(pts, tmp); | 220 SkChopQuadAtHalf(pts, tmp); |
226 hairquad(tmp, clip, blitter, level - 1, lineproc); | 221 hairquad(tmp, clip, blitter, level - 1, lineproc); |
227 hairquad(&tmp[2], clip, blitter, level - 1, lineproc); | 222 hairquad(&tmp[2], clip, blitter, level - 1, lineproc); |
228 } else { | 223 } else { |
229 SkPoint tmp[] = { pts[0], pts[2] }; | 224 SkPoint tmp[] = { pts[0], pts[2] }; |
230 lineproc(tmp, 2, clip, blitter); | 225 lineproc(tmp, 2, clip, blitter); |
231 } | 226 } |
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 | |
254 } | 227 } |
255 | 228 |
256 #ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2 | 229 static void haircubic(const SkPoint pts[4], const SkRegion* clip, |
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, | |
337 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { | 230 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro
c) { |
338 #ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 | |
339 if (level > 0) { | 231 if (level > 0) { |
340 SkPoint tmp[7]; | 232 SkPoint tmp[7]; |
341 | 233 |
342 SkChopCubicAt(pts, tmp, SK_Scalar1/2); | 234 SkChopCubicAt(pts, tmp, SK_Scalar1/2); |
343 haircubic(tmp, clip, blitter, level - 1, lineproc); | 235 haircubic(tmp, clip, blitter, level - 1, lineproc); |
344 haircubic(&tmp[3], clip, blitter, level - 1, lineproc); | 236 haircubic(&tmp[3], clip, blitter, level - 1, lineproc); |
345 } else { | 237 } else { |
346 SkPoint tmp[] = { pts[0], pts[3] }; | 238 SkPoint tmp[] = { pts[0], pts[3] }; |
347 lineproc(tmp, 2, clip, blitter); | 239 lineproc(tmp, 2, clip, blitter); |
348 } | 240 } |
349 #else | 241 } |
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 | 242 |
356 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); | 243 #define kMaxCubicSubdivideLevel 6 |
357 for (int i = 0; i < count; i++) { | 244 #define kMaxQuadSubdivideLevel 5 |
358 hair_cubic(&tmp[i * 3], clip, blitter, lineproc); | |
359 } | |
360 } | |
361 #endif | |
362 } | |
363 | 245 |
364 static int compute_quad_level(const SkPoint pts[3]) { | 246 static int compute_quad_level(const SkPoint pts[3]) { |
365 int d = compute_int_quad_dist(pts); | 247 int d = compute_int_quad_dist(pts); |
366 /* quadratics approach the line connecting their start and end points | 248 /* quadratics approach the line connecting their start and end points |
367 4x closer with each subdivision, so we compute the number of | 249 4x closer with each subdivision, so we compute the number of |
368 subdivisions to be the minimum need to get that distance to be less | 250 subdivisions to be the minimum need to get that distance to be less |
369 than a pixel. | 251 than a pixel. |
370 */ | 252 */ |
371 int level = (33 - SkCLZ(d)) >> 1; | 253 int level = (33 - SkCLZ(d)) >> 1; |
372 // sanity check on level (from the previous version) | 254 // sanity check on level (from the previous version) |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 const SkScalar tol = SK_Scalar1 / 4; | 304 const SkScalar tol = SK_Scalar1 / 4; |
423 const SkPoint* quadPts = converter.computeQuads(pts, | 305 const SkPoint* quadPts = converter.computeQuads(pts, |
424 iter.conicWeight(), tol); | 306 iter.conicWeight(), tol); |
425 for (int i = 0; i < converter.countQuads(); ++i) { | 307 for (int i = 0; i < converter.countQuads(); ++i) { |
426 int level = compute_quad_level(quadPts); | 308 int level = compute_quad_level(quadPts); |
427 hairquad(quadPts, clip, blitter, level, lineproc); | 309 hairquad(quadPts, clip, blitter, level, lineproc); |
428 quadPts += 2; | 310 quadPts += 2; |
429 } | 311 } |
430 break; | 312 break; |
431 } | 313 } |
432 case SkPath::kCubic_Verb: { | 314 case SkPath::kCubic_Verb: |
433 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
; | 315 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc)
; |
434 } break; | 316 break; |
435 case SkPath::kClose_Verb: | 317 case SkPath::kClose_Verb: |
436 break; | 318 break; |
437 case SkPath::kDone_Verb: | 319 case SkPath::kDone_Verb: |
438 break; | 320 break; |
439 } | 321 } |
440 } | 322 } |
441 } | 323 } |
442 | 324 |
443 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
litter) { | 325 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b
litter) { |
444 hair_path(path, clip, blitter, SkScan::HairLineRgn); | 326 hair_path(path, clip, blitter, SkScan::HairLineRgn); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 | 400 |
519 SkAAClipBlitterWrapper wrap; | 401 SkAAClipBlitterWrapper wrap; |
520 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 402 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { |
521 wrap.init(clip, blitter); | 403 wrap.init(clip, blitter); |
522 blitter = wrap.getBlitter(); | 404 blitter = wrap.getBlitter(); |
523 clipRgn = &wrap.getRgn(); | 405 clipRgn = &wrap.getRgn(); |
524 } | 406 } |
525 AntiHairLineRgn(pts, count, clipRgn, blitter); | 407 AntiHairLineRgn(pts, count, clipRgn, blitter); |
526 } | 408 } |
527 } | 409 } |
OLD | NEW |