Fix rounding errors caused by glyph cross references (#2545) (#2546)

* Fix rounding errors caused by glyph cross references (#2545)

* Do it in simpler way
This commit is contained in:
Belleve 2024-10-12 15:25:26 -10:00 committed by GitHub
parent 1b7ad7cab9
commit 35de3aa463
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 50 additions and 51 deletions

View file

@ -9,6 +9,7 @@
* Optimize glyph for Cyrillic Lower Dzze (`U+A689`) under italics. * Optimize glyph for Cyrillic Lower Dzze (`U+A689`) under italics.
* Optimize glyphs for Volapük Ae/Oe/Ue (`U+A79A`..`U+A79F`). * Optimize glyphs for Volapük Ae/Oe/Ue (`U+A79A`..`U+A79F`).
* Optimize glyph for Latin Lower Dezh Digraph with Palatal Hook (`U+1DF12`). * 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: * Add characters:
- WAVY LINE (`U+2307`). - WAVY LINE (`U+2307`).
- SYMMETRY (`U+232F`). - SYMMETRY (`U+232F`).

View file

@ -10,16 +10,17 @@ export : define [calculateMetrics para] : begin
# Key metrics # Key metrics
define Width : Math.round para.width define Width : Math.round para.width
define SB para.sb define SB : Math.round para.sb
define CAP para.cap define CAP : Math.round para.cap
define XH para.xHeight define XH : Math.round para.xHeight
define Ascender para.ascender define Ascender : Math.round para.ascender
define Descender : fallback para.descender (XH - Ascender) define Descender : Math.round : fallback para.descender (XH - Ascender)
define Contrast : fallback para.contrast 1
# Key metrics for symbols # Key metrics for symbols
define SymbolMid para.symbolMid define SymbolMid : Math.round para.symbolMid
define ParenTop : SymbolMid + para.parenSize / 2 define halfParenSize : Math.ceil (para.parenSize / 2)
define ParenBot : SymbolMid - para.parenSize / 2 define ParenTop : SymbolMid + halfParenSize
define ParenBot : SymbolMid - halfParenSize
define OperTop : SymbolMid + para.operSize * (Width - SB * 2) define OperTop : SymbolMid + para.operSize * (Width - SB * 2)
define OperBot : SymbolMid - para.operSize * (Width - SB * 2) define OperBot : SymbolMid - para.operSize * (Width - SB * 2)
@ -32,6 +33,7 @@ export : define [calculateMetrics para] : begin
define BgOpTop : SymbolMid + para.bgopSize * (Width - SB * 2) define BgOpTop : SymbolMid + para.bgopSize * (Width - SB * 2)
define BgOpBot : SymbolMid - para.bgopSize * (Width - SB * 2) define BgOpBot : SymbolMid - para.bgopSize * (Width - SB * 2)
define Contrast : fallback para.contrast 1
# Transform constructors # Transform constructors
define [Italify angle shift] : begin define [Italify angle shift] : begin

View file

@ -162,11 +162,12 @@ glyph-block Symbol-Punctuation-Brackets : begin
export : define [Mask] : Rect MosaicTop MosaicBottom (-Width) (2 * Width) 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 local hDim : HDim barLeft ext
include : HBar.b hDim.l hDim.r bottom return : union
include : HBar.t hDim.l hDim.r top HBar.b hDim.l hDim.r bottom
include : VBar.l hDim.l bottom top HBar.t hDim.l hDim.r top
VBar.l hDim.l bottom top
do "Bracket Glyphs" do "Bracket Glyphs"
create-glyph 'bracketLeft' '[' : Bracket.Shape ParenTop ParenBot create-glyph 'bracketLeft' '[' : Bracket.Shape ParenTop ParenBot

View file

@ -12,9 +12,16 @@ export function finalizeGlyphs(cache, para, glyphStore) {
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
function regulateGlyphStore(cache, para, skew, glyphStore) { function regulateGlyphStore(cache, para, skew, glyphStore) {
const simplifiedResultMap = new Map();
for (const g of glyphStore.glyphs()) { for (const g of glyphStore.glyphs()) {
if (!(g.geometry.measureComplexity() & Geom.CPLX_NON_EMPTY)) continue; 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);
} }
} }
@ -22,14 +29,13 @@ function flattenSimpleGlyph(cache, para, skew, g) {
try { try {
if (!g.gizmo) throw new TypeError("No gizmo"); if (!g.gizmo) throw new TypeError("No gizmo");
const gSimplified = Geom.SimplifyGeometry.wrapWithGizmo(g.geometry, g.gizmo); const gSimplified = Geom.SimplifyGeometry.wrapWithGizmo(g.geometry, g.gizmo);
const cs = gSimplified.toContours({ cache }); return gSimplified.toContours({ cache });
g.clearGeometry();
g.includeContours(cs);
} catch (e) { } catch (e) {
console.error("Detected broken geometry when processing", g._m_identifier); console.error("Detected broken geometry when processing", g._m_identifier);
console.error(e);
console.error( console.error(
`${para.naming.family} ${para.naming.weight} ${para.naming.width} ${para.naming.slope}`, `${para.naming.family} ${para.naming.weight} ${para.naming.width} ${para.naming.slope}`,
); );
g.clearGeometry(); return [];
} }
} }

View file

@ -5,7 +5,7 @@ import zlib from "zlib";
import * as CurveUtil from "@iosevka/geometry/curve-util"; import * as CurveUtil from "@iosevka/geometry/curve-util";
import { encode, decode } from "@msgpack/msgpack"; import { encode, decode } from "@msgpack/msgpack";
const Edition = 46; const Edition = 50;
const MAX_AGE = 16; const MAX_AGE = 16;
class GfEntry { class GfEntry {
constructor(age, value) { constructor(age, value) {

View file

@ -102,16 +102,7 @@ export class CachedGeometry extends GeometryBase {
} }
} }
export class SpiroGeometry extends CachedGeometry { class SimpleGeometry 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);
}
toReferences() { toReferences() {
return null; return null;
} }
@ -121,6 +112,19 @@ export class SpiroGeometry extends CachedGeometry {
filterTag(fn) { filterTag(fn) {
return this; 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() { measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE; let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_knots) { for (const z of this.m_knots) {
@ -140,7 +144,7 @@ export class SpiroGeometry extends CachedGeometry {
} }
} }
export class SpiroPenGeometry extends CachedGeometry { export class SpiroPenGeometry extends SimpleGeometry {
constructor(gizmo, penProfile, closed, knots) { constructor(gizmo, penProfile, closed, knots) {
super(); super();
this.m_gizmo = gizmo; this.m_gizmo = gizmo;
@ -177,16 +181,6 @@ export class SpiroPenGeometry extends CachedGeometry {
return ctx.contours; return ctx.contours;
} }
toReferences() {
return null;
}
getDependencies() {
return null;
}
filterTag(fn) {
return this;
}
measureComplexity() { measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE; let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_penProfile) { for (const z of this.m_penProfile) {
@ -217,7 +211,7 @@ export class SpiroPenGeometry extends CachedGeometry {
} }
} }
export class DiSpiroGeometry extends CachedGeometry { export class DiSpiroGeometry extends SimpleGeometry {
constructor(gizmo, contrast, closed, biKnots) { constructor(gizmo, contrast, closed, biKnots) {
super(); super();
this.m_biKnots = biKnots; // untransformed this.m_biKnots = biKnots; // untransformed
@ -261,15 +255,7 @@ export class DiSpiroGeometry extends CachedGeometry {
} }
return expander.expand(); return expander.expand();
} }
toReferences() {
return null;
}
getDependencies() {
return null;
}
filterTag(fn) {
return this;
}
measureComplexity() { measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE; let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_biKnots) { for (const z of this.m_biKnots) {
@ -298,12 +284,14 @@ export class ReferenceGeometry extends GeometryBase {
this.m_x = x || 0; this.m_x = x || 0;
this.m_y = y || 0; this.m_y = y || 0;
} }
unwrap() { unwrap() {
return TransformedGeometry.create( return TransformedGeometry.create(
Transform.Translate(this.m_x, this.m_y), Transform.Translate(this.m_x, this.m_y),
this.m_glyph.geometry, this.m_glyph.geometry,
); );
} }
toContours(ctx) { toContours(ctx) {
return this.unwrap().toContours(ctx); return this.unwrap().toContours(ctx);
} }
@ -557,6 +545,7 @@ export class BooleanGeometry extends CachedGeometry {
if (i > 0) sink.push({ type: "operator", operator: this.m_operator }); if (i > 0) sink.push({ type: "operator", operator: this.m_operator });
} }
} }
toReferences() { toReferences() {
return null; return null;
} }