Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Macros | Typedefs | Functions
SkScan_Hairline.cpp File Reference
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRegion.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkSafe32.h"
#include "src/base/SkMathPriv.h"
#include "src/base/SkUtils.h"
#include "src/base/SkVx.h"
#include "src/core/SkBlitter.h"
#include "src/core/SkFDot6.h"
#include "src/core/SkGeometry.h"
#include "src/core/SkLineClipper.h"
#include "src/core/SkPathPriv.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkScan.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>

Go to the source code of this file.

Macros

#define kMaxCubicSubdivideLevel   9
 
#define kMaxQuadSubdivideLevel   5
 

Typedefs

using float2 = skvx::float2
 
using mask2 = skvx::Vec< 2, uint32_t >
 

Functions

static void horiline (int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter *blitter)
 
static void vertline (int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter *blitter)
 
static uint32_t compute_int_quad_dist (const SkPoint pts[3])
 
static void hair_quad (const SkPoint pts[3], const SkRegion *clip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
 
static SkRect compute_nocheck_quad_bounds (const SkPoint pts[3])
 
static bool is_inverted (const SkRect &r)
 
static bool geometric_overlap (const SkRect &a, const SkRect &b)
 
static bool geometric_contains (const SkRect &outer, const SkRect &inner)
 
static void hairquad (const SkPoint pts[3], const SkRegion *clip, const SkRect *insetClip, const SkRect *outsetClip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
 
static SkScalar max_component (const float2 &value)
 
static int compute_cubic_segs (const SkPoint pts[4])
 
static bool lt_90 (SkPoint p0, SkPoint pivot, SkPoint p2)
 
static bool quick_cubic_niceness_check (const SkPoint pts[4])
 
static mask2 float2_is_finite (const float2 &x)
 
static void hair_cubic (const SkPoint pts[4], const SkRegion *clip, SkBlitter *blitter, SkScan::HairRgnProc lineproc)
 
static SkRect compute_nocheck_cubic_bounds (const SkPoint pts[4])
 
static void haircubic (const SkPoint pts[4], const SkRegion *clip, const SkRect *insetClip, const SkRect *outsetClip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
 
static int compute_quad_level (const SkPoint pts[3])
 
template<SkPaint::Cap capStyle>
void extend_pts (SkPath::Verb prevVerb, SkPath::Verb nextVerb, SkPoint *pts, int ptCount)
 
template<SkPaint::Cap capStyle>
void hair_path (const SkPath &path, const SkRasterClip &rclip, SkBlitter *blitter, SkScan::HairRgnProc lineproc)
 

Macro Definition Documentation

◆ kMaxCubicSubdivideLevel

#define kMaxCubicSubdivideLevel   9

Definition at line 230 of file SkScan_Hairline.cpp.

◆ kMaxQuadSubdivideLevel

#define kMaxQuadSubdivideLevel   5

Definition at line 231 of file SkScan_Hairline.cpp.

Typedef Documentation

◆ float2

Definition at line 233 of file SkScan_Hairline.cpp.

◆ mask2

using mask2 = skvx::Vec<2, uint32_t>

Definition at line 371 of file SkScan_Hairline.cpp.

Function Documentation

◆ compute_cubic_segs()

static int compute_cubic_segs ( const SkPoint  pts[4])
inlinestatic

Definition at line 335 of file SkScan_Hairline.cpp.

335 {
336 float2 p0 = from_point(pts[0]);
337 float2 p1 = from_point(pts[1]);
338 float2 p2 = from_point(pts[2]);
339 float2 p3 = from_point(pts[3]);
340
341 const float2 oneThird(1.0f / 3.0f);
342 const float2 twoThird(2.0f / 3.0f);
343
344 float2 p13 = oneThird * p3 + twoThird * p0;
345 float2 p23 = oneThird * p0 + twoThird * p3;
346
347 SkScalar diff = max_component(max(abs(p1 - p13), abs(p2 - p23)));
348 SkScalar tol = SK_Scalar1 / 8;
349
350 for (int i = 0; i < kMaxCubicSubdivideLevel; ++i) {
351 if (diff < tol) {
352 return 1 << i;
353 }
354 tol *= 4;
355 }
356 return 1 << kMaxCubicSubdivideLevel;
357}
static skvx::float2 from_point(const SkPoint &point)
Definition SkGeometry.h:22
#define SK_Scalar1
Definition SkScalar.h:18
#define kMaxCubicSubdivideLevel
static SkScalar max_component(const float2 &value)
float SkScalar
Definition extension.cpp:12
static float max(float r, float g, float b)
Definition hsl.cpp:49
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition SkVx.h:707

◆ compute_int_quad_dist()

static uint32_t compute_int_quad_dist ( const SkPoint  pts[3])
static

Definition at line 235 of file SkScan_Hairline.cpp.

235 {
236 // compute the vector between the control point ([1]) and the middle of the
237 // line connecting the start and end ([0] and [2])
238 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX;
239 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY;
240 // we want everyone to be positive
241 dx = SkScalarAbs(dx);
242 dy = SkScalarAbs(dy);
243 // convert to whole pixel values (use ceiling to be conservative).
244 // assign to unsigned so we can safely add 1/2 of the smaller and still fit in
245 // uint32_t, since SkScalarCeilToInt() returns 31 bits at most.
246 uint32_t idx = SkScalarCeilToInt(dx);
247 uint32_t idy = SkScalarCeilToInt(dy);
248 // use the cheap approx for distance
249 if (idx > idy) {
250 return idx + (idy >> 1);
251 } else {
252 return idy + (idx >> 1);
253 }
254}
#define SkScalarHalf(a)
Definition SkScalar.h:75
#define SkScalarCeilToInt(x)
Definition SkScalar.h:36
#define SkScalarAbs(x)
Definition SkScalar.h:39
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208
float fX
x-axis value
float fY
y-axis value

◆ compute_nocheck_cubic_bounds()

static SkRect compute_nocheck_cubic_bounds ( const SkPoint  pts[4])
static

Definition at line 414 of file SkScan_Hairline.cpp.

414 {
415 SkASSERT(SkIsFinite(&pts[0].fX, 8));
416
417 float2 min = float2::Load(pts);
418 float2 max = min;
419 for (int i = 1; i < 4; ++i) {
420 float2 pair = float2::Load(pts+i);
421 min = skvx::min(min, pair);
422 max = skvx::max(max, pair);
423 }
424 return { min[0], min[1], max[0], max[1] };
425}
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool SkIsFinite(T x, Pack... values)
static float min(float r, float g, float b)
Definition hsl.cpp:48
SIT T max(const Vec< 1, T > &x)
Definition SkVx.h:641
SIT T min(const Vec< 1, T > &x)
Definition SkVx.h:640
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition SkVx.h:109

◆ compute_nocheck_quad_bounds()

static SkRect compute_nocheck_quad_bounds ( const SkPoint  pts[3])
static

Definition at line 281 of file SkScan_Hairline.cpp.

281 {
282 SkASSERT(SkIsFinite(&pts[0].fX, 6));
283
284 float2 min = float2::Load(pts);
285 float2 max = min;
286 for (int i = 1; i < 3; ++i) {
287 float2 pair = float2::Load(pts+i);
288 min = skvx::min(min, pair);
289 max = skvx::max(max, pair);
290 }
291 return { min[0], min[1], max[0], max[1] };
292}

◆ compute_quad_level()

static int compute_quad_level ( const SkPoint  pts[3])
static

Definition at line 452 of file SkScan_Hairline.cpp.

452 {
453 uint32_t d = compute_int_quad_dist(pts);
454 /* quadratics approach the line connecting their start and end points
455 4x closer with each subdivision, so we compute the number of
456 subdivisions to be the minimum need to get that distance to be less
457 than a pixel.
458 */
459 int level = (33 - SkCLZ(d)) >> 1;
460 // safety check on level (from the previous version)
461 if (level > kMaxQuadSubdivideLevel) {
463 }
464 return level;
465}
static int SkCLZ(uint32_t mask)
Definition SkMathPriv.h:186
#define kMaxQuadSubdivideLevel
static uint32_t compute_int_quad_dist(const SkPoint pts[3])
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19

◆ extend_pts()

template<SkPaint::Cap capStyle>
void extend_pts ( SkPath::Verb  prevVerb,
SkPath::Verb  nextVerb,
SkPoint pts,
int  ptCount 
)

Definition at line 472 of file SkScan_Hairline.cpp.

472 {
473 SkASSERT(SkPaint::kSquare_Cap == capStyle || SkPaint::kRound_Cap == capStyle);
474 // The area of a circle is PI*R*R. For a unit circle, R=1/2, and the cap covers half of that.
475 const SkScalar capOutset = SkPaint::kSquare_Cap == capStyle ? 0.5f : SK_ScalarPI / 8;
476 if (SkPath::kMove_Verb == prevVerb) {
477 SkPoint* first = pts;
478 SkPoint* ctrl = first;
479 int controls = ptCount - 1;
480 SkVector tangent;
481 do {
482 tangent = *first - *++ctrl;
483 } while (tangent.isZero() && --controls > 0);
484 if (tangent.isZero()) {
485 tangent.set(1, 0);
486 controls = ptCount - 1; // If all points are equal, move all but one
487 } else {
488 tangent.normalize();
489 }
490 do { // If the end point and control points are equal, loop to move them in tandem.
491 first->fX += tangent.fX * capOutset;
492 first->fY += tangent.fY * capOutset;
493 ++first;
494 } while (++controls < ptCount);
495 }
496 if (SkPath::kMove_Verb == nextVerb || SkPath::kDone_Verb == nextVerb
497 || SkPath::kClose_Verb == nextVerb) {
498 SkPoint* last = &pts[ptCount - 1];
499 SkPoint* ctrl = last;
500 int controls = ptCount - 1;
501 SkVector tangent;
502 do {
503 tangent = *last - *--ctrl;
504 } while (tangent.isZero() && --controls > 0);
505 if (tangent.isZero()) {
506 tangent.set(-1, 0);
507 controls = ptCount - 1;
508 } else {
509 tangent.normalize();
510 }
511 do {
512 last->fX += tangent.fX * capOutset;
513 last->fY += tangent.fY * capOutset;
514 --last;
515 } while (++controls < ptCount);
516 }
517}
#define SK_ScalarPI
Definition SkScalar.h:21
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kSquare_Cap
adds square
Definition SkPaint.h:336
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kDone_Verb
Definition SkPath.h:1464
bool isZero() const
void set(float x, float y)
bool normalize()
Definition SkPoint.cpp:22

◆ float2_is_finite()

static mask2 float2_is_finite ( const float2 x)
inlinestatic

Definition at line 373 of file SkScan_Hairline.cpp.

373 {
374 const mask2 exp_mask = mask2(0xFF << 23);
375 return (sk_bit_cast<mask2>(x) & exp_mask) != exp_mask;
376}
skvx::Vec< 2, uint32_t > mask2
double x

◆ geometric_contains()

static bool geometric_contains ( const SkRect outer,
const SkRect inner 
)
static

Definition at line 308 of file SkScan_Hairline.cpp.

308 {
309 SkASSERT(!is_inverted(outer) && !is_inverted(inner));
310 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft &&
311 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop;
312}
static bool is_inverted(const SkRect &r)
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15

◆ geometric_overlap()

static bool geometric_overlap ( const SkRect a,
const SkRect b 
)
static

Definition at line 300 of file SkScan_Hairline.cpp.

300 {
302 return a.fLeft < b.fRight && b.fLeft < a.fRight &&
303 a.fTop < b.fBottom && b.fTop < a.fBottom;
304}
static bool b
struct MyStruct a[10]

◆ hair_cubic()

static void hair_cubic ( const SkPoint  pts[4],
const SkRegion clip,
SkBlitter blitter,
SkScan::HairRgnProc  lineproc 
)
static

Definition at line 378 of file SkScan_Hairline.cpp.

379 {
380 const int lines = compute_cubic_segs(pts);
381 SkASSERT(lines > 0);
382 if (1 == lines) {
383 SkPoint tmp[2] = { pts[0], pts[3] };
384 lineproc(tmp, 2, clip, blitter);
385 return;
386 }
387
388 SkCubicCoeff coeff(pts);
389
390 const float2 dt(SK_Scalar1 / lines);
391 float2 t(0);
392
393 SkPoint tmp[(1 << kMaxCubicSubdivideLevel) + 1];
394 SkASSERT((unsigned)lines < std::size(tmp));
395
396 tmp[0] = pts[0];
397 float2 A = coeff.fA;
398 float2 B = coeff.fB;
399 float2 C = coeff.fC;
400 float2 D = coeff.fD;
401 mask2 is_finite(~0); // start out as true
402 for (int i = 1; i < lines; ++i) {
403 t = t + dt;
404 float2 p = ((A * t + B) * t + C) * t + D;
405 is_finite &= float2_is_finite(p);
406 p.store(&tmp[i]);
407 }
408 if (all(is_finite)) {
409 tmp[lines] = pts[3];
410 lineproc(tmp, lines + 1, clip, blitter);
411 } // else some point(s) are non-finite, so don't draw
412}
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static int compute_cubic_segs(const SkPoint pts[4])
static mask2 float2_is_finite(const float2 &x)
#define B
SIT bool all(const Vec< 1, T > &x)
Definition SkVx.h:582

◆ hair_path()

template<SkPaint::Cap capStyle>
void hair_path ( const SkPath path,
const SkRasterClip rclip,
SkBlitter blitter,
SkScan::HairRgnProc  lineproc 
)

Definition at line 520 of file SkScan_Hairline.cpp.

521 {
522 if (path.isEmpty()) {
523 return;
524 }
525
527 const SkRegion* clip = nullptr;
528 SkRect insetStorage, outsetStorage;
529 const SkRect* insetClip = nullptr;
530 const SkRect* outsetClip = nullptr;
531
532 {
533 const int capOut = SkPaint::kButt_Cap == capStyle ? 1 : 2;
534 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(capOut, capOut);
535 if (rclip.quickReject(ibounds)) {
536 return;
537 }
538 if (!rclip.quickContains(ibounds)) {
539 if (rclip.isBW()) {
540 clip = &rclip.bwRgn();
541 } else {
542 wrap.init(rclip, blitter);
543 blitter = wrap.getBlitter();
544 clip = &wrap.getRgn();
545 }
546
547 /*
548 * We now cache two scalar rects, to use for culling per-segment (e.g. cubic).
549 * Since we're hairlining, the "bounds" of the control points isn't necessairly the
550 * limit of where a segment can draw (it might draw up to 1 pixel beyond in aa-hairs).
551 *
552 * Compute the pt-bounds per segment is easy, so we do that, and then inversely adjust
553 * the culling bounds so we can just do a straight compare per segment.
554 *
555 * insetClip is use for quick-accept (i.e. the segment is not clipped), so we inset
556 * it from the clip-bounds (since segment bounds can be off by 1).
557 *
558 * outsetClip is used for quick-reject (i.e. the segment is entirely outside), so we
559 * outset it from the clip-bounds.
560 */
561 insetStorage.set(clip->getBounds());
562 outsetStorage = insetStorage.makeOutset(1, 1);
563 insetStorage.inset(1, 1);
564 if (is_inverted(insetStorage)) {
565 /*
566 * our bounds checks assume the rects are never inverted. If insetting has
567 * created that, we assume that the area is too small to safely perform a
568 * quick-accept, so we just mark the rect as empty (so the quick-accept check
569 * will always fail.
570 */
571 insetStorage.setEmpty(); // just so we don't pass an inverted rect
572 }
573 if (rclip.isRect()) {
574 insetClip = &insetStorage;
575 }
576 outsetClip = &outsetStorage;
577 }
578 }
579
582 SkPoint pts[4], firstPt, lastPt;
583 SkPath::Verb prevVerb;
585
586 if (SkPaint::kButt_Cap != capStyle) {
587 prevVerb = SkPath::kDone_Verb;
588 }
589 while (iter != end) {
590 auto [pathVerb, pathPts, w] = *iter++;
591 SkPath::Verb verb = (SkPath::Verb)pathVerb;
592 SkPath::Verb nextVerb = (iter != end) ? (SkPath::Verb)iter.peekVerb() : SkPath::kDone_Verb;
593 memcpy(pts, pathPts, SkPathPriv::PtsInIter(verb) * sizeof(SkPoint));
594 switch (verb) {
596 firstPt = lastPt = pts[0];
597 break;
599 if (SkPaint::kButt_Cap != capStyle) {
600 extend_pts<capStyle>(prevVerb, nextVerb, pts, 2);
601 }
602 lineproc(pts, 2, clip, blitter);
603 lastPt = pts[1];
604 break;
606 if (SkPaint::kButt_Cap != capStyle) {
607 extend_pts<capStyle>(prevVerb, nextVerb, pts, 3);
608 }
609 hairquad(pts, clip, insetClip, outsetClip, blitter, compute_quad_level(pts), lineproc);
610 lastPt = pts[2];
611 break;
612 case SkPath::kConic_Verb: {
613 if (SkPaint::kButt_Cap != capStyle) {
614 extend_pts<capStyle>(prevVerb, nextVerb, pts, 3);
615 }
616 // how close should the quads be to the original conic?
617 const SkScalar tol = SK_Scalar1 / 4;
618 const SkPoint* quadPts = converter.computeQuads(pts, *w, tol);
619 for (int i = 0; i < converter.countQuads(); ++i) {
620 int level = compute_quad_level(quadPts);
621 hairquad(quadPts, clip, insetClip, outsetClip, blitter, level, lineproc);
622 quadPts += 2;
623 }
624 lastPt = pts[2];
625 break;
626 }
627 case SkPath::kCubic_Verb: {
628 if (SkPaint::kButt_Cap != capStyle) {
629 extend_pts<capStyle>(prevVerb, nextVerb, pts, 4);
630 }
631 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSubdivideLevel, lineproc);
632 lastPt = pts[3];
633 } break;
635 pts[0] = lastPt;
636 pts[1] = firstPt;
637 if (SkPaint::kButt_Cap != capStyle && prevVerb == SkPath::kMove_Verb) {
638 // cap moveTo/close to match svg expectations for degenerate segments
639 extend_pts<capStyle>(prevVerb, nextVerb, pts, 2);
640 }
641 lineproc(pts, 2, clip, blitter);
642 break;
644 break;
645 }
646 if (SkPaint::kButt_Cap != capStyle) {
647 if (prevVerb == SkPath::kMove_Verb &&
648 verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
649 firstPt = pts[0]; // the curve moved the initial point, so close to it instead
650 }
651 prevVerb = verb;
652 }
653 }
654}
static void haircubic(const SkPoint pts[4], const SkRegion *clip, const SkRect *insetClip, const SkRect *outsetClip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
static void hairquad(const SkPoint pts[3], const SkRegion *clip, const SkRect *insetClip, const SkRect *outsetClip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
static int compute_quad_level(const SkPoint pts[3])
void init(const SkRasterClip &, SkBlitter *)
const SkRegion & getRgn() const
SkBlitter * getBlitter()
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
static int PtsInIter(unsigned verb)
Definition SkPathPriv.h:305
SkPath::RangeIter RangeIter
Definition SkPathPriv.h:164
const SkRect & getBounds() const
Definition SkPath.cpp:420
@ kConic_Verb
Definition SkPath.h:1461
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
const SkRegion & bwRgn() const
bool quickContains(const SkIRect &rect) const
bool isRect() const
bool isBW() const
bool quickReject(const SkIRect &rect) const
glong glong end
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
SkScalar w
SkPath::RangeIter end()
Definition SkPathPriv.h:187
SkPath::RangeIter begin()
Definition SkPathPriv.h:186
void inset(float dx, float dy)
Definition SkRect.h:1060
SkRect makeOutset(float dx, float dy) const
Definition SkRect.h:1002
void set(const SkIRect &src)
Definition SkRect.h:849
void setEmpty()
Definition SkRect.h:842

◆ hair_quad()

static void hair_quad ( const SkPoint  pts[3],
const SkRegion clip,
SkBlitter blitter,
int  level,
SkScan::HairRgnProc  lineproc 
)
static

Definition at line 256 of file SkScan_Hairline.cpp.

257 {
259
260 SkQuadCoeff coeff(pts);
261
262 const int lines = 1 << level;
263 float2 t(0);
264 float2 dt(SK_Scalar1 / lines);
265
266 SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1];
267 SkASSERT((unsigned)lines < std::size(tmp));
268
269 tmp[0] = pts[0];
270 float2 A = coeff.fA;
271 float2 B = coeff.fB;
272 float2 C = coeff.fC;
273 for (int i = 1; i < lines; ++i) {
274 t = t + dt;
275 ((A * t + B) * t + C).store(&tmp[i]);
276 }
277 tmp[lines] = pts[2];
278 lineproc(tmp, lines + 1, clip, blitter);
279}

◆ haircubic()

static void haircubic ( const SkPoint  pts[4],
const SkRegion clip,
const SkRect insetClip,
const SkRect outsetClip,
SkBlitter blitter,
int  level,
SkScan::HairRgnProc  lineproc 
)
inlinestatic

Definition at line 427 of file SkScan_Hairline.cpp.

428 {
429 if (insetClip) {
430 SkASSERT(outsetClip);
432 if (!geometric_overlap(*outsetClip, bounds)) {
433 return;
434 } else if (geometric_contains(*insetClip, bounds)) {
435 clip = nullptr;
436 }
437 }
438
440 hair_cubic(pts, clip, blitter, lineproc);
441 } else {
442 SkPoint tmp[13];
443 SkScalar tValues[3];
444
445 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
446 for (int i = 0; i < count; i++) {
447 hair_cubic(&tmp[i * 3], clip, blitter, lineproc);
448 }
449 }
450}
int count
int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3])
static bool quick_cubic_niceness_check(const SkPoint pts[4])
static SkRect compute_nocheck_cubic_bounds(const SkPoint pts[4])
static bool geometric_overlap(const SkRect &a, const SkRect &b)
static void hair_cubic(const SkPoint pts[4], const SkRegion *clip, SkBlitter *blitter, SkScan::HairRgnProc lineproc)
static bool geometric_contains(const SkRect &outer, const SkRect &inner)
Optional< SkRect > bounds
Definition SkRecords.h:189

◆ hairquad()

static void hairquad ( const SkPoint  pts[3],
const SkRegion clip,
const SkRect insetClip,
const SkRect outsetClip,
SkBlitter blitter,
int  level,
SkScan::HairRgnProc  lineproc 
)
inlinestatic

Definition at line 314 of file SkScan_Hairline.cpp.

315 {
316 if (insetClip) {
317 SkASSERT(outsetClip);
319 if (!geometric_overlap(*outsetClip, bounds)) {
320 return;
321 } else if (geometric_contains(*insetClip, bounds)) {
322 clip = nullptr;
323 }
324 }
325
326 hair_quad(pts, clip, blitter, level, lineproc);
327}
static void hair_quad(const SkPoint pts[3], const SkRegion *clip, SkBlitter *blitter, int level, SkScan::HairRgnProc lineproc)
static SkRect compute_nocheck_quad_bounds(const SkPoint pts[3])

◆ horiline()

static void horiline ( int  x,
int  stopx,
SkFixed  fy,
SkFixed  dy,
SkBlitter blitter 
)
static

Definition at line 35 of file SkScan_Hairline.cpp.

36 {
37 SkASSERT(x < stopx);
38
39 do {
40 blitter->blitH(x, fy >> 16, 1);
41 fy += dy;
42 } while (++x < stopx);
43}
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.

◆ is_inverted()

static bool is_inverted ( const SkRect r)
static

Definition at line 294 of file SkScan_Hairline.cpp.

294 {
295 return r.fLeft > r.fRight || r.fTop > r.fBottom;
296}

◆ lt_90()

static bool lt_90 ( SkPoint  p0,
SkPoint  pivot,
SkPoint  p2 
)
static

Definition at line 359 of file SkScan_Hairline.cpp.

359 {
360 return SkVector::DotProduct(p0 - pivot, p2 - pivot) >= 0;
361}
static float DotProduct(const SkVector &a, const SkVector &b)

◆ max_component()

static SkScalar max_component ( const float2 value)
inlinestatic

Definition at line 329 of file SkScan_Hairline.cpp.

329 {
330 SkScalar components[2];
331 value.store(components);
332 return std::max(components[0], components[1]);
333}
uint8_t value

◆ quick_cubic_niceness_check()

static bool quick_cubic_niceness_check ( const SkPoint  pts[4])
static

Definition at line 364 of file SkScan_Hairline.cpp.

364 {
365 return lt_90(pts[1], pts[0], pts[3]) &&
366 lt_90(pts[2], pts[0], pts[3]) &&
367 lt_90(pts[1], pts[3], pts[0]) &&
368 lt_90(pts[2], pts[3], pts[0]);
369}
static bool lt_90(SkPoint p0, SkPoint pivot, SkPoint p2)

◆ vertline()

static void vertline ( int  y,
int  stopy,
SkFixed  fx,
SkFixed  dx,
SkBlitter blitter 
)
static

Definition at line 45 of file SkScan_Hairline.cpp.

46 {
47 SkASSERT(y < stopy);
48
49 do {
50 blitter->blitH(fx >> 16, y, 1);
51 fx += dx;
52 } while (++y < stopy);
53}
double y