Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Typedefs | Enumerations | Functions | Variables
GrDistanceFieldGenFromVector.cpp File Reference
#include "src/gpu/ganesh/GrDistanceFieldGenFromVector.h"
#include "include/core/SkMatrix.h"
#include "include/private/base/SkTPin.h"
#include "src/base/SkAutoMalloc.h"
#include "src/core/SkDistanceFieldGen.h"
#include "src/core/SkGeometry.h"
#include "src/core/SkPathPriv.h"
#include "src/core/SkPointPriv.h"
#include "src/core/SkRectPriv.h"
#include "src/gpu/ganesh/geometry/GrPathUtils.h"

Go to the source code of this file.

Classes

struct  DFData
 
class  DAffineMatrix
 
class  PathSegment
 
struct  RowData
 

Typedefs

typedef TArray< PathSegment, true > PathSegmentArray
 

Enumerations

enum  SegSide { kLeft_SegSide = -1 , kOn_SegSide = 0 , kRight_SegSide = 1 , kNA_SegSide = 2 }
 

Functions

static bool between_closed_open (double a, double b, double c, double tolerance=0.0, bool xformToleranceToX=false)
 
static bool between_closed (double a, double b, double c, double tolerance=0.0, bool xformToleranceToX=false)
 
static bool nearly_zero (double x, double tolerance=kNearlyZero)
 
static bool nearly_equal (double x, double y, double tolerance=kNearlyZero, bool xformToleranceToX=false)
 
static double sign_of (const double &val)
 
static bool is_colinear (const SkPoint pts[3])
 
static void init_distances (DFData *data, int size)
 
static void add_line (const SkPoint pts[2], PathSegmentArray *segments)
 
static void add_quad (const SkPoint pts[3], PathSegmentArray *segments)
 
static void add_cubic (const SkPoint pts[4], PathSegmentArray *segments)
 
static float calculate_nearest_point_for_quad (const PathSegment &segment, const DPoint &xFormPt)
 
void precomputation_for_row (RowData *rowData, const PathSegment &segment, const SkPoint &pointLeft, const SkPoint &pointRight)
 
SegSide calculate_side_of_quad (const PathSegment &segment, const SkPoint &point, const DPoint &xFormPt, const RowData &rowData)
 
static float distance_to_segment (const SkPoint &point, const PathSegment &segment, const RowData &rowData, SegSide *side)
 
static void calculate_distance_field_data (PathSegmentArray *segments, DFData *dataPtr, int width, int height)
 
template<int distanceMagnitude>
static unsigned char pack_distance_field_val (float dist)
 
bool GrGenerateDistanceFieldFromPath (unsigned char *distanceField, const SkPath &path, const SkMatrix &drawMatrix, int width, int height, size_t rowBytes)
 

Variables

static const double kClose = (SK_Scalar1 / 16.0)
 
static const double kCloseSqd = kClose * kClose
 
static const double kNearlyZero = (SK_Scalar1 / (1 << 18))
 
static const double kTangentTolerance = (SK_Scalar1 / (1 << 11))
 
static const float kConicTolerance = 0.25f
 

Typedef Documentation

◆ PathSegmentArray

Definition at line 230 of file GrDistanceFieldGenFromVector.cpp.

Enumeration Type Documentation

◆ SegSide

enum SegSide

If a scanline (a row of texel) cross from the kRight_SegSide of a segment to the kLeft_SegSide, the winding score should add 1. And winding score should subtract 1 if the scanline cross from kLeft_SegSide to kRight_SegSide. Always return kNA_SegSide if the scanline does not cross over the segment. Winding score should be zero in this case. You can get the winding number for each texel of the scanline by adding the winding score from left to right. Assuming we always start from outside, so the winding number should always start from zero.


| | | | ...R|L......L|R.....L|R......R|L..... <= Scanline & side of segment |+1 |-1 |-1 |+1 <= Winding score 0 | 1 ^ 0 ^ -1 |0 <= Winding number |________| |________|

.......NA................NA.......... 0 0

Enumerator
kLeft_SegSide 
kOn_SegSide 
kRight_SegSide 
kNA_SegSide 

Definition at line 61 of file GrDistanceFieldGenFromVector.cpp.

Function Documentation

◆ add_cubic()

static void add_cubic ( const SkPoint  pts[4],
PathSegmentArray segments 
)
inlinestatic

Definition at line 377 of file GrDistanceFieldGenFromVector.cpp.

378 {
381 int count = quads.size();
382 for (int q = 0; q < count; q += 3) {
383 add_quad(&quads[q], segments);
384 }
385}
int count
static void add_quad(const SkPoint pts[3], PathSegmentArray *segments)
#define SK_Scalar1
Definition SkScalar.h:18
int size() const
Definition SkTArray.h:416
void convertCubicToQuads(const SkPoint p[4], SkScalar tolScale, skia_private::TArray< SkPoint, true > *quads)

◆ add_line()

static void add_line ( const SkPoint  pts[2],
PathSegmentArray segments 
)
inlinestatic

Definition at line 347 of file GrDistanceFieldGenFromVector.cpp.

347 {
348 segments->push_back();
349 segments->back().fType = PathSegment::kLine;
350 segments->back().fPts[0] = pts[0];
351 segments->back().fPts[1] = pts[1];
352
353 segments->back().init();
354}

◆ add_quad()

static void add_quad ( const SkPoint  pts[3],
PathSegmentArray segments 
)
inlinestatic

Definition at line 356 of file GrDistanceFieldGenFromVector.cpp.

356 {
357 if (SkPointPriv::DistanceToSqd(pts[0], pts[1]) < kCloseSqd ||
358 SkPointPriv::DistanceToSqd(pts[1], pts[2]) < kCloseSqd ||
359 is_colinear(pts)) {
360 if (pts[0] != pts[2]) {
361 SkPoint line_pts[2];
362 line_pts[0] = pts[0];
363 line_pts[1] = pts[2];
364 add_line(line_pts, segments);
365 }
366 } else {
367 segments->push_back();
368 segments->back().fType = PathSegment::kQuad;
369 segments->back().fPts[0] = pts[0];
370 segments->back().fPts[1] = pts[1];
371 segments->back().fPts[2] = pts[2];
372
373 segments->back().init();
374 }
375}
static bool is_colinear(const SkPoint pts[3])
static void add_line(const SkPoint pts[2], PathSegmentArray *segments)
static const double kCloseSqd
static SkScalar DistanceToSqd(const SkPoint &pt, const SkPoint &a)
Definition SkPointPriv.h:48

◆ between_closed()

static bool between_closed ( double  a,
double  b,
double  c,
double  tolerance = 0.0,
bool  xformToleranceToX = false 
)
inlinestatic

Definition at line 159 of file GrDistanceFieldGenFromVector.cpp.

161 {
162 SkASSERT(tolerance >= 0.0);
163 double tolB = tolerance;
164 double tolC = tolerance;
165
166 if (xformToleranceToX) {
167 tolB = tolerance / sqrt(4.0 * b * b + 1.0);
168 tolC = tolerance / sqrt(4.0 * c * c + 1.0);
169 }
170 return b < c ? (a >= b - tolB && a <= c + tolC) :
171 (a >= c - tolC && a <= b + tolB);
172}
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool b
struct MyStruct a[10]
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition SkVx.h:706

◆ between_closed_open()

static bool between_closed_open ( double  a,
double  b,
double  c,
double  tolerance = 0.0,
bool  xformToleranceToX = false 
)
inlinestatic

Definition at line 136 of file GrDistanceFieldGenFromVector.cpp.

138 {
139 SkASSERT(tolerance >= 0.0);
140 double tolB = tolerance;
141 double tolC = tolerance;
142
143 if (xformToleranceToX) {
144 // Canonical space is y = x^2 and the derivative of x^2 is 2x.
145 // So the slope of the tangent line at point (x, x^2) is 2x.
146 //
147 // /|
148 // sqrt(2x * 2x + 1 * 1) / | 2x
149 // /__|
150 // 1
151 tolB = tolerance / sqrt(4.0 * b * b + 1.0);
152 tolC = tolerance / sqrt(4.0 * c * c + 1.0);
153 }
154 return b < c ? (a >= b - tolB && a < c - tolC) :
155 (a >= c - tolC && a < b - tolB);
156}

◆ calculate_distance_field_data()

static void calculate_distance_field_data ( PathSegmentArray segments,
DFData dataPtr,
int  width,
int  height 
)
static

Definition at line 624 of file GrDistanceFieldGenFromVector.cpp.

626 {
627 int count = segments->size();
628 // for each segment
629 for (int a = 0; a < count; ++a) {
630 PathSegment& segment = (*segments)[a];
631 const SkRect& segBB = segment.fBoundingBox;
632 // get the bounding box, outset by distance field pad, and clip to total bounds
634 int startColumn = (int)paddedBB.fLeft;
635 int endColumn = SkScalarCeilToInt(paddedBB.fRight);
636
637 int startRow = (int)paddedBB.fTop;
638 int endRow = SkScalarCeilToInt(paddedBB.fBottom);
639
640 SkASSERT((startColumn >= 0) && "StartColumn < 0!");
641 SkASSERT((endColumn <= width) && "endColumn > width!");
642 SkASSERT((startRow >= 0) && "StartRow < 0!");
643 SkASSERT((endRow <= height) && "EndRow > height!");
644
645 // Clip inside the distance field to avoid overflow
646 startColumn = std::max(startColumn, 0);
647 endColumn = std::min(endColumn, width);
648 startRow = std::max(startRow, 0);
649 endRow = std::min(endRow, height);
650
651 // for each row in the padded bounding box
652 for (int row = startRow; row < endRow; ++row) {
653 SegSide prevSide = kNA_SegSide; // track side for winding count
654 const float pY = row + 0.5f; // offset by 1/2? why?
655 RowData rowData;
656
657 const SkPoint pointLeft = SkPoint::Make((SkScalar)startColumn, pY);
658 const SkPoint pointRight = SkPoint::Make((SkScalar)endColumn, pY);
659
660 // if this is a row inside the original segment bounding box
661 if (between_closed_open(pY, segBB.fTop, segBB.fBottom)) {
662 // compute intersections with the row
663 precomputation_for_row(&rowData, segment, pointLeft, pointRight);
664 }
665
666 // adjust distances and windings in each column based on the row calculation
667 for (int col = startColumn; col < endColumn; ++col) {
668 int idx = (row * width) + col;
669
670 const float pX = col + 0.5f;
671 const SkPoint point = SkPoint::Make(pX, pY);
672
673 const float distSq = dataPtr[idx].fDistSq;
674
675 // Optimization for not calculating some points.
676 int dilation = distSq < 1.5f * 1.5f ? 1 :
677 distSq < 2.5f * 2.5f ? 2 :
678 distSq < 3.5f * 3.5f ? 3 : SK_DistanceFieldPad;
679 if (dilation < SK_DistanceFieldPad &&
680 !segBB.roundOut().makeOutset(dilation, dilation).contains(col, row)) {
681 continue;
682 }
683
685 int deltaWindingScore = 0;
686 float currDistSq = distance_to_segment(point, segment, rowData, &side);
687 if (prevSide == kLeft_SegSide && side == kRight_SegSide) {
688 deltaWindingScore = -1;
689 } else if (prevSide == kRight_SegSide && side == kLeft_SegSide) {
690 deltaWindingScore = 1;
691 }
692
693 prevSide = side;
694
695 if (currDistSq < distSq) {
696 dataPtr[idx].fDistSq = currDistSq;
697 }
698
699 dataPtr[idx].fDeltaWindingScore += deltaWindingScore;
700 }
701 }
702 }
703}
void precomputation_for_row(RowData *rowData, const PathSegment &segment, const SkPoint &pointLeft, const SkPoint &pointRight)
static float distance_to_segment(const SkPoint &point, const PathSegment &segment, const RowData &rowData, SegSide *side)
static bool between_closed_open(double a, double b, double c, double tolerance=0.0, bool xformToleranceToX=false)
#define SK_DistanceFieldPad
static int side(double x)
#define SkScalarCeilToInt(x)
Definition SkScalar.h:36
Type::kYUV Type::kRGBA() int(0.7 *637)
float SkScalar
Definition extension.cpp:12
int32_t height
int32_t width
static constexpr SkPoint Make(float x, float y)
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkRect makeOutset(float dx, float dy) const
Definition SkRect.h:1002
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15

◆ calculate_nearest_point_for_quad()

static float calculate_nearest_point_for_quad ( const PathSegment segment,
const DPoint &  xFormPt 
)
static

Definition at line 387 of file GrDistanceFieldGenFromVector.cpp.

389 {
390 static const float kThird = 0.33333333333f;
391 static const float kTwentySeventh = 0.037037037f;
392
393 const float a = 0.5f - (float)xFormPt.fY;
394 const float b = -0.5f * (float)xFormPt.fX;
395
396 const float a3 = a * a * a;
397 const float b2 = b * b;
398
399 const float c = (b2 * 0.25f) + (a3 * kTwentySeventh);
400
401 if (c >= 0.f) {
402 const float sqrtC = sqrt(c);
403 const float result = (float)cbrt((-b * 0.5f) + sqrtC) + (float)cbrt((-b * 0.5f) - sqrtC);
404 return result;
405 } else {
406 const float cosPhi = (float)sqrt((b2 * 0.25f) * (-27.f / a3)) * ((b > 0) ? -1.f : 1.f);
407 const float phi = (float)acos(cosPhi);
408 float result;
409 if (xFormPt.fX > 0.f) {
410 result = 2.f * (float)sqrt(-a * kThird) * (float)cos(phi * kThird);
411 if (!between_closed(result, segment.fP0T.fX, segment.fP2T.fX)) {
412 result = 2.f * (float)sqrt(-a * kThird) * (float)cos((phi * kThird) + (SK_ScalarPI * 2.f * kThird));
413 }
414 } else {
415 result = 2.f * (float)sqrt(-a * kThird) * (float)cos((phi * kThird) + (SK_ScalarPI * 2.f * kThird));
416 if (!between_closed(result, segment.fP0T.fX, segment.fP2T.fX)) {
417 result = 2.f * (float)sqrt(-a * kThird) * (float)cos(phi * kThird);
418 }
419 }
420 return result;
421 }
422}
static bool between_closed(double a, double b, double c, double tolerance=0.0, bool xformToleranceToX=false)
#define SK_ScalarPI
Definition SkScalar.h:21
GAsyncResult * result

◆ calculate_side_of_quad()

SegSide calculate_side_of_quad ( const PathSegment segment,
const SkPoint point,
const DPoint &  xFormPt,
const RowData rowData 
)

Definition at line 503 of file GrDistanceFieldGenFromVector.cpp.

507 {
509
511 side = (SegSide)(int)(sign_of(xFormPt.fY - rowData.fYAtIntersection) * rowData.fQuadXDirection);
512 }
514 const double p1 = rowData.fXAtIntersection1;
515 const double p2 = rowData.fXAtIntersection2;
516
517 int signP1 = (int)sign_of(p1 - xFormPt.fX);
518 bool includeP1 = true;
519 bool includeP2 = true;
520
521 if (rowData.fScanlineXDirection == 1) {
522 if ((rowData.fQuadXDirection == -1 && segment.fPts[0].fY <= point.fY &&
523 nearly_equal(segment.fP0T.fX, p1, segment.fNearlyZeroScaled, true)) ||
524 (rowData.fQuadXDirection == 1 && segment.fPts[2].fY <= point.fY &&
525 nearly_equal(segment.fP2T.fX, p1, segment.fNearlyZeroScaled, true))) {
526 includeP1 = false;
527 }
528 if ((rowData.fQuadXDirection == -1 && segment.fPts[2].fY <= point.fY &&
529 nearly_equal(segment.fP2T.fX, p2, segment.fNearlyZeroScaled, true)) ||
530 (rowData.fQuadXDirection == 1 && segment.fPts[0].fY <= point.fY &&
531 nearly_equal(segment.fP0T.fX, p2, segment.fNearlyZeroScaled, true))) {
532 includeP2 = false;
533 }
534 }
535
536 if (includeP1 && between_closed(p1, segment.fP0T.fX, segment.fP2T.fX,
537 segment.fNearlyZeroScaled, true)) {
538 side = (SegSide)(signP1 * rowData.fQuadXDirection);
539 }
540 if (includeP2 && between_closed(p2, segment.fP0T.fX, segment.fP2T.fX,
541 segment.fNearlyZeroScaled, true)) {
542 int signP2 = (int)sign_of(p2 - xFormPt.fX);
543 if (side == kNA_SegSide || signP2 == 1) {
544 side = (SegSide)(-signP2 * rowData.fQuadXDirection);
545 }
546 }
547 } else if (RowData::kTangentLine == rowData.fIntersectionType) {
548 // The scanline is the tangent line of current quadratic segment.
549
550 const double p = rowData.fXAtIntersection1;
551 int signP = (int)sign_of(p - xFormPt.fX);
552 if (rowData.fScanlineXDirection == 1) {
553 // The path start or end at the tangent point.
554 if (segment.fPts[0].fY == point.fY) {
555 side = (SegSide)(signP);
556 } else if (segment.fPts[2].fY == point.fY) {
557 side = (SegSide)(-signP);
558 }
559 }
560 }
561
562 return side;
563}
static double sign_of(const double &val)
static bool nearly_equal(double x, double y, double tolerance=kNearlyZero, bool xformToleranceToX=false)
enum RowData::IntersectionType fIntersectionType
float fY
y-axis value

◆ distance_to_segment()

static float distance_to_segment ( const SkPoint point,
const PathSegment segment,
const RowData rowData,
SegSide side 
)
static

Definition at line 565 of file GrDistanceFieldGenFromVector.cpp.

568 {
569 SkASSERT(side);
570
571 const DPoint xformPt = segment.fXformMatrix.mapPoint(point);
572
573 if (segment.fType == PathSegment::kLine) {
575
576 if (between_closed(xformPt.fX, segment.fP0T.fX, segment.fP2T.fX)) {
577 result = (float)(xformPt.fY * xformPt.fY);
578 } else if (xformPt.fX < segment.fP0T.fX) {
579 result = (float)(xformPt.fX * xformPt.fX + xformPt.fY * xformPt.fY);
580 } else {
581 result = (float)((xformPt.fX - segment.fP2T.fX) * (xformPt.fX - segment.fP2T.fX)
582 + xformPt.fY * xformPt.fY);
583 }
584
585 if (between_closed_open(point.fY, segment.fBoundingBox.fTop,
586 segment.fBoundingBox.fBottom)) {
587 *side = (SegSide)(int)sign_of(xformPt.fY);
588 } else {
589 *side = kNA_SegSide;
590 }
591 return result;
592 } else {
594
595 const float nearestPoint = calculate_nearest_point_for_quad(segment, xformPt);
596
597 float dist;
598
599 if (between_closed(nearestPoint, segment.fP0T.fX, segment.fP2T.fX)) {
600 DPoint x = { nearestPoint, nearestPoint * nearestPoint };
601 dist = (float)xformPt.distanceSquared(x);
602 } else {
603 const float distToB0T = (float)xformPt.distanceSquared(segment.fP0T);
604 const float distToB2T = (float)xformPt.distanceSquared(segment.fP2T);
605
606 if (distToB0T < distToB2T) {
607 dist = distToB0T;
608 } else {
609 dist = distToB2T;
610 }
611 }
612
613 if (between_closed_open(point.fY, segment.fBoundingBox.fTop,
614 segment.fBoundingBox.fBottom)) {
615 *side = calculate_side_of_quad(segment, point, xformPt, rowData);
616 } else {
617 *side = kNA_SegSide;
618 }
619
620 return (float)(dist * segment.fScalingFactorSqd);
621 }
622}
SegSide calculate_side_of_quad(const PathSegment &segment, const SkPoint &point, const DPoint &xFormPt, const RowData &rowData)
static float calculate_nearest_point_for_quad(const PathSegment &segment, const DPoint &xFormPt)
DPoint mapPoint(const SkPoint &src) const
enum PathSegment::@376 fType
double x
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17

◆ GrGenerateDistanceFieldFromPath()

bool GrGenerateDistanceFieldFromPath ( unsigned char *  distanceField,
const SkPath path,
const SkMatrix viewMatrix,
int  width,
int  height,
size_t  rowBytes 
)

Given a vector path, generate the associated distance field.

Parameters
distanceFieldThe distance field to be generated. Should already be allocated by the client with the padding defined in "SkDistanceFieldGen.h".
pathThe path we're using to generate the distance field.
matrixTransformation matrix for path.
widthWidth of the distance field.
heightHeight of the distance field.
rowBytesSize of each row in the distance field, in bytes.

Definition at line 721 of file GrDistanceFieldGenFromVector.cpp.

723 {
724 SkASSERT(distanceField);
725
726 // transform to device space, then:
727 // translate path to offset (SK_DistanceFieldPad, SK_DistanceFieldPad)
728 SkMatrix dfMatrix(drawMatrix);
729 dfMatrix.postTranslate(SK_DistanceFieldPad, SK_DistanceFieldPad);
730
731#ifdef SK_DEBUG
732 SkPath xformPath;
733 path.transform(dfMatrix, &xformPath);
734 SkIRect pathBounds = xformPath.getBounds().roundOut();
735 SkIRect expectPathBounds = SkIRect::MakeWH(width, height);
736#endif
737
738 SkASSERT(expectPathBounds.isEmpty() ||
739 expectPathBounds.contains(pathBounds.fLeft, pathBounds.fTop));
740 SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() ||
741 expectPathBounds.contains(pathBounds));
742
743// TODO: restore when Simplify() is working correctly
744// see https://bugs.chromium.org/p/skia/issues/detail?id=9732
745// SkPath simplifiedPath;
746 SkPath workingPath;
747// if (Simplify(path, &simplifiedPath)) {
748// workingPath = simplifiedPath;
749// } else {
750 workingPath = path;
751// }
752 // only even-odd and inverse even-odd supported
753 if (!IsDistanceFieldSupportedFillType(workingPath.getFillType())) {
754 return false;
755 }
756
757 // transform to device space + SDF offset
758 // TODO: remove degenerate segments while doing this?
759 workingPath.transform(dfMatrix);
760
761 SkDEBUGCODE(pathBounds = workingPath.getBounds().roundOut());
762 SkASSERT(expectPathBounds.isEmpty() ||
763 expectPathBounds.contains(pathBounds.fLeft, pathBounds.fTop));
764 SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() ||
765 expectPathBounds.contains(pathBounds));
766
767 // create temp data
768 size_t dataSize = width * height * sizeof(DFData);
769 SkAutoSMalloc<1024> dfStorage(dataSize);
770 DFData* dataPtr = (DFData*) dfStorage.get();
771
772 // create initial distance data (init to "far away")
773 init_distances(dataPtr, width * height);
774
775 // polygonize path into line and quad segments
776 SkPathEdgeIter iter(workingPath);
778 while (auto e = iter.next()) {
779 switch (e.fEdge) {
780 case SkPathEdgeIter::Edge::kLine: {
781 add_line(e.fPts, &segments);
782 break;
783 }
784 case SkPathEdgeIter::Edge::kQuad:
785 add_quad(e.fPts, &segments);
786 break;
787 case SkPathEdgeIter::Edge::kConic: {
788 SkScalar weight = iter.conicWeight();
790 const SkPoint* quadPts = converter.computeQuads(e.fPts, weight, kConicTolerance);
791 for (int i = 0; i < converter.countQuads(); ++i) {
792 add_quad(quadPts + 2*i, &segments);
793 }
794 break;
795 }
796 case SkPathEdgeIter::Edge::kCubic: {
797 add_cubic(e.fPts, &segments);
798 break;
799 }
800 }
801 }
802
803 // do all the work
804 calculate_distance_field_data(&segments, dataPtr, width, height);
805
806 // adjust distance based on winding
807 for (int row = 0; row < height; ++row) {
808 using DFSign = int;
809 constexpr DFSign kInside = -1;
810 constexpr DFSign kOutside = 1;
811
812 int windingNumber = 0; // Winding number start from zero for each scanline
813 for (int col = 0; col < width; ++col) {
814 int idx = (row * width) + col;
815 windingNumber += dataPtr[idx].fDeltaWindingScore;
816
817 DFSign dfSign;
818 switch (workingPath.getFillType()) {
820 dfSign = windingNumber ? kInside : kOutside;
821 break;
823 dfSign = windingNumber ? kOutside : kInside;
824 break;
826 dfSign = (windingNumber % 2) ? kInside : kOutside;
827 break;
829 dfSign = (windingNumber % 2) ? kOutside : kInside;
830 break;
831 }
832
833 const float miniDist = sqrt(dataPtr[idx].fDistSq);
834 const float dist = dfSign * miniDist;
835
836 unsigned char pixelVal = pack_distance_field_val<SK_DistanceFieldMagnitude>(dist);
837
838 distanceField[(row * rowBytes) + col] = pixelVal;
839 }
840
841 // The winding number at the end of a scanline should be zero.
842 if (windingNumber != 0) {
843 SkDEBUGFAIL("Winding number should be zero at the end of a scan line.");
844 // Fallback to use SkPath::contains to determine the sign of pixel in release build.
845 for (int col = 0; col < width; ++col) {
846 int idx = (row * width) + col;
847 DFSign dfSign = workingPath.contains(col + 0.5, row + 0.5) ? kInside : kOutside;
848 const float miniDist = sqrt(dataPtr[idx].fDistSq);
849 const float dist = dfSign * miniDist;
850
851 unsigned char pixelVal = pack_distance_field_val<SK_DistanceFieldMagnitude>(dist);
852
853 distanceField[(row * rowBytes) + col] = pixelVal;
854 }
855 continue;
856 }
857 }
858 return true;
859}
static void init_distances(DFData *data, int size)
static void calculate_distance_field_data(PathSegmentArray *segments, DFData *dataPtr, int width, int height)
static const float kConicTolerance
static void add_cubic(const SkPoint pts[4], PathSegmentArray *segments)
bool IsDistanceFieldSupportedFillType(SkPathFillType fFillType)
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
SkPathFillType getFillType() const
Definition SkPath.h:230
const SkRect & getBounds() const
Definition SkPath.cpp:420
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition SkPath.cpp:1647
bool contains(SkScalar x, SkScalar y) const
Definition SkPath.cpp:3054
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
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
bool isEmpty() const
Definition SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
void roundOut(SkIRect *dst) const
Definition SkRect.h:1241

◆ init_distances()

static void init_distances ( DFData data,
int  size 
)
static

Definition at line 336 of file GrDistanceFieldGenFromVector.cpp.

336 {
337 DFData* currData = data;
338
339 for (int i = 0; i < size; ++i) {
340 // init distance to "far away"
342 currData->fDeltaWindingScore = 0;
343 ++currData;
344 }
345}
#define SK_DistanceFieldMagnitude
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259

◆ is_colinear()

static bool is_colinear ( const SkPoint  pts[3])
static

Definition at line 193 of file GrDistanceFieldGenFromVector.cpp.

193 {
194 return nearly_zero((pts[1].fY - pts[0].fY) * (pts[1].fX - pts[2].fX) -
195 (pts[1].fY - pts[2].fY) * (pts[1].fX - pts[0].fX), kCloseSqd);
196}
static bool nearly_zero(double x, double tolerance=kNearlyZero)

◆ nearly_equal()

static bool nearly_equal ( double  x,
double  y,
double  tolerance = kNearlyZero,
bool  xformToleranceToX = false 
)
inlinestatic

Definition at line 179 of file GrDistanceFieldGenFromVector.cpp.

181 {
182 SkASSERT(tolerance >= 0.0);
183 if (xformToleranceToX) {
184 tolerance = tolerance / sqrt(4.0 * y * y + 1.0);
185 }
186 return fabs(x - y) <= tolerance;
187}
double y

◆ nearly_zero()

static bool nearly_zero ( double  x,
double  tolerance = kNearlyZero 
)
inlinestatic

Definition at line 174 of file GrDistanceFieldGenFromVector.cpp.

174 {
175 SkASSERT(tolerance >= 0.0);
176 return fabs(x) <= tolerance;
177}

◆ pack_distance_field_val()

template<int distanceMagnitude>
static unsigned char pack_distance_field_val ( float  dist)
static

Definition at line 706 of file GrDistanceFieldGenFromVector.cpp.

706 {
707 // The distance field is constructed as unsigned char values, so that the zero value is at 128,
708 // Beside 128, we have 128 values in range [0, 128), but only 127 values in range (128, 255].
709 // So we multiply distanceMagnitude by 127/128 at the latter range to avoid overflow.
710 dist = SkTPin<float>(-dist, -distanceMagnitude, distanceMagnitude * 127.0f / 128.0f);
711
712 // Scale into the positive range for unsigned distance.
713 dist += distanceMagnitude;
714
715 // Scale into unsigned char range.
716 // Round to place negative and positive values as equally as possible around 128
717 // (which represents zero).
718 return (unsigned char)SkScalarRoundToInt(dist / (2 * distanceMagnitude) * 256.0f);
719}
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37

◆ precomputation_for_row()

void precomputation_for_row ( RowData rowData,
const PathSegment segment,
const SkPoint pointLeft,
const SkPoint pointRight 
)

Definition at line 450 of file GrDistanceFieldGenFromVector.cpp.

451 {
452 if (segment.fType != PathSegment::kQuad) {
453 return;
454 }
455
456 const DPoint& xFormPtLeft = segment.fXformMatrix.mapPoint(pointLeft);
457 const DPoint& xFormPtRight = segment.fXformMatrix.mapPoint(pointRight);
458
459 rowData->fQuadXDirection = (int)sign_of(segment.fP2T.fX - segment.fP0T.fX);
460 rowData->fScanlineXDirection = (int)sign_of(xFormPtRight.fX - xFormPtLeft.fX);
461
462 const double x1 = xFormPtLeft.fX;
463 const double y1 = xFormPtLeft.fY;
464 const double x2 = xFormPtRight.fX;
465 const double y2 = xFormPtRight.fY;
466
467 if (nearly_equal(x1, x2, segment.fNearlyZeroScaled, true)) {
469 rowData->fYAtIntersection = x1 * x1;
470 rowData->fScanlineXDirection = 0;
471 return;
472 }
473
474 // Line y = mx + b
475 const double m = (y2 - y1) / (x2 - x1);
476 const double b = -m * x1 + y1;
477
478 const double m2 = m * m;
479 const double c = m2 + 4.0 * b;
480
481 const double tol = 4.0 * segment.fTangentTolScaledSqd / (m2 + 1.0);
482
483 // Check if the scanline is the tangent line of the curve,
484 // and the curve start or end at the same y-coordinate of the scanline
485 if ((rowData->fScanlineXDirection == 1 &&
486 (segment.fPts[0].fY == pointLeft.fY ||
487 segment.fPts[2].fY == pointLeft.fY)) &&
488 nearly_zero(c, tol)) {
490 rowData->fXAtIntersection1 = m / 2.0;
491 rowData->fXAtIntersection2 = m / 2.0;
492 } else if (c <= 0.0) {
494 return;
495 } else {
497 const double d = sqrt(c);
498 rowData->fXAtIntersection1 = (m + d) / 2.0;
499 rowData->fXAtIntersection2 = (m - d) / 2.0;
500 }
501}
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19

◆ sign_of()

static double sign_of ( const double &  val)
inlinestatic

Definition at line 189 of file GrDistanceFieldGenFromVector.cpp.

189 {
190 return std::copysign(1, val);
191}

Variable Documentation

◆ kClose

const double kClose = (SK_Scalar1 / 16.0)
static

Definition at line 129 of file GrDistanceFieldGenFromVector.cpp.

◆ kCloseSqd

const double kCloseSqd = kClose * kClose
static

Definition at line 130 of file GrDistanceFieldGenFromVector.cpp.

◆ kConicTolerance

const float kConicTolerance = 0.25f
static

Definition at line 133 of file GrDistanceFieldGenFromVector.cpp.

◆ kNearlyZero

const double kNearlyZero = (SK_Scalar1 / (1 << 18))
static

Definition at line 131 of file GrDistanceFieldGenFromVector.cpp.

◆ kTangentTolerance

const double kTangentTolerance = (SK_Scalar1 / (1 << 11))
static

Definition at line 132 of file GrDistanceFieldGenFromVector.cpp.