diff --git a/changes/29.0.1.md b/changes/29.0.1.md index beb5b9dc4..d3b10e18c 100644 --- a/changes/29.0.1.md +++ b/changes/29.0.1.md @@ -1,2 +1,4 @@ -* Fix broken `s`/`t` variants for `U+01BE`. (#2223) +* Fix broken `s`/`t` variants for `U+01BE`. (#2223). +* Fix precomposed iota with double marks (#2229). +* Fix leaning mark placement on letters around i/l. * Fix sans-serif linking for `U+2781`..`U+2784` and `U+278B`..`U+278E`. diff --git a/packages/font-glyphs/src/auto-build/accents.ptl b/packages/font-glyphs/src/auto-build/accents.ptl index fb1fb083c..a5147cc46 100644 --- a/packages/font-glyphs/src/auto-build/accents.ptl +++ b/packages/font-glyphs/src/auto-build/accents.ptl @@ -174,16 +174,16 @@ glyph-block AutoBuild-Accents : begin # Handle ogonek substParts parts ogonek.ignore {[hasBaseAnchor 'trailing']} {ogonek.matcher} {} ogonek.production - # Handle leaning marks - substParts parts [isMarkExcluding 'above'] {[MatchUtil.either [hasBaseAnchor 'leaningAbove'] [isMark 'leaningAbove']]} {[isLeaningMark 'above']} {} leaningMarkSplit - substParts parts [isMarkExcluding 'below'] {[MatchUtil.either [hasBaseAnchor 'leaningBelow'] [isMark 'leaningBelow']]} {[isLeaningMark 'below']} {} leaningMarkSplit - # Handle mark combinations (Greek) substParts parts MatchUtil.never {} { markComposition.matchFirst markComposition.matchSecond } {} markComposition.production # Handle upper Greek Tonos marks substParts parts MatchUtil.never {[hasBaseAnchor 'grekUpperTonos']} {upperTonos.matcher} {} upperTonos.production + # Handle leaning marks + substParts parts [isMarkExcluding 'above'] {[MatchUtil.either [hasBaseAnchor 'leaningAbove'] [isMark 'leaningAbove']]} {[isLeaningMark 'above']} {} leaningMarkSplit + substParts parts [isMarkExcluding 'below'] {[MatchUtil.either [hasBaseAnchor 'leaningBelow'] [isMark 'leaningBelow']]} {[isLeaningMark 'below']} {} leaningMarkSplit + define [pad _s n] : begin local s _s while (s.length < n) : s = '0' + s diff --git a/packages/font-glyphs/src/auto-build/mark-doppelganger.ptl b/packages/font-glyphs/src/auto-build/mark-doppelganger.ptl index e3f4eed0c..f3bcf2ba3 100644 --- a/packages/font-glyphs/src/auto-build/mark-doppelganger.ptl +++ b/packages/font-glyphs/src/auto-build/mark-doppelganger.ptl @@ -12,6 +12,7 @@ glyph-module glyph-block Mark-Doppelganger : if [not recursive] : begin glyph-block-import CommonShapes glyph-block-import Common-Derivatives + glyph-block-import Mark-Adjustment : TieAnchorMap LeaningAnchorMap define [DeriveMarkChange gr gn akFrom akTo] : begin DeriveMeshT {gn} AnyDerivingCv : function [gns] : begin @@ -29,11 +30,6 @@ glyph-block Mark-Doppelganger : if [not recursive] : begin return toGN - local spacerGlyphSet : new Set - define TieAnchorMap : list - list 'above' 'tieAbove' - list 'below' 'tieBelow' - do : foreach { u gn g } [glyphStore.encodedEntries] : DeriveTieMarks gn g : where : [DeriveTieMarks gn g] : begin local selection null @@ -46,10 +42,7 @@ glyph-block Mark-Doppelganger : if [not recursive] : begin DeriveMarkChange TieMark gn akFrom akTo - define LeaningAnchorMap : list - list 'above' 'leaningAbove' - list 'below' 'leaningBelow' - + local spacerGlyphSet : new Set do : foreach { u gn g } [glyphStore.encodedEntries] : DeriveLeaningMark gn g : where : [DeriveLeaningMark gn g] : begin local selection null diff --git a/packages/font-glyphs/src/letter/latin/lower-h.ptl b/packages/font-glyphs/src/letter/latin/lower-h.ptl index c948a4219..e48b81ba0 100644 --- a/packages/font-glyphs/src/letter/latin/lower-h.ptl +++ b/packages/font-glyphs/src/letter/latin/lower-h.ptl @@ -1,7 +1,7 @@ $$include '../../meta/macros.ptl' import [mix fallback SuffixCfg] from "@iosevka/util" -import [ScheduleLeaningMark MathSansSerif] from "@iosevka/glyph/relation" +import [MathSansSerif] from "@iosevka/glyph/relation" glyph-module diff --git a/packages/font-glyphs/src/letter/shared.ptl b/packages/font-glyphs/src/letter/shared.ptl index 876e66313..9d0d7b0fb 100644 --- a/packages/font-glyphs/src/letter/shared.ptl +++ b/packages/font-glyphs/src/letter/shared.ptl @@ -1,7 +1,8 @@ $$include '../meta/macros.ptl' import [mix clamp fallback] from "@iosevka/util" -import [Dotless CvDecompose RightDependentTrigger RightDependentLink DependentSelector] from "@iosevka/glyph/relation" +import [Dotless CvDecompose] from "@iosevka/glyph/relation" +import [RightDependentTrigger RightDependentLink DependentSelector] from "@iosevka/glyph/relation" import [DesignParameters] from "../meta/aesthetics.mjs" glyph-module @@ -9,14 +10,17 @@ glyph-module glyph-block Letter-Shared : begin glyph-block-import CommonShapes glyph-block-import Common-Derivatives - glyph-block-import Mark-Adjustment : TurnMarks + glyph-block-import Mark-Adjustment : TurnMarks LeaningAnchorMap glyph-block-export CreateAccentedComposition define [CreateAccentedComposition dst u srcGid accentGid] derive-multi-part-glyphs dst u { srcGid accentGid } : function [gns gr] : glyph-proc local { base mark } gns + local gMark : query-glyph mark + include [refer-glyph base] AS_BASE ALSO_METRICS - include [refer-glyph mark] + currentGlyph.includeMarkWithLeaningSupport gMark LeaningAnchorMap + if (!gr && accentGid === 'dotAbove') : Dotless.set currentGlyph base glyph-block-export CreateOgonekComposition diff --git a/packages/font-glyphs/src/marks/adjust.ptl b/packages/font-glyphs/src/marks/adjust.ptl index 44c77ecfd..19da10c93 100644 --- a/packages/font-glyphs/src/marks/adjust.ptl +++ b/packages/font-glyphs/src/marks/adjust.ptl @@ -56,6 +56,16 @@ glyph-block Mark-Adjustment : begin if (bLeaningAbove && currentGlyph.baseAnchors.below) set-base-anchor 'leaningBelow' [mix cx bLeaningAbove.x (-1)] currentGlyph.baseAnchors.below.y + glyph-block-export TieAnchorMap + define TieAnchorMap : list + list 'above' 'tieAbove' + list 'below' 'tieBelow' + + glyph-block-export LeaningAnchorMap + define LeaningAnchorMap : list + list 'above' 'leaningAbove' + list 'below' 'leaningBelow' + glyph-block-export LeaningAnchor define LeaningAnchor : namespace define [SetProcImpl mkCenter mkLeaning x] : glyph-proc diff --git a/packages/font-glyphs/src/marks/composite.ptl b/packages/font-glyphs/src/marks/composite.ptl index 41ab014e1..b22bfe519 100644 --- a/packages/font-glyphs/src/marks/composite.ptl +++ b/packages/font-glyphs/src/marks/composite.ptl @@ -1,6 +1,7 @@ $$include '../meta/macros.ptl' import [mix linreg clamp fallback] from "@iosevka/util" +import [ScheduleLeaningMark] from "@iosevka/glyph/relation" glyph-module @@ -48,7 +49,7 @@ glyph-block Mark-Composite : begin local yc : aboveMarkTop - commaAboveRadius + DotRadius * 0.3 + commaOvershoot - derive-glyphs 'psiliPerispomeni' null 'commaAbove' : function [src gr] : glyph-proc + derive-glyphs 'psiliPerispomeni' 0xEF01 'commaAbove' : function [src gr] : glyph-proc set-width 0 include : refer-glyph src local radius : Math.max (markExtend - commaAboveRadius) (commaAboveRadius * 1.25) @@ -63,6 +64,7 @@ glyph-block Mark-Composite : begin set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkStack + markHalfStroke * 2) set-base-anchor 'aboveBraceL' (markMiddle - 0.5 * markExtend) (aboveMarkMid + markHalfStroke) set-base-anchor 'aboveBraceR' (markMiddle + 0.5 * markExtend) (aboveMarkMid + markHalfStroke) + ScheduleLeaningMark.set currentGlyph derive-glyphs 'psiliPerispomeniGrekUpperTonos' null 'psiliPerispomeni' : function [src gr] : glyph-proc set-width 0 @@ -76,7 +78,7 @@ glyph-block Mark-Composite : begin set-width [query-glyph 'markBaseSpace'].advanceWidth include : refer-glyph src - derive-glyphs 'dasiaPerispomeni' null 'revCommaAbove' : function [src gr] : glyph-proc + derive-glyphs 'dasiaPerispomeni' 0xEF02 'revCommaAbove' : function [src gr] : glyph-proc set-width 0 include : refer-glyph src local radius : Math.max (markExtend - commaAboveRadius) (commaAboveRadius * 1.25) @@ -91,6 +93,7 @@ glyph-block Mark-Composite : begin set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkStack + markHalfStroke * 2) set-base-anchor 'aboveBraceL' (markMiddle - 0.5 * markExtend) (aboveMarkMid + markHalfStroke) set-base-anchor 'aboveBraceR' (markMiddle + 0.5 * markExtend) (aboveMarkMid + markHalfStroke) + ScheduleLeaningMark.set currentGlyph derive-glyphs 'dasiaPerispomeniGrekUpperTonos' null 'dasiaPerispomeni' : function [src gr] : glyph-proc set-width 0 diff --git a/packages/glyph/src/glyph.mjs b/packages/glyph/src/glyph.mjs index 766182ce7..fe069b50a 100644 --- a/packages/glyph/src/glyph.mjs +++ b/packages/glyph/src/glyph.mjs @@ -4,6 +4,7 @@ import * as Geom from "@iosevka/geometry"; import { Anchor } from "@iosevka/geometry/anchor"; import { Vec2 } from "@iosevka/geometry/point"; import { Transform } from "@iosevka/geometry/transform"; +import { ScheduleLeaningMark } from "./relation.mjs"; export class Glyph { constructor(identifier) { @@ -105,14 +106,19 @@ export class Glyph { } includeGlyph(g, copyAnchors, copyWidth) { if (g instanceof Function) throw new Error("Unreachable"); + if (g.isMarkSet) throw new Error("Invalid component to be introduced."); // Combine anchors and get offset let shift = new Vec2(0, 0); this.combineMarks(g, shift); this.includeGlyphImpl(g, shift.x, shift.y); - if (g.isMarkSet) throw new Error("Invalid component to be introduced."); if (copyAnchors) this.copyAnchors(g); if (copyWidth && g.advanceWidth >= 0) this.advanceWidth = g.advanceWidth; } + includeMarkWithLeaningSupport(g, lm) { + let shift = new Vec2(0, 0); + this.combineMarks(g, shift, lm); + this.includeGlyphImpl(g, shift.x, shift.y); + } includeGlyphImpl(g, shiftX, shiftY) { if (g._m_identifier) { this.includeGeometry(new Geom.ReferenceGeometry(g, shiftX, shiftY)); @@ -157,26 +163,52 @@ export class Glyph { this.geometry = this.geometry.filterTag(t => tag !== t); } // Anchors - combineMarks(g, shift) { + combineMarks(g, shift, lm) { if (!g.markAnchors) return; - for (const m in g.markAnchors) { - const markThat = g.markAnchors[m]; - const baseThis = this.baseAnchors[m]; - if (!baseThis) continue; - shift.x = baseThis.x - markThat.x; - shift.y = baseThis.y - markThat.y; + const fScheduledLeaning = lm && ScheduleLeaningMark.get(g); + for (const mk in g.markAnchors) { + // Find the base mark class and anchor + const baseThisN = this.baseAnchors[mk]; + if (!baseThisN) continue; + + // Find the leaning base mark class and anchor, if any + let mkLeaning = mk; + if (fScheduledLeaning) { + for (const [mkT, mkLeaningT] of lm) + if (mk === mkT && this.baseAnchors[mkLeaningT]) mkLeaning = mkLeaningT; + } + const baseThisL = this.baseAnchors[mkLeaning]; + if (!baseThisL) continue; + + // Find the mark anchor in mark glyph + const markThat = g.markAnchors[mk]; + + // Calculate the shift + shift.x = baseThisL.x - markThat.x; + shift.y = baseThisL.y - markThat.y; + + // Place anchors from mark glyph to current glyph let fSuppress = true; if (g.baseAnchors) { - for (const m2 in g.baseAnchors) { - if (m2 === m) fSuppress = false; - const baseDerived = g.baseAnchors[m2]; - this.baseAnchors[m2] = new Anchor( - shift.x + baseDerived.x, - shift.y + baseDerived.y, + for (const mkNewMark in g.baseAnchors) { + const baseDerived = g.baseAnchors[mkNewMark]; + this.baseAnchors[mkNewMark] = new Anchor( + baseThisN.x - markThat.x + baseDerived.x, + baseThisN.y - markThat.y + baseDerived.y, ); + if (mkNewMark === mk) { + fSuppress = false; + if (mkLeaning !== mk) { + this.baseAnchors[mkLeaning] = new Anchor( + baseThisL.x - markThat.x + baseDerived.x, + baseThisL.y - markThat.y + baseDerived.y, + ); + } + } } } - if (fSuppress) delete this.baseAnchors[m]; + if (fSuppress) delete this.baseAnchors[mk]; + break; } } copyAnchors(g) {