55
66#include < skia/core/SkPath.h>
77#include < skia/pathops/SkPathOps.h>
8+ #include " ../core/arithmetics.hpp"
89#include " ../core/Vector2.hpp"
910#include " ../core/edge-segments.h"
1011#include " ../core/Contour.h"
@@ -22,10 +23,11 @@ Point2 pointFromSkiaPoint(const SkPoint p) {
2223void shapeToSkiaPath (SkPath &skPath, const Shape &shape) {
2324 for (std::vector<Contour>::const_iterator contour = shape.contours .begin (); contour != shape.contours .end (); ++contour) {
2425 if (!contour->edges .empty ()) {
25- skPath.moveTo (pointToSkiaPoint (contour->edges .front ()->point (0 )));
26- for (std::vector<EdgeHolder>::const_iterator edge = contour->edges .begin (); edge != contour->edges .end (); ++edge) {
27- const Point2 *p = (*edge)->controlPoints ();
28- switch ((*edge)->type ()) {
26+ const EdgeSegment *edge = contour->edges .back ();
27+ skPath.moveTo (pointToSkiaPoint (*edge->controlPoints ()));
28+ for (std::vector<EdgeHolder>::const_iterator nextEdge = contour->edges .begin (); nextEdge != contour->edges .end (); edge = *nextEdge++) {
29+ const Point2 *p = edge->controlPoints ();
30+ switch (edge->type ()) {
2931 case (int ) LinearSegment::EDGE_TYPE:
3032 skPath.lineTo (pointToSkiaPoint (p[1 ]));
3133 break ;
@@ -78,13 +80,47 @@ void shapeFromSkiaPath(Shape &shape, const SkPath &skPath) {
7880 shape.contours .pop_back ();
7981}
8082
83+ static void pruneCrossedQuadrilaterals (Shape &shape) {
84+ int n = 0 ;
85+ for (int i = 0 ; i < (int ) shape.contours .size (); ++i) {
86+ Contour &contour = shape.contours [i];
87+ if (
88+ contour.edges .size () == 4 &&
89+ contour.edges [0 ]->type () == (int ) LinearSegment::EDGE_TYPE &&
90+ contour.edges [1 ]->type () == (int ) LinearSegment::EDGE_TYPE &&
91+ contour.edges [2 ]->type () == (int ) LinearSegment::EDGE_TYPE &&
92+ contour.edges [3 ]->type () == (int ) LinearSegment::EDGE_TYPE && (
93+ sign (crossProduct (contour.edges [0 ]->direction (1 ), contour.edges [1 ]->direction (0 )))+
94+ sign (crossProduct (contour.edges [1 ]->direction (1 ), contour.edges [2 ]->direction (0 )))+
95+ sign (crossProduct (contour.edges [2 ]->direction (1 ), contour.edges [3 ]->direction (0 )))+
96+ sign (crossProduct (contour.edges [3 ]->direction (1 ), contour.edges [0 ]->direction (0 )))
97+ ) == 0
98+ ) {
99+ contour.edges .clear ();
100+ } else {
101+ if (i != n) {
102+ #ifdef MSDFGEN_USE_CPP11
103+ shape.contours [n] = (Contour &&) contour;
104+ #else
105+ shape.contours [n] = contour;
106+ #endif
107+ }
108+ ++n;
109+ }
110+ }
111+ shape.contours .resize (n);
112+ }
113+
81114bool resolveShapeGeometry (Shape &shape) {
82115 SkPath skPath;
116+ shape.normalize ();
83117 shapeToSkiaPath (skPath, shape);
84118 if (!Simplify (skPath, &skPath))
85119 return false ;
86120 // Skia's AsWinding doesn't seem to work for unknown reasons
87121 shapeFromSkiaPath (shape, skPath);
122+ // In some rare cases, Skia produces tiny residual crossed quadrilateral contours, which are not valid geometry, so they must be removed.
123+ pruneCrossedQuadrilaterals (shape);
88124 shape.orientContours ();
89125 return true ;
90126}
0 commit comments