Skip to content

Commit 5dc5f62

Browse files
committed
Skia bug workaround, savePng crash fix
1 parent 75813f3 commit 5dc5f62

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

ext/resolve-shape-geometry.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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) {
2223
void 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+
81114
bool 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
}

ext/save-png.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class PngGuard {
2222
inline PngGuard(png_structp png, png_infop info) : png(png), info(info), file(NULL) { }
2323
inline ~PngGuard() {
2424
png_destroy_write_struct(&png, &info);
25-
fclose(file);
25+
if (file)
26+
fclose(file);
2627
}
2728
inline void setFile(FILE *file) {
2829
this->file = file;

0 commit comments

Comments
 (0)