Skip to content

Commit

Permalink
Fix rounding errors caused by glyph cross references (#2545) (#2546)
Browse files Browse the repository at this point in the history
* Fix rounding errors caused by glyph cross references (#2545)

* Do it in simpler way
  • Loading branch information
be5invis authored Oct 13, 2024
1 parent 1b7ad7c commit 35de3aa
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 51 deletions.
1 change: 1 addition & 0 deletions changes/31.9.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Optimize glyph for Cyrillic Lower Dzze (`U+A689`) under italics.
* Optimize glyphs for Volapük Ae/Oe/Ue (`U+A79A`..`U+A79F`).
* Optimize glyph for Latin Lower Dezh Digraph with Palatal Hook (`U+1DF12`).
* Fix misalignments of square brackets under certain size caused by rounding errors (#2545).
* Add characters:
- WAVY LINE (`U+2307`).
- SYMMETRY (`U+232F`).
Expand Down
22 changes: 12 additions & 10 deletions packages/font-glyphs/src/meta/aesthetics.ptl
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ export : define [calculateMetrics para] : begin
define HalfUPM : UPM / 2

# Key metrics
define Width : Math.round para.width
define SB para.sb
define CAP para.cap
define XH para.xHeight
define Ascender para.ascender
define Descender : fallback para.descender (XH - Ascender)
define Contrast : fallback para.contrast 1
define Width : Math.round para.width
define SB : Math.round para.sb
define CAP : Math.round para.cap
define XH : Math.round para.xHeight
define Ascender : Math.round para.ascender
define Descender : Math.round : fallback para.descender (XH - Ascender)

# Key metrics for symbols
define SymbolMid para.symbolMid
define ParenTop : SymbolMid + para.parenSize / 2
define ParenBot : SymbolMid - para.parenSize / 2
define SymbolMid : Math.round para.symbolMid
define halfParenSize : Math.ceil (para.parenSize / 2)
define ParenTop : SymbolMid + halfParenSize
define ParenBot : SymbolMid - halfParenSize

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

define Contrast : fallback para.contrast 1

# Transform constructors
define [Italify angle shift] : begin
Expand Down
9 changes: 5 additions & 4 deletions packages/font-glyphs/src/symbol/punctuation/brackets.ptl
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,12 @@ glyph-block Symbol-Punctuation-Brackets : begin

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

export : define [Shape top bottom barLeft ext] : glyph-proc
export : define [Shape top bottom barLeft ext] : begin
local hDim : HDim barLeft ext
include : HBar.b hDim.l hDim.r bottom
include : HBar.t hDim.l hDim.r top
include : VBar.l hDim.l bottom top
return : union
HBar.b hDim.l hDim.r bottom
HBar.t hDim.l hDim.r top
VBar.l hDim.l bottom top

do "Bracket Glyphs"
create-glyph 'bracketLeft' '[' : Bracket.Shape ParenTop ParenBot
Expand Down
16 changes: 11 additions & 5 deletions packages/font/src/cleanup/glyphs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,30 @@ export function finalizeGlyphs(cache, para, glyphStore) {
///////////////////////////////////////////////////////////////////////////////////////////////////

function regulateGlyphStore(cache, para, skew, glyphStore) {
const simplifiedResultMap = new Map();
for (const g of glyphStore.glyphs()) {
if (!(g.geometry.measureComplexity() & Geom.CPLX_NON_EMPTY)) continue;
if (!g.geometry.toReferences()) flattenSimpleGlyph(cache, para, skew, g);
if (!g.geometry.toReferences()) {
simplifiedResultMap.set(g, flattenSimpleGlyph(cache, para, skew, g));
}
}
for (const [g, sr] of simplifiedResultMap) {
g.gizmo = Transform.Id();
g.geometry = new Geom.ContourSetGeometry(sr);
}
}

function flattenSimpleGlyph(cache, para, skew, g) {
try {
if (!g.gizmo) throw new TypeError("No gizmo");
const gSimplified = Geom.SimplifyGeometry.wrapWithGizmo(g.geometry, g.gizmo);
const cs = gSimplified.toContours({ cache });
g.clearGeometry();
g.includeContours(cs);
return gSimplified.toContours({ cache });
} catch (e) {
console.error("Detected broken geometry when processing", g._m_identifier);
console.error(e);
console.error(
`${para.naming.family} ${para.naming.weight} ${para.naming.width} ${para.naming.slope}`,
);
g.clearGeometry();
return [];
}
}
2 changes: 1 addition & 1 deletion packages/geometry-cache/src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import zlib from "zlib";
import * as CurveUtil from "@iosevka/geometry/curve-util";
import { encode, decode } from "@msgpack/msgpack";

const Edition = 46;
const Edition = 50;
const MAX_AGE = 16;
class GfEntry {
constructor(age, value) {
Expand Down
51 changes: 20 additions & 31 deletions packages/geometry/src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,7 @@ export class CachedGeometry extends GeometryBase {
}
}

export class SpiroGeometry extends CachedGeometry {
constructor(gizmo, closed, knots) {
super();
this.m_knots = knots;
this.m_closed = closed;
this.m_gizmo = gizmo;
}
toContoursImpl() {
return spiroToOutlineWithSimplification(this.m_knots, this.m_closed, this.m_gizmo);
}
class SimpleGeometry extends CachedGeometry {
toReferences() {
return null;
}
Expand All @@ -121,6 +112,19 @@ export class SpiroGeometry extends CachedGeometry {
filterTag(fn) {
return this;
}
}

export class SpiroGeometry extends SimpleGeometry {
constructor(gizmo, closed, knots) {
super();
this.m_knots = knots;
this.m_closed = closed;
this.m_gizmo = gizmo;
}
toContoursImpl() {
return spiroToOutlineWithSimplification(this.m_knots, this.m_closed, this.m_gizmo);
}

measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_knots) {
Expand All @@ -140,7 +144,7 @@ export class SpiroGeometry extends CachedGeometry {
}
}

export class SpiroPenGeometry extends CachedGeometry {
export class SpiroPenGeometry extends SimpleGeometry {
constructor(gizmo, penProfile, closed, knots) {
super();
this.m_gizmo = gizmo;
Expand Down Expand Up @@ -177,16 +181,6 @@ export class SpiroPenGeometry extends CachedGeometry {
return ctx.contours;
}

toReferences() {
return null;
}
getDependencies() {
return null;
}
filterTag(fn) {
return this;
}

measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_penProfile) {
Expand Down Expand Up @@ -217,7 +211,7 @@ export class SpiroPenGeometry extends CachedGeometry {
}
}

export class DiSpiroGeometry extends CachedGeometry {
export class DiSpiroGeometry extends SimpleGeometry {
constructor(gizmo, contrast, closed, biKnots) {
super();
this.m_biKnots = biKnots; // untransformed
Expand Down Expand Up @@ -261,15 +255,7 @@ export class DiSpiroGeometry extends CachedGeometry {
}
return expander.expand();
}
toReferences() {
return null;
}
getDependencies() {
return null;
}
filterTag(fn) {
return this;
}

measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_biKnots) {
Expand Down Expand Up @@ -298,12 +284,14 @@ export class ReferenceGeometry extends GeometryBase {
this.m_x = x || 0;
this.m_y = y || 0;
}

unwrap() {
return TransformedGeometry.create(
Transform.Translate(this.m_x, this.m_y),
this.m_glyph.geometry,
);
}

toContours(ctx) {
return this.unwrap().toContours(ctx);
}
Expand Down Expand Up @@ -557,6 +545,7 @@ export class BooleanGeometry extends CachedGeometry {
if (i > 0) sink.push({ type: "operator", operator: this.m_operator });
}
}

toReferences() {
return null;
}
Expand Down

0 comments on commit 35de3aa

Please sign in to comment.