Skip to content

Commit bdb0782

Browse files
committed
Fix some NaN in svg paths
This is a quick commit to fix a few NaN issues in SVG paths. This commit is not suitable for a PR, as it was created for a temporary use case. More context: opentypejs#797
1 parent aa8ad76 commit bdb0782

File tree

6 files changed

+53
-32
lines changed

6 files changed

+53
-32
lines changed

src/font.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ Font.prototype.forEachGlyph = function(text, x, y, fontSize, options, callback)
380380
y = y !== undefined ? y : 0;
381381
fontSize = fontSize !== undefined ? fontSize : 72;
382382
options = Object.assign({}, this.defaultRenderOptions, options);
383-
const fontScale = 1 / this.unitsPerEm * fontSize;
383+
const fontScale = 1 / (this.unitsPerEm || 1000) * fontSize;
384384
const glyphs = this.stringToGlyphs(text, options);
385385
let kerningLookups;
386386
if (options.kerning) {

src/glyph.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ Glyph.prototype.drawPoints = function(ctx, x, y, fontSize, options, font) {
399399
x = x !== undefined ? x : 0;
400400
y = y !== undefined ? y : 0;
401401
fontSize = fontSize !== undefined ? fontSize : 24;
402-
const scale = 1 / this.path.unitsPerEm * fontSize;
402+
const scale = 1 / (this.path.unitsPerEm || 1000) * fontSize;
403403

404404
const blueCircles = [];
405405
const redCircles = [];
@@ -446,7 +446,7 @@ Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
446446
x = x !== undefined ? x : 0;
447447
y = y !== undefined ? y : 0;
448448
fontSize = fontSize !== undefined ? fontSize : 24;
449-
scale = 1 / this.path.unitsPerEm * fontSize;
449+
scale = 1 / (this.path.unitsPerEm || 1000) * fontSize;
450450
ctx.lineWidth = 1;
451451

452452
// Draw the origin

src/hintingtt.mjs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ const xUnitVector = {
224224
const rpdx = rpx + d * pv.x;
225225
const rpdy = rpy + d * pv.y;
226226

227-
p.x = rpdx + (p.y - rpdy) / pv.normalSlope;
227+
p.x = (isFinite(pv.normalSlope) && pv.normalSlope !== 0) ? rpdx + (p.y - rpdy) / pv.normalSlope : rpdx;
228228
},
229229

230230
// Slope of vector line.
@@ -366,8 +366,8 @@ function UnitVector(x, y) {
366366
this.x = x;
367367
this.y = y;
368368
this.axis = undefined;
369-
this.slope = y / x;
370-
this.normalSlope = -x / y;
369+
this.slope = x === 0 ? (y === 0 ? 0 : Infinity) : y / x;
370+
this.normalSlope = y === 0 ? (x === 0 ? 0 : Infinity) : -x / y;
371371
Object.freeze(this);
372372
}
373373

@@ -440,7 +440,8 @@ UnitVector.prototype.setRelative = function(p, rp, d, pv, org) {
440440
const px = p.x;
441441
const py = p.y;
442442

443-
p.x = (fvs * px - pvns * rpdx + rpdy - py) / (fvs - pvns);
443+
const denom = fvs - pvns;
444+
p.x = denom === 0 ? px : (fvs * px - pvns * rpdx + rpdy - py) / denom;
444445
p.y = fvs * (p.x - px) + py;
445446
};
446447

@@ -1109,8 +1110,14 @@ function ISECT(state)
11091110
const f1 = x1 * y2 - y1 * x2;
11101111
const f2 = x3 * y4 - y3 * x4;
11111112

1112-
p.x = (f1 * (x3 - x4) - f2 * (x1 - x2)) / div;
1113-
p.y = (f1 * (y3 - y4) - f2 * (y1 - y2)) / div;
1113+
if (div === 0) {
1114+
// Lines are parallel, use midpoint
1115+
p.x = (x1 + x2) / 2;
1116+
p.y = (y1 + y2) / 2;
1117+
} else {
1118+
p.x = (f1 * (x3 - x4) - f2 * (x1 - x2)) / div;
1119+
p.y = (f1 * (y3 - y4) - f2 * (y1 - y2)) / div;
1120+
}
11141121
}
11151122

11161123
// SRP0[] Set Reference Point 0
@@ -2116,7 +2123,7 @@ function DIV(state) {
21162123

21172124
if (DEBUG) console.log(state.step, 'DIV[]', n2, n1);
21182125

2119-
stack.push(n1 * 64 / n2);
2126+
stack.push(n2 === 0 ? 0 : n1 * 64 / n2);
21202127
}
21212128

21222129
// MUL[] MUL
@@ -2195,7 +2202,8 @@ function WCVTF(state) {
21952202

21962203
if (DEBUG) console.log(state.step, 'WCVTF[]', v, l);
21972204

2198-
state.cvt[l] = v * state.ppem / state.font.unitsPerEm;
2205+
const unitsPerEm = state.font.unitsPerEm || 1000;
2206+
state.cvt[l] = v * state.ppem / unitsPerEm;
21992207
}
22002208

22012209
// DELTAC1[] DELTA exception C1

src/path.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ function roundDecimal(float, places) {
3232
const roundedDecimalPart = decimalRoundingCache[places][decimalPart];
3333
return integerPart + roundedDecimalPart;
3434
}
35-
36-
const roundedDecimalPart = +(Math.round(decimalPart + 'e+' + places) + 'e-' + places);
35+
36+
const roundedDecimalPart = Number((Math.round(decimalPart * Math.pow(10, places)) / Math.pow(10, places)).toFixed(places));
3737
decimalRoundingCache[places][decimalPart] = roundedDecimalPart;
3838

3939
return integerPart + roundedDecimalPart;

src/tables/cpal.mjs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,18 @@ function rgbToHSL(bgra) {
108108
h = s = 0;
109109
} else {
110110
const d = max - min;
111-
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
112-
switch (max) {
113-
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
114-
case g: h = (b - r) / d + 2; break;
115-
case b: h = (r - g) / d + 4; break;
111+
if (d === 0) {
112+
h = s = 0;
113+
} else {
114+
const denomS = l > 0.5 ? (2 - max - min) : (max + min);
115+
s = denomS === 0 ? 0 : d / denomS;
116+
switch (max) {
117+
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
118+
case g: h = (b - r) / d + 2; break;
119+
case b: h = (r - g) / d + 4; break;
120+
}
121+
h /= 6;
116122
}
117-
h /= 6;
118123
}
119124

120125
return {

src/variationprocessor.mjs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ export class VariationProcessor {
4646
tagValue = axis.defaultValue;
4747
}
4848
if (tagValue < axis.defaultValue) {
49-
normalized.push((tagValue - axis.defaultValue + Number.EPSILON) / (axis.defaultValue - axis.minValue + Number.EPSILON));
49+
const denom = axis.defaultValue - axis.minValue;
50+
normalized.push(denom === 0 ? 0 : (tagValue - axis.defaultValue) / denom);
5051
} else {
51-
normalized.push((tagValue - axis.defaultValue + Number.EPSILON) / (axis.maxValue - axis.defaultValue + Number.EPSILON));
52+
const denom = axis.maxValue - axis.defaultValue;
53+
normalized.push(denom === 0 ? 0 : (tagValue - axis.defaultValue) / denom);
5254
}
5355
}
5456

@@ -61,10 +63,13 @@ export class VariationProcessor {
6163
let pair = segment.axisValueMaps[j];
6264
if (j >= 1 && normalized[i] < pair.fromCoordinate) {
6365
let prev = segment.axisValueMaps[j - 1];
64-
normalized[i] = ((normalized[i] - prev.fromCoordinate) * (pair.toCoordinate - prev.toCoordinate) + Number.EPSILON) /
65-
(pair.fromCoordinate - prev.fromCoordinate + Number.EPSILON) +
66-
prev.toCoordinate;
67-
66+
const denom = pair.fromCoordinate - prev.fromCoordinate;
67+
if (denom === 0) {
68+
normalized[i] = prev.toCoordinate;
69+
} else {
70+
normalized[i] = ((normalized[i] - prev.fromCoordinate) * (pair.toCoordinate - prev.toCoordinate)) / denom + prev.toCoordinate;
71+
}
72+
6873
break;
6974
}
7075
}
@@ -284,15 +289,18 @@ export class VariationProcessor {
284289
break;
285290
}
286291

287-
factor = (factor * normalizedCoords[a] + Number.EPSILON) / (tupleCoords[a] + Number.EPSILON);
292+
const denom = tupleCoords[a];
293+
factor = denom === 0 ? 0 : (factor * normalizedCoords[a]) / denom;
288294
} else {
289295
if ((normalizedCoords[a] < header.intermediateStartTuple[a]) || (normalizedCoords[a] > header.intermediateEndTuple[a])) {
290296
factor = 0;
291297
break;
292298
} else if (normalizedCoords[a] < tupleCoords[a]) {
293-
factor = factor * (normalizedCoords[a] - header.intermediateStartTuple[a] + Number.EPSILON) / (tupleCoords[a] - header.intermediateStartTuple[a] + Number.EPSILON);
299+
const denom = tupleCoords[a] - header.intermediateStartTuple[a];
300+
factor = denom === 0 ? 0 : factor * (normalizedCoords[a] - header.intermediateStartTuple[a]) / denom;
294301
} else {
295-
factor = factor * (header.intermediateEndTuple[a] - normalizedCoords[a] + Number.EPSILON) / (header.intermediateEndTuple[a] - tupleCoords[a] + Number.EPSILON);
302+
const denom = header.intermediateEndTuple[a] - tupleCoords[a];
303+
factor = denom === 0 ? 0 : factor * (header.intermediateEndTuple[a] - normalizedCoords[a]) / denom;
296304
}
297305
}
298306
}
@@ -526,11 +534,11 @@ export class VariationProcessor {
526534
if (normalizedCoords[j] === axis.peakCoord) {
527535
axisScalar = 1;
528536
} else if (normalizedCoords[j] < axis.peakCoord) {
529-
axisScalar = (normalizedCoords[j] - axis.startCoord + Number.EPSILON) /
530-
(axis.peakCoord - axis.startCoord + Number.EPSILON);
537+
const denom = axis.peakCoord - axis.startCoord;
538+
axisScalar = denom === 0 ? 1 : (normalizedCoords[j] - axis.startCoord) / denom;
531539
} else {
532-
axisScalar = (axis.endCoord - normalizedCoords[j] + Number.EPSILON) /
533-
(axis.endCoord - axis.peakCoord + Number.EPSILON);
540+
const denom = axis.endCoord - axis.peakCoord;
541+
axisScalar = denom === 0 ? 1 : (axis.endCoord - normalizedCoords[j]) / denom;
534542
}
535543
}
536544

0 commit comments

Comments
 (0)