Fix precomposed iota with double marks (#2229).

This commit is contained in:
be5invis 2024-03-10 06:41:41 -07:00
parent f80097b88d
commit 03f3423e5d
8 changed files with 79 additions and 35 deletions

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) {