Skip to content

Commit 139b90b

Browse files
committed
Fix rounding errors caused by glyph cross references (#2545)
1 parent 1b7ad7c commit 139b90b

File tree

5 files changed

+96
-51
lines changed

5 files changed

+96
-51
lines changed

packages/font-glyphs/src/meta/aesthetics.ptl

+12-10
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ export : define [calculateMetrics para] : begin
99
define HalfUPM : UPM / 2
1010

1111
# Key metrics
12-
define Width : Math.round para.width
13-
define SB para.sb
14-
define CAP para.cap
15-
define XH para.xHeight
16-
define Ascender para.ascender
17-
define Descender : fallback para.descender (XH - Ascender)
18-
define Contrast : fallback para.contrast 1
12+
define Width : Math.round para.width
13+
define SB : Math.round para.sb
14+
define CAP : Math.round para.cap
15+
define XH : Math.round para.xHeight
16+
define Ascender : Math.round para.ascender
17+
define Descender : Math.round : fallback para.descender (XH - Ascender)
18+
1919
# Key metrics for symbols
20-
define SymbolMid para.symbolMid
21-
define ParenTop : SymbolMid + para.parenSize / 2
22-
define ParenBot : SymbolMid - para.parenSize / 2
20+
define SymbolMid : Math.round para.symbolMid
21+
define halfParenSize : Math.ceil (para.parenSize / 2)
22+
define ParenTop : SymbolMid + halfParenSize
23+
define ParenBot : SymbolMid - halfParenSize
2324

2425
define OperTop : SymbolMid + para.operSize * (Width - SB * 2)
2526
define OperBot : SymbolMid - para.operSize * (Width - SB * 2)
@@ -32,6 +33,7 @@ export : define [calculateMetrics para] : begin
3233
define BgOpTop : SymbolMid + para.bgopSize * (Width - SB * 2)
3334
define BgOpBot : SymbolMid - para.bgopSize * (Width - SB * 2)
3435

36+
define Contrast : fallback para.contrast 1
3537

3638
# Transform constructors
3739
define [Italify angle shift] : begin

packages/font-glyphs/src/symbol/punctuation/brackets.ptl

+5-4
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,12 @@ glyph-block Symbol-Punctuation-Brackets : begin
162162

163163
export : define [Mask] : Rect MosaicTop MosaicBottom (-Width) (2 * Width)
164164

165-
export : define [Shape top bottom barLeft ext] : glyph-proc
165+
export : define [Shape top bottom barLeft ext] : begin
166166
local hDim : HDim barLeft ext
167-
include : HBar.b hDim.l hDim.r bottom
168-
include : HBar.t hDim.l hDim.r top
169-
include : VBar.l hDim.l bottom top
167+
return : union
168+
HBar.b hDim.l hDim.r bottom
169+
HBar.t hDim.l hDim.r top
170+
VBar.l hDim.l bottom top
170171

171172
do "Bracket Glyphs"
172173
create-glyph 'bracketLeft' '[' : Bracket.Shape ParenTop ParenBot

packages/font/src/cleanup/glyphs.mjs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as Geom from "@iosevka/geometry";
2-
import { Transform } from "@iosevka/geometry/transform";
32

43
///////////////////////////////////////////////////////////////////////////////////////////////////
54

@@ -12,6 +11,9 @@ export function finalizeGlyphs(cache, para, glyphStore) {
1211
///////////////////////////////////////////////////////////////////////////////////////////////////
1312

1413
function regulateGlyphStore(cache, para, skew, glyphStore) {
14+
for (const g of glyphStore.glyphs()) {
15+
if (!g.geometry.toReferences()) g.geometry = g.geometry.toIndependent();
16+
}
1517
for (const g of glyphStore.glyphs()) {
1618
if (!(g.geometry.measureComplexity() & Geom.CPLX_NON_EMPTY)) continue;
1719
if (!g.geometry.toReferences()) flattenSimpleGlyph(cache, para, skew, g);
@@ -27,6 +29,7 @@ function flattenSimpleGlyph(cache, para, skew, g) {
2729
g.includeContours(cs);
2830
} catch (e) {
2931
console.error("Detected broken geometry when processing", g._m_identifier);
32+
console.error(e);
3033
console.error(
3134
`${para.naming.family} ${para.naming.weight} ${para.naming.width} ${para.naming.slope}`,
3235
);

packages/geometry-cache/src/index.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import zlib from "zlib";
55
import * as CurveUtil from "@iosevka/geometry/curve-util";
66
import { encode, decode } from "@msgpack/msgpack";
77

8-
const Edition = 46;
8+
const Edition = 50;
99
const MAX_AGE = 16;
1010
class GfEntry {
1111
constructor(age, value) {

packages/geometry/src/index.mjs

+74-35
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export class GeometryBase {
2222
toReferences() {
2323
throw new Error("Unimplemented");
2424
}
25+
toIndependent() {
26+
throw new Error("Unimplemented");
27+
}
2528
getDependencies() {
2629
throw new Error("Unimplemented");
2730
}
@@ -50,6 +53,9 @@ export class ContourSetGeometry extends GeometryBase {
5053
toReferences() {
5154
return null;
5255
}
56+
toIndependent() {
57+
return this;
58+
}
5359
getDependencies() {
5460
return null;
5561
}
@@ -102,25 +108,32 @@ export class CachedGeometry extends GeometryBase {
102108
}
103109
}
104110

105-
export class SpiroGeometry extends CachedGeometry {
106-
constructor(gizmo, closed, knots) {
107-
super();
108-
this.m_knots = knots;
109-
this.m_closed = closed;
110-
this.m_gizmo = gizmo;
111-
}
112-
toContoursImpl() {
113-
return spiroToOutlineWithSimplification(this.m_knots, this.m_closed, this.m_gizmo);
114-
}
111+
class SimpleGeometry extends CachedGeometry {
115112
toReferences() {
116113
return null;
117114
}
115+
toIndependent() {
116+
return this;
117+
}
118118
getDependencies() {
119119
return null;
120120
}
121121
filterTag(fn) {
122122
return this;
123123
}
124+
}
125+
126+
export class SpiroGeometry extends SimpleGeometry {
127+
constructor(gizmo, closed, knots) {
128+
super();
129+
this.m_knots = knots;
130+
this.m_closed = closed;
131+
this.m_gizmo = gizmo;
132+
}
133+
toContoursImpl() {
134+
return spiroToOutlineWithSimplification(this.m_knots, this.m_closed, this.m_gizmo);
135+
}
136+
124137
measureComplexity() {
125138
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
126139
for (const z of this.m_knots) {
@@ -140,7 +153,7 @@ export class SpiroGeometry extends CachedGeometry {
140153
}
141154
}
142155

143-
export class SpiroPenGeometry extends CachedGeometry {
156+
export class SpiroPenGeometry extends SimpleGeometry {
144157
constructor(gizmo, penProfile, closed, knots) {
145158
super();
146159
this.m_gizmo = gizmo;
@@ -177,16 +190,6 @@ export class SpiroPenGeometry extends CachedGeometry {
177190
return ctx.contours;
178191
}
179192

180-
toReferences() {
181-
return null;
182-
}
183-
getDependencies() {
184-
return null;
185-
}
186-
filterTag(fn) {
187-
return this;
188-
}
189-
190193
measureComplexity() {
191194
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
192195
for (const z of this.m_penProfile) {
@@ -217,7 +220,7 @@ export class SpiroPenGeometry extends CachedGeometry {
217220
}
218221
}
219222

220-
export class DiSpiroGeometry extends CachedGeometry {
223+
export class DiSpiroGeometry extends SimpleGeometry {
221224
constructor(gizmo, contrast, closed, biKnots) {
222225
super();
223226
this.m_biKnots = biKnots; // untransformed
@@ -261,15 +264,7 @@ export class DiSpiroGeometry extends CachedGeometry {
261264
}
262265
return expander.expand();
263266
}
264-
toReferences() {
265-
return null;
266-
}
267-
getDependencies() {
268-
return null;
269-
}
270-
filterTag(fn) {
271-
return this;
272-
}
267+
273268
measureComplexity() {
274269
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
275270
for (const z of this.m_biKnots) {
@@ -298,14 +293,24 @@ export class ReferenceGeometry extends GeometryBase {
298293
this.m_x = x || 0;
299294
this.m_y = y || 0;
300295
}
301-
unwrap() {
296+
297+
toIndependent() {
298+
// Do unlinking *recursively*
299+
return TransformedGeometry.create(
300+
Transform.Translate(this.m_x, this.m_y),
301+
this.m_glyph.geometry.toIndependent(),
302+
);
303+
}
304+
unwrapSimple() {
305+
// Do unlinking *for only one level*
302306
return TransformedGeometry.create(
303307
Transform.Translate(this.m_x, this.m_y),
304308
this.m_glyph.geometry,
305309
);
306310
}
311+
307312
toContours(ctx) {
308-
return this.unwrap().toContours(ctx);
313+
return this.unwrapSimple().toContours(ctx);
309314
}
310315
toReferences() {
311316
if (this.m_glyph.geometry.measureComplexity() & CPLX_NON_EMPTY) {
@@ -319,13 +324,13 @@ export class ReferenceGeometry extends GeometryBase {
319324
return [this.m_glyph];
320325
}
321326
filterTag(fn) {
322-
return this.unwrap().filterTag(fn);
327+
return this.unwrapSimple().filterTag(fn);
323328
}
324329
measureComplexity() {
325330
return this.m_glyph.geometry.measureComplexity();
326331
}
327332
hash(h) {
328-
this.unwrap().hash(h);
333+
this.unwrapSimple().hash(h);
329334
}
330335
}
331336

@@ -341,6 +346,9 @@ export class TaggedGeometry extends GeometryBase {
341346
toReferences() {
342347
return this.m_geom.toReferences();
343348
}
349+
toIndependent() {
350+
return new TaggedGeometry(this.m_geom.toIndependent(), this.m_tag);
351+
}
344352
getDependencies() {
345353
return this.m_geom.getDependencies();
346354
}
@@ -395,6 +403,9 @@ export class TransformedGeometry extends GeometryBase {
395403
result.push({ glyph, x: x + this.m_transform.tx, y: y + this.m_transform.ty });
396404
return result;
397405
}
406+
toIndependent() {
407+
return TransformedGeometry.create(this.m_transform, this.m_geom.toIndependent());
408+
}
398409
getDependencies() {
399410
return this.m_geom.getDependencies();
400411
}
@@ -429,6 +440,9 @@ export class RadicalGeometry extends GeometryBase {
429440
toReferences() {
430441
return null;
431442
}
443+
toIndependent() {
444+
return new RadicalGeometry(this.m_geom.toIndependent());
445+
}
432446
getDependencies() {
433447
return this.m_geom.getDependencies();
434448
}
@@ -480,6 +494,9 @@ export class CombineGeometry extends GeometryBase {
480494
}
481495
return results;
482496
}
497+
toIndependent() {
498+
return new CombineGeometry(this.m_parts.map(x => x.toIndependent()));
499+
}
483500
getDependencies() {
484501
let results = [];
485502
for (const part of this.m_parts) {
@@ -557,9 +574,16 @@ export class BooleanGeometry extends CachedGeometry {
557574
if (i > 0) sink.push({ type: "operator", operator: this.m_operator });
558575
}
559576
}
577+
560578
toReferences() {
561579
return null;
562580
}
581+
toIndependent() {
582+
return new BooleanGeometry(
583+
this.m_operator,
584+
this.m_operands.map(x => x.toIndependent()),
585+
);
586+
}
563587
getDependencies() {
564588
let results = [];
565589
for (const part of this.m_operands) {
@@ -634,6 +658,15 @@ export class StrokeGeometry extends CachedGeometry {
634658
toReferences() {
635659
return null;
636660
}
661+
toIndependent() {
662+
return new StrokeGeometry(
663+
this.m_geom.toIndependent(),
664+
this.m_gizmo,
665+
this.m_radius,
666+
this.m_contrast,
667+
this.m_fInside,
668+
);
669+
}
637670
getDependencies() {
638671
return this.m_geom.getDependencies();
639672
}
@@ -709,6 +742,9 @@ export class RemoveHolesGeometry extends CachedGeometry {
709742
toReferences() {
710743
return null;
711744
}
745+
toIndependent() {
746+
return new RemoveHolesGeometry(this.m_geom.toIndependent(), this.m_gizmo);
747+
}
712748
getDependencies() {
713749
return this.m_geom.getDependencies();
714750
}
@@ -756,6 +792,9 @@ export class SimplifyGeometry extends CachedGeometry {
756792
toReferences() {
757793
return null;
758794
}
795+
toIndependent() {
796+
return new SimplifyGeometry(this.m_geom.toIndependent());
797+
}
759798
getDependencies() {
760799
return this.m_geom.getDependencies();
761800
}

0 commit comments

Comments
 (0)