Implement leaning mark mechanism for F, L, P, b, d, h, k, p, q, r to get better mark placement. Now, "narrow" marks will align to these letters' extension parts (#1851).

This commit is contained in:
be5invis 2023-08-12 23:01:10 -07:00
parent 387389919c
commit f7fd09172b
33 changed files with 419 additions and 168 deletions

View file

@ -1,6 +1,7 @@
* Add characters:
- CLOCK FACE ONE OCLOCK (`U+1F550`) ... CLOCK FACE TWELVE-THIRTY (`U+1F567`) (#1850).
* Implement leaning mark mechanism for `F`, `L`, `P`, `b`, `d`, `h`, `k`, `p`, `q`, `r` to get better mark placement. Now, "narrow" marks will align to these letters' extension parts (#1851).
* Fix detached cedilla in Hookless asymmetric LATIN SMALL LETTER T WITH CEDILLA (`U+0163`) (#1914).
* Fix broken hookless/tailless/assymetric t variants in ſt ligature (`U+FB05`) (#1915).
* Fix broken hookless/tailless/asymmetric t variants in ſt ligature (`U+FB05`) (#1915).
* Remove unnecessary tailed variants for Cyrillic Shha with Descender (`U+0527`) (#1916).
* Remove unnecessary lower-right serif variants for Latin Lower K with Descender (`U+2C6A`) (#1917).

View file

@ -21,7 +21,7 @@ function assignSubRank(glyphStore) {
// "Fixed" subfamilies are properly built.
function validateMonospace(para, glyphStore) {
let awSet = new Set();
for (const [u, g] of glyphStore.encodedEntries()) {
for (const [u, n, g] of glyphStore.encodedEntries()) {
const aw = Math.round(g.advanceWidth || 0);
if (aw > 0) awSet.add(aw);
}

View file

@ -1,4 +1,4 @@
import { Joining, AnyCv, TieMark, Nwid, Wwid } from "../../support/gr.mjs";
import { Joining, AnyCv, TieMark, Nwid, Wwid, VS01 } from "../../support/gr.mjs";
const ApplePostNames = new Map([
/* spell-checker: disable */
@ -286,14 +286,18 @@ export function bySpacing(gSrcBase, gOtBase, internalNameMap, conflictSet) {
return n;
}
const NamingGr = [TieMark, VS01];
export function byGr(gSrcBase, gOtBase, internalNameMap, conflictSet) {
if (!gOtBase.name) return 0;
let n = 0;
for (const cv of AnyCv.query(gSrcBase)) {
n += nameByGr(cv, gSrcBase, gOtBase, internalNameMap, conflictSet);
}
if (TieMark.get(gSrcBase)) {
n += nameByGr(TieMark, gSrcBase, gOtBase, internalNameMap, conflictSet);
for (const gr of NamingGr) {
if (gr.get(gSrcBase)) {
n += nameByGr(gr, gSrcBase, gOtBase, internalNameMap, conflictSet);
}
}
return n;
}

View file

@ -1,10 +1,13 @@
###### Automatic builds
$$include '../../meta/macros.ptl'
import [Dotless AnyDerivingCv DotlessOrNot getGrTree CvDecompose] from"../../support/gr.mjs"
import [fallback] from"../../support/utils.mjs"
import [Dotless AnyDerivingCv DotlessOrNot getGrTree CvDecompose LeaningMark LeaningMarkSpacer] from"../../support/gr.mjs"
import [fallback ArrayUtil MatchUtil constant] from"../../support/utils.mjs"
import as UnicodeKnowledge from"../../meta/unicode-knowledge.mjs"
extern Map
extern Set
glyph-module
glyph-block AutoBuild-Accents : begin
@ -24,42 +27,150 @@ glyph-block AutoBuild-Accents : begin
set map.(key) amended
return amended
# Build accented glyphs
define [isAboveMark mark] : begin
return : mark && mark.markAnchors && mark.markAnchors.above
# Here, we build a simplified substitution builder that does the mark substitutions
define [substParts parts ignore backtrack input loookAhead production] : begin
local igl 0
while (igl < parts.length) : begin
local m : substMatch parts igl ignore backtrack input loookAhead
if [not m]
: then : inc igl
: else : begin
local inputGlyphs : ArrayUtil.mapIndexToItems parts m
local producedGlyphs : production.apply null inputGlyphs
foreach i [range (m.length - 1) downtill 0] : begin
parts.splice m.(i) 1
ArrayUtil.insertSliceAt parts m.0 producedGlyphs
set igl : m.(m.length - 1) + 1 + producedGlyphs.length - m.length
define [MarkSubst lookup] : function [p j parts] : begin
foreach { k v } [Object.entries lookup] : begin
if (p === [query-glyph k]) : set parts.(j) [query-glyph v]
return parts
define iotaBelowToLF : MarkSubst UnicodeKnowledge.iotaBelowToLfTf
define ogonekBelowToTR : MarkSubst UnicodeKnowledge.ogonekBelowToTRTf
define grekUpperTonos : MarkSubst UnicodeKnowledge.upperGrekMarkToTonosTf
define [substMatch parts igl ignore backtrack input lookAhead] : begin
if (igl >= parts.length) : return null
if [ignore parts.(igl)] : return null
if [not : input.0 parts.(igl)] : return null
local m { igl }
# Check input
local iglInput : igl + 1
foreach iInput [range 1 input.length] : begin
while (iglInput < parts.length && [ignore parts.(iglInput)]) : inc iglInput
if (iglInput >= parts.length) : return null
if [not : input.(iInput) parts.(iglInput)] : return null
m.push iglInput
inc iglInput
# Check lookahead
local iglLookAhead iglInput
foreach iLookAhead [range 0 lookAhead.length] : begin
while (iglLookAhead < parts.length && [ignore parts.(iglLookAhead)]) : inc iglLookAhead
if (iglLookAhead >= parts.length) : return null
if [not : lookAhead.(iLookAhead) parts.(iglLookAhead)] : return null
inc iglLookAhead
# Check backtrack
local iglBacktrack : igl - 1
foreach iBacktrack [range (backtrack.length - 1) downtill 0] : begin
while (iglBacktrack >= 0 && [ignore parts.(iglBacktrack)]) : dec iglBacktrack
if (iglBacktrack < 0) : return null
if [not : backtrack.(iBacktrack) parts.(iglBacktrack)] : return null
dec iglBacktrack
return m
define [dotless g] : begin
local gDotless : query-glyph : Dotless.get g
if [not gDotless] : return null
return {gDotless}
define [isMark k] : function [g] : begin
return : g && g.markAnchors && g.markAnchors.(k)
define [isMarkExcluding k] : function [g] : begin
return : g && g.markAnchors && [Object.keys g.markAnchors].length && !g.markAnchors.(k)
define [hasBaseAnchor k] : function [g] : begin
return : g && g.baseAnchors && g.baseAnchors.(k)
define [isLeaningMark k] : function [g] : begin
return : g && g.markAnchors && g.markAnchors.(k) && [LeaningMark.get g]
define [leaningMarkSplit g] : begin
local spacer : query-glyph : LeaningMarkSpacer.get g
local alternative : query-glyph : LeaningMark.get g
if (spacer && alternative) : return { spacer alternative }
return { g }
define [markSubst uk] : begin
local fromGlyphs : new Set
local mapping : new Map
foreach { k v } [Object.entries uk] : begin
local gFrom : query-glyph k
local gTo : query-glyph v
if (gFrom && gTo) : begin
fromGlyphs.add gFrom
mapping.set gFrom gTo
define [matcher g] : fromGlyphs.has g
define [ignore g] : g && g.markAnchors && [Object.keys g.markAnchors].length && ![matcher g]
define [production g] : list ([mapping.get g] || g)
return : object matcher ignore production
define [markCombine uk] : begin
local first : new Set
local second : new Set
local mapping : new Map
foreach { k1 m } [Object.entries uk] : begin
foreach { k2 v } [Object.entries m] : begin
local g1 : query-glyph k1
local g2 : query-glyph k2
local g3 : query-glyph v
if (g1 && g2 && g3) : begin
first.add g1
second.add g2
local mm : mapping.get g1
if [not mm] : begin
set mm : new Map
mapping.set g1 mm
mm.set g2 g3
define [matchFirst g] : first.has g
define [matchSecond g] : second.has g
define [production g1 g2] : begin
local mm : mapping.get g1
if [not mm] : return { g1 g2 }
local g3 : mm.get g2
if [not g3] : return { g1 g2 }
return { g3 }
return : object matchFirst matchSecond production
define iotaLF : markSubst UnicodeKnowledge.iotaBelowToLfTf
define ogonek : markSubst UnicodeKnowledge.ogonekBelowToTRTf
define upperTonos : markSubst UnicodeKnowledge.upperGrekMarkToTonosTf
define markComposition : markCombine UnicodeKnowledge.markCompositionTf
define [subParts parts] : begin
# Keep the semantics here synchronized with `ccmp` feature
# Handle dotless
local hasMarkAbove false
foreach p [items-of parts] : if [isAboveMark p] : set hasMarkAbove true
if (hasMarkAbove && [Dotless.get parts.0]) : begin
local dotless [query-glyph : Dotless.get parts.0]
if dotless : set parts.0 dotless
### Keep the semantics here synchronized with `ccmp` feature
# replace below marks with trailing marks
if parts.0.baseAnchors.lf : parts.forEach iotaBelowToLF
if parts.0.baseAnchors.trailing : parts.forEach ogonekBelowToTR
# Handle dotless form
substParts parts [isMarkExcluding 'above'] {} {dotless} {[isMark 'above']} dotless
# composite greek Marks
for [local j 0] (j < parts.length) [inc j] : begin
foreach { gidFirst seconds } [Object.entries UnicodeKnowledge.markCompositionTf]
if (parts.(j) === [query-glyph gidFirst])
foreach { gidSecond gidTo } [Object.entries seconds]
if (parts.(j + 1) === [query-glyph gidSecond]) : begin
set parts.(j) [query-glyph gidTo]; set parts.(j + 1) null
# Handle iota subscript
substParts parts iotaLF.ignore {[hasBaseAnchor 'lf']} {iotaLF.matcher} {} iotaLF.production
if parts.0.baseAnchors.grekUpperTonos : grekUpperTonos parts.1 1 parts
# Handle ogonek
substParts parts ogonek.ignore {[hasBaseAnchor 'trailing']} {ogonek.matcher} {} ogonek.production
return : parts.filter : function [x] [not : not x]
# 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
define [pad _s n] : begin
local s _s
@ -96,7 +207,7 @@ glyph-block AutoBuild-Accents : begin
if (allFound && parts.length) : begin
local glyphName : 'u' + [code.toString 16 :.padStart 4 '0']
set parts : subParts parts
subParts parts
set foundDecompositions.(glyphName) { glyphName code parts }
local s_goalName nothing

View file

@ -3,29 +3,76 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [TieMark AnyDerivingCv ScheduleLeaningMark LeaningMark LeaningMarkSpacer] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
extern Set
glyph-module
glyph-block Mark-Doppelganger : if [not recursive] : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
define AnchorMap : list
list 'above' 'tieAbove'
list 'below' 'tieBelow'
foreach { gn g } [glyphStore.namedEntries] : begin
local handled false
foreach { akFrom akTo } [items-of AnchorMap] : begin
if (!handled && g.markAnchors && g.markAnchors.(akFrom)) : begin
set handled true
local toGN : TieMark.amendName gn
define [DeriveMarkChange gr gn akFrom akTo] : begin
DeriveMeshT {gn} AnyDerivingCv : function [gns] : begin
local srcGn gns.0
local src : query-glyph srcGn
local toGN : gr.amendName srcGn
if [not : query-glyph toGN] : begin
create-glyph toGN : glyph-proc
include g AS_BASE ALSO_METRICS
include [refer-glyph srcGn] AS_BASE ALSO_METRICS
set currentGlyph.markAnchors.(akTo) currentGlyph.markAnchors.(akFrom)
currentGlyph.deleteMarkAnchor akFrom
set currentGlyph.baseAnchors.(akTo) currentGlyph.baseAnchors.(akFrom)
currentGlyph.deleteBaseAnchor akFrom
TieMark.set g toGN
gr.set src toGN
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
foreach { akFrom akTo } [items-of TieAnchorMap] : begin
if (!selection && g.markAnchors.(akFrom)) : begin
set selection { akFrom akTo }
if selection : begin
local { akFrom akTo } selection
DeriveMarkChange TieMark gn akFrom akTo
define LeaningAnchorMap : list
list 'above' 'leaningAbove'
list 'below' 'leaningBelow'
do : foreach { u gn g } [glyphStore.encodedEntries] : DeriveLeaningMark gn g
: where : [DeriveLeaningMark gn g] : begin
local selection null
foreach { akFrom akTo } [items-of LeaningAnchorMap] : begin
if (!selection && g.markAnchors.(akFrom) && [ScheduleLeaningMark.get g]) : begin
set selection { akFrom akTo }
if selection : begin
local { akFrom akTo } selection
# Build the doppelganger
DeriveMarkChange LeaningMark gn akFrom akTo
# build spacer glyph
local deltaX : Math.round : g.baseAnchors.(akFrom).x - g.markAnchors.(akFrom).x
local deltaY : Math.round : g.baseAnchors.(akFrom).y - g.markAnchors.(akFrom).y
local spacerGn "spacerGlyph{\(akTo)}{\(deltaX)}{\(deltaY)}"
LeaningMarkSpacer.set g spacerGn
if [not : spacerGlyphSet.has spacerGn] : begin
spacerGlyphSet.add spacerGn
create-glyph spacerGn : glyph-proc
include g AS_BASE ALSO_METRICS
currentGlyph.clearGeometry

View file

@ -48,7 +48,9 @@ glyph-block Common-Derivatives : begin
alias name unicode (name + '.upright')
glyph-block-export query-glyph
define [query-glyph id] : return : glyphStore.queryByName id
define [query-glyph id] : begin
if [not id] : return nothing
return : glyphStore.queryByName id
glyph-block-export refer-glyph
define [refer-glyph id] : lambda [copyAnchors copyWidth] : begin

View file

@ -22,6 +22,7 @@ glyph-block Letter-Cyrillic-Che : begin
define SLAB-TAILED-BGR 6
define [CyrCheShape top pyBar bodyType slabType] : glyph-proc
set-base-anchor 'leaningBelow' (RightSB - [HSwToV HalfStroke]) 0
local bar : top * [fallback pyBar 0.5]
include : match bodyType
[Just BODY-TAILED] : RightwardTailedBar RightSB 0 top

View file

@ -23,6 +23,7 @@ glyph-block Letter-Greek-Upper-Gamma: begin
define GammaBarLeft (SB * 1.5)
define [GammaShape top slabType] : glyph-proc
set-base-anchor 'leaningBelow' (GammaBarLeft + [HSwToV HalfStroke]) 0
include : VBar.l GammaBarLeft 0 top
include : HBar.t (GammaBarLeft - O) (RightSB - OX) top
match slabType

View file

@ -503,15 +503,12 @@ glyph-block Letter-Latin-K : begin
if slabLT : include : HSerif.lt (SB + [KBalance slabLT straightBar]) Ascender SideJut
if slabLB : include : tagged 'serifLB'
HSerif.mb (SB + [KBalance slabLT straightBar] + [HSwToV HalfStroke]) 0 Jut
set-base-anchor 'leaningAbove' (SB + [KBalance slabLT straightBar] + [HSwToV HalfStroke]) Ascender
create-glyph "k.\(suffix)" : glyph-proc
include : MarkSet.b
include : kBaseShape
create-glyph "k/circumflexBase.\(suffix)" : glyph-proc
include [refer-glyph "k.\(suffix)"] AS_BASE ALSO_METRICS
set-base-anchor 'above' (SB + [KBalance slabLT straightBar] + [HSwToV HalfStroke]) Ascender
create-glyph "kDescender.\(suffix)" : glyph-proc
include : MarkSet.b
include : kBaseShape CyrDescender
@ -550,7 +547,6 @@ glyph-block Letter-Latin-K : begin
select-variant 'k' 'k'
select-variant 'k/nonCursive' (shapeFrom -- 'k')
select-variant 'k/circumflexBase' (follow -- 'k')
link-reduced-variant 'k/sansSerif' 'k' MathSansSerif
select-variant 'kDescender' 0x2C6A
select-variant 'kPalatalHook' 0x1D84 (follow -- 'kDescender')
@ -578,11 +574,6 @@ glyph-block Letter-Latin-K : begin
derive-composites 'KBarLegStroke' 0xA744 'KBar' 'legSlashOver'
derive-composites 'kBarLegStroke' 0xA745 'kBar' 'legSlashOver'
derive-glyphs 'kCaron' 0x1E9 'k/circumflexBase' : lambda [src gr] : glyph-proc
local shift : Width + SB - Middle + [HSwToV HalfStroke]
include [refer-glyph src] AS_BASE ALSO_METRICS
include [refer-glyph "caronAbove"]
turned 'turnK' 0xA7B0 'K' Middle (CAP / 2)
turned 'turnk' 0x29E 'k' Middle (XH / 2) [MarkSet.p]
turned 'turnSmcpK' 0x1DF10 'smcpK' Middle (XH / 2)

View file

@ -45,6 +45,7 @@ glyph-block Letter-Latin-Lower-B : begin
include : Serifs
set-base-anchor 'overlayOnExtension' (SB + [HSwToV : 0.5 * Stroke]) yOverlay
set-base-anchor 'overlay' Middle (XH / 2)
set-base-anchor 'leaningAbove' (SB + [HSwToV HalfStroke]) Ascender
create-glyph "bBar.\(suffix)" : glyph-proc
include [refer-glyph "b.\(suffix)"] AS_BASE ALSO_METRICS
@ -86,8 +87,9 @@ glyph-block Letter-Latin-Lower-B : begin
derive-multi-part-glyphs 'bDot' 0x1E03 {'b' 'dotAbove'} : lambda [srcs gr] : glyph-proc
local { base mark } srcs
include : refer-glyph mark
include : Translate (Width + HalfStroke) 0
include : Translate (Width + [HSwToV HalfStroke]) 0
include [refer-glyph base] AS_BASE
set-base-anchor 'leaningAbove' (Middle + [HSwToV HalfStroke]) Ascender
glyph-block-import Letter-Blackboard : BBS BBD BBBarLeft
create-glyph 'mathbb/b' 0x1D553 : glyph-proc

View file

@ -96,6 +96,7 @@ glyph-block Letter-Latin-Lower-D : begin
if topSerif : include : topSerif df Ascender
if bottomSerif : include : bottomSerif df Ascender
set-base-anchor 'overlayOnExtension' (df.rightSB - [HSwToV : 0.5 * Stroke]) yOverlay
set-base-anchor 'leaningAbove' (df.rightSB - [HSwToV HalfStroke]) Ascender
create-glyph "dcroat.\(suffix)" : glyph-proc
local df : DivFrame 1
@ -165,8 +166,9 @@ glyph-block Letter-Latin-Lower-D : begin
derive-multi-part-glyphs 'dDot' 0x1E0B {'d' 'dotAbove'} : lambda [srcs gr] : glyph-proc
local { base mark } srcs
include : refer-glyph mark
include : Translate (Width - HalfStroke) 0
include : Translate (Width - [HSwToV HalfStroke]) 0
include [refer-glyph base] AS_BASE
set-base-anchor 'leaningAbove' (Middle - [HSwToV HalfStroke]) Ascender
derive-composites 'dBar' 0xA7C8 'd'
HBar.m (SB - OX) (RightSB + OX) (XH * 0.5) OverlayStroke

View file

@ -1,7 +1,7 @@
$$include '../../../meta/macros.ptl'
import [mix fallback SuffixCfg] from"../../../support/utils.mjs"
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
import [ScheduleLeaningMark MathSansSerif] from"../../../support/gr.mjs"
glyph-module
@ -57,6 +57,7 @@ glyph-block Letter-Latin-Lower-H : begin
foreach { suffix { fTailed {fHasTopSerif Serifs} } } [Object.entries HConfig] : do
create-glyph "h.\(suffix)" : glyph-proc
include : MarkSet.b
set-base-anchor 'leaningAbove' (SB + [HSwToV HalfStroke]) Ascender
include : VBar.l SB 0 Ascender
include : nShoulder
left -- (SB + [HSwToV Stroke])
@ -65,10 +66,6 @@ glyph-block Letter-Latin-Lower-H : begin
if fTailed : include : RightwardTailedBar RightSB 0 (XH - SmallArchDepthB)
include : Serifs fTailed false
create-glyph "h/circumflexBase.\(suffix)" : glyph-proc
include [refer-glyph "h.\(suffix)"] AS_BASE ALSO_METRICS
set-base-anchor 'above' (SB + [HSwToV HalfStroke]) Ascender
create-glyph "hBar.\(suffix)" : glyph-proc
include [refer-glyph "h.\(suffix)"] AS_BASE ALSO_METRICS
include : HBar.mOverlay fHasTopSerif
@ -125,19 +122,9 @@ glyph-block Letter-Latin-Lower-H : begin
select-variant 'h' 'h'
select-variant 'h/tailless' (shapeFrom -- 'h')
select-variant 'h/circumflexBase' (follow -- 'h')
link-reduced-variant 'h/descBase' 'h'
link-reduced-variant 'h/sansSerif' 'h' MathSansSerif
derive-glyphs 'hCircumflex' 0x125 'h/circumflexBase' : lambda [src gr] : glyph-proc
include [refer-glyph src] AS_BASE ALSO_METRICS
include [refer-glyph "circumflexAbove"]
derive-glyphs 'hCaron' 0x21F 'h/circumflexBase' : lambda [src gr] : glyph-proc
include [refer-glyph src] AS_BASE ALSO_METRICS
include [refer-glyph "caronAbove"]
select-variant 'hBar' 0x127 (follow -- 'h')
turned 'turnh' 0x265 'h/tailless' Middle (XH / 2) [MarkSet.p]
@ -159,6 +146,7 @@ glyph-block Letter-Latin-Lower-H : begin
local { base mark } srcs
include [refer-glyph base] AS_BASE ALSO_METRICS
include : with-transform [ApparentTranslate [HSwToV HalfStroke] (XH - Ascender)] [refer-glyph mark]
set-base-anchor 'leaningAbove' (Middle + [HSwToV HalfStroke]) Ascender
derive-glyphs 'hCedilla' 0x1E29 'h' : lambda [src gr] : glyph-proc
local shift : Width + SB - Middle + [HSwToV HalfStroke]

View file

@ -51,6 +51,7 @@ glyph-block Letter-Latin-Lower-P : begin
include : Serifs XH
set-base-anchor 'overlayOnExtension' (SB + [HSwToV : 0.5 * Stroke]) yOverlay
set-base-anchor 'strike' Middle (XH / 2)
set-base-anchor 'leaningBelow' (SB + [HSwToV HalfStroke]) Descender
create-glyph "thorn.\(suffix)" : glyph-proc
include : MarkSet.bp

View file

@ -77,6 +77,7 @@ glyph-block Letter-Latin-Lower-Q : begin
include : Body terminal XH Descender
if sRT : include : sRT XH
if sRB : include : sRB Descender
set-base-anchor 'leaningBelow' (RightSB - [HSwToV HalfStroke]) Descender
create-glyph "QRTail.\(suffix)" : glyph-proc
include : MarkSet.capDesc

View file

@ -72,17 +72,17 @@ glyph-block Letter-Latin-Lower-R : begin
[Just rNarrowSerifed] : mix df.width rHookX df.div
[Just rNarrow] : xArchMiddle + 0.1
__ rHookX
local [setMarks doTopSerif] : glyph-proc
set-base-anchor 'above' [mix [mix df.leftSB (xBar - [HSwToV Stroke]) : if doTopSerif 0.5 1] df.rightSB 0.5] XH
set-base-anchor 'overlay' (xBar - Stroke * 0.25) (XH * 0.5)
set-base-anchor 'palatalHookAttach' xBar 0
set-base-anchor 'palatalHookPos' (xBar + [PalatalHook.adviceGap Stroke]) 0
local [setMarks doTopSerif top bottom] : glyph-proc
set-base-anchor 'above' [mix [mix df.leftSB (xBar - [HSwToV Stroke]) : if doTopSerif 0.5 1] df.rightSB 0.5] top
set-base-anchor 'leaningBelow' (xBar - [HSwToV HalfStroke]) bottom
set-base-anchor 'overlay' (xBar - Stroke * 0.25) [mix bottom top 0.5]
set-base-anchor 'palatalHookAttach' xBar bottom
set-base-anchor 'palatalHookPos' (xBar + [PalatalHook.adviceGap Stroke]) top
return : object xBar rBottomSerif rTopSerif fine xArchMiddle skew rHookX rHookXN rHookY hookSuperness setMarks
define [StandardShape df md doTopSerif doBottomSerif] : glyph-proc
define [object xBar rBottomSerif rTopSerif fine xArchMiddle skew rHookX rHookY hookSuperness setMarks] : RDim df md
include : setMarks doTopSerif
define [object xBar rBottomSerif rTopSerif fine xArchMiddle skew rHookX rHookY hookSuperness] : RDim df md
include : dispiro
widths.lhs
g4.up.start rHookX (XH - rHookY - Stroke * 0.5) [heading Upward]
@ -97,8 +97,7 @@ glyph-block Letter-Latin-Lower-R : begin
define [CompactShape df md ts bs] : CompactShapeImpl df md false ts bs
define [CornerHookShape df md ts bs] : CompactShapeImpl df md true ts bs
define [CompactShapeImpl df md doHookSerif doTopSerif doBottomSerif] : glyph-proc
define [object xBar rBottomSerif rTopSerif fine xArchMiddle rHookXN setMarks] : RDim df md
include : setMarks doTopSerif
define [object xBar rBottomSerif rTopSerif fine xArchMiddle rHookXN] : RDim df md
define xCor : if doHookSerif 0 : CorrectionOMidS * [linreg 72 0.75 108 1 Stroke]
define arcTopShift : match md
@ -126,8 +125,7 @@ glyph-block Letter-Latin-Lower-R : begin
if doTopSerif : include : rTopSerif XH
define [EarlessCornerShape df md doTopSerif doBottomSerif] : glyph-proc
define [object xBar xArchMiddle rHookX rHookY hookSuperness rBottomSerif setMarks] : RDim df md
include : setMarks doTopSerif
define [object xBar xArchMiddle rHookX rHookY hookSuperness rBottomSerif] : RDim df md
include : dispiro
widths.lhs
g4.up.start rHookX (XH - rHookY - Stroke * 0.5) [heading Upward]
@ -138,8 +136,7 @@ glyph-block Letter-Latin-Lower-R : begin
if doBottomSerif : include : rBottomSerif 0
define [EarlessRoundedShape df md doTopSerif doBottomSerif] : glyph-proc
define [object xBar xArchMiddle rHookX rHookY hookSuperness rBottomSerif setMarks] : RDim df md
include : setMarks doTopSerif
define [object xBar xArchMiddle rHookX rHookY hookSuperness rBottomSerif] : RDim df md
local hx : Math.max rHookX (xBar + 1.25 * Stroke)
include : dispiro
widths.lhs
@ -150,9 +147,8 @@ glyph-block Letter-Latin-Lower-R : begin
if doBottomSerif : include : rBottomSerif 0
define [FlapHooklessShape df md doTopSerif doBottomSerif] : glyph-proc
define [object xBar rBottomSerif xArchMiddle setMarks] : RDim df md
define [object xBar rBottomSerif xArchMiddle] : RDim df md
set-base-anchor 'overlay' (xBar - [HSwToV : 0.5 * Stroke]) (XH / 2)
include : setMarks doTopSerif
include : dispiro
widths.lhs
g4.left.start (xArchMiddle - CorrectionOMidS * [linreg 72 0.75 108 1 Stroke]) (XH - O)
@ -184,12 +180,20 @@ glyph-block Letter-Latin-Lower-R : begin
create-glyph "r.\(suffix)" : glyph-proc
set-width df.width
include : df.markSet.e
define [object setMarks] : RDim df mode
include : setMarks doTS XH 0
include : F df mode doTS doBS
currentGlyph.copyBaseAnchorIfAbsent 'leaningBelow' 'below'
create-glyph "rLongLeg.\(suffix)" : glyph-proc
set-width df.width
include : df.markSet.p
define [object xBar rBottomSerif] : RDim df mode
define [object xBar rBottomSerif setMarks] : RDim df mode
include : setMarks doTS XH Descender
include : F df mode doTS 0
eject-contour 'serifLB'
include : VBar.r xBar Descender 0
@ -230,11 +234,10 @@ glyph-block Letter-Latin-Lower-R : begin
include : RetroflexHook.rExt xBar 0
create-glyph "rTurnRTail.\(suffix)" : glyph-proc
set-width df.width
include : df.markSet.e
include : F df mode 0 doBS
include [refer-glyph "r.\(suffix)"] AS_BASE ALSO_METRICS
eject-contour 'serifLT'
include : FlipAround df.middle (XH / 2)
include : df.markSet.e
define [object xBar] : RDim df mode
include : RetroflexHook.lExt (df.rightSB - xBar + df.leftSB) 0

View file

@ -67,12 +67,12 @@ glyph-block Letter-Latin-Lower-T : begin
local g : include : HookShapeT dispiro df sym 0 top bot Stroke
local gEnd g.knots.(g.knots.length - 1)
set-base-anchor 'bottomRight' gEnd.x gEnd.y
local xLeft : BarLeftPos df sym
set-base-anchor 'above' (xLeft + [HSwToV HalfStroke]) top
set-base-anchor 'leaningAbove' (xLeft + [HSwToV HalfStroke]) top
set-base-anchor 'hooktopAttach' (xLeft + [HSwToV HalfStroke]) top
set-base-anchor 'below' [mix xLeft gEnd.x : StrokeWidthBlend 0.375 0.5] bot
set-base-anchor 'bottomRight' gEnd.x gEnd.y
set-base-anchor 'overlay' (g.knots.0.x + [HSwToV : 0.625 * Stroke]) (XH * 0.58)
export : define [Retroflex df sym top bot] : Flat.Retroflex df sym top bot
@ -96,9 +96,9 @@ glyph-block Letter-Latin-Lower-T : begin
local gEnd g.rhsKnots.(g.rhsKnots.length - 1)
set-base-anchor 'bottomRight' gEnd.x gEnd.y
set-base-anchor 'above' ([BarLeftPos df sym] + [HSwToV HalfStroke]) top
set-base-anchor 'leaningAbove' ([BarLeftPos df sym] + [HSwToV HalfStroke]) top
set-base-anchor 'hooktopAttach' ([BarLeftPos df sym] + [HSwToV HalfStroke]) top
set-base-anchor 'bottomRight' gEnd.x gEnd.y
set-base-anchor 'overlay' (g.knots.0.x + [HSwToV : 0.125 * Stroke]) (XH * 0.58)
export : define [Retroflex df sym top bot] : Flat.Retroflex df sym top bot
@ -147,7 +147,7 @@ glyph-block Letter-Latin-Lower-T : begin
flat xBarLeft [if (shape === RETROFLEX) (bot + Hook + HalfStroke) hd.y]
curl xBarLeft top [heading Upward]
set-base-anchor 'above' (xBarLeft + [HSwToV HalfStroke]) top
set-base-anchor 'leaningAbove' (xBarLeft + [HSwToV HalfStroke]) top
set-base-anchor 'hooktopAttach' (xBarLeft + [HSwToV HalfStroke]) top
set-base-anchor 'topRight' xCrossRight Ascender
set-base-anchor 'overlay' (xBarLeft + [HSwToV : 0.625 * Stroke]) (XH * 0.58)
@ -172,7 +172,8 @@ glyph-block Letter-Latin-Lower-T : begin
include : HCrossBar.top xcl xcr yCrossBar
set-base-anchor 'overlay' (xLeft + [HSwToV HalfStroke]) (XH * 0.58)
set-base-anchor 'hooktopAttach' (xLeft + [HSwToV HalfStroke]) top
set-base-anchor 'below' (xLeft + [HSwToV HalfStroke]) bot
set-base-anchor 'leaningAbove' (xLeft + [HSwToV HalfStroke]) top
set-base-anchor 'leaningBelow' (xLeft + [HSwToV HalfStroke]) bot
set-base-anchor 'bottomRight' xEnd (bot + Stroke)
set-base-anchor 'lTailHookAttach' xEnd (bot + Stroke)
@ -202,6 +203,8 @@ glyph-block Letter-Latin-Lower-T : begin
set-width df.width
include : df.markSet.b
include : Style.Body df sym top 0
currentGlyph.copyBaseAnchorIfAbsent 'leaningAbove' 'above'
currentGlyph.copyBaseAnchorIfAbsent 'leaningBelow' 'below'
create-glyph "t/phoneticLeft2.\(suffix)" : glyph-proc
set-width df.width

View file

@ -27,6 +27,7 @@ glyph-block Letter-Latin-Upper-F : begin
define xFBarRight : Width - SB * 1.5
define [FShape] : with-params [top pyBar serifLT serifLB serifV [stroke : AdviceStroke2 2 3 top]] : glyph-proc
set-base-anchor 'leaningBelow' (xFBarLeft + [HSwToV : 0.5 * stroke]) 0
include : VBar.l (xFBarLeft) 0 top stroke
include : HBar.t (xFBarLeft - O) RightSB top stroke
include : tagged 'crossBar'

View file

@ -16,6 +16,7 @@ glyph-block Letter-Latin-Upper-L : begin
define [LBarLeftX df] : df.leftSB * 1.5
define [LRightX df] : df.rightSB - 0.75 * OX
define [LShape df top sgr swv] : glyph-proc
set-base-anchor 'leaningAbove' ([LBarLeftX df] + [HSwToV : 0.5 * swv]) top
include : VBar.l [LBarLeftX df] 0 top swv
include : HBar.b ([LBarLeftX df] - O) [LRightX df] 0
if (sgr > 1) : begin

View file

@ -71,7 +71,7 @@ glyph-block Letter-Latin-Upper-P : begin
include : spiro-outline
PShapeOutlineKnots top mul bp overshoot sw offset
define [PShape] : with-params [top [mul PShape.defaultMul] [bp PShape.BarPos] [overshoot PShape.defaultOvershoot] [sw Stroke] [slab null] [withBar true]] : glyph-proc
define [PShape] : with-params [top [mul PShape.defaultMul] [bp PShape.BarPos] [overshoot PShape.defaultOvershoot] [sw Stroke] [slab null] [withBar true] [setMark false]] : glyph-proc
include : dispiro [widths.rhs sw] [PShapeOutlineKnots top mul bp overshoot sw 0]
if withBar : include : tagged 'strokeL' : VBar.l (SB * mul) 0 top sw
if slab : include : slab top sw mul
@ -141,6 +141,7 @@ glyph-block Letter-Latin-Upper-P : begin
create-glyph "P.\(suffix)" : glyph-proc
include : MarkSet.capital
set-base-anchor 'leaningBelow' (SB * PShape.defaultMul + [HSwToV HalfStroke]) 0
include : difference
PShape CAP (slab -- slabs)
if fGap [PShape.OpenGap (top -- CAP) (bot -- [if fSlabBot Stroke 0])] [glyph-proc]
@ -151,6 +152,7 @@ glyph-block Letter-Latin-Upper-P : begin
create-glyph "smcpP.\(suffix)" : glyph-proc
include : MarkSet.e
set-base-anchor 'leaningBelow' (SB * PShape.defaultMul + [HSwToV HalfStroke]) 0
include : difference
PShape XH (slab -- slabs)
if fGap [PShape.OpenGap (top -- XH) (bot -- [if fSlabBot Stroke 0])] [glyph-proc]

View file

@ -4,7 +4,7 @@ import [Arcs Quadify ShapeConv] from "typo-geom"
import [OffsetCurve BezToContoursSink GEOMETRY_PRECISION] from"../../support/geometry/curve-util.mjs"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [ScheduleLeaningMark] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
import [Point] from"../../support/geometry/point.mjs"
@ -30,16 +30,17 @@ glyph-block Mark-Above : begin
define commaAboveRadius : 0.85 * DotRadius * markHalfStroke / HalfStroke
define StdAnchors : namespace
export : define [impl mk padding k] : glyph-proc
export : define [impl mk padding k fLeaning] : glyph-proc
if (mk === 'above')
: then : set-mark-anchor mk markMiddle (XH - padding * AccentHeight) markMiddle (aboveMarkStack + padding * AccentHeight)
: else : set-mark-anchor mk markMiddle (XH - padding * AccentHeight)
set-base-anchor 'aboveBraceL' (markMiddle - k * markExtend) aboveMarkMid
set-base-anchor 'aboveBraceR' (markMiddle + k * markExtend) aboveMarkMid
if fLeaning : ScheduleLeaningMark.set currentGlyph
export : define [narrow] : impl 'above' 0 0
export : define [mediumNarrow] : impl 'above' 0 0.25
export : define [medium] : impl 'above' 0 0.5
export : define [narrow] : impl 'above' 0 0 true
export : define [mediumNarrow] : impl 'above' 0 0.25 true
export : define [medium] : impl 'above' 0 0.5 true
export : define [mediumWide] : impl 'above' 0 0.75
export : define [wide] : impl 'above' 0 1
export : define [extraWide] : impl 'above' 0 1.5
@ -50,6 +51,7 @@ glyph-block Mark-Above : begin
set-width 0
include : StdAnchors.narrow
include : DrawAt markMiddle aboveMarkMid (DotRadius * kdr)
ScheduleLeaningMark.set currentGlyph
create-glyph "dieresisAbove.\(suffix)" : glyph-proc
set-width 0
@ -195,7 +197,7 @@ glyph-block Mark-Above : begin
create-glyph 'circumflexAbove' 0x302 : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaretShape
xMiddle -- markMiddle
width -- CaretCaronWidth
@ -206,7 +208,7 @@ glyph-block Mark-Above : begin
create-glyph 'bardownAbove' 0x1DC6 : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaretRightShape
xMiddle -- markMiddle
width -- CaretCaronWidth
@ -225,7 +227,7 @@ glyph-block Mark-Above : begin
create-glyph 'upbarAbove' 0x1DC7 : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaretLeftShape
xMiddle -- markMiddle
width -- CaretCaronWidth
@ -258,7 +260,7 @@ glyph-block Mark-Above : begin
create-glyph 'caronAbove' 0x30c : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaronShape
xMiddle -- markMiddle
width -- CaretCaronWidth
@ -269,7 +271,7 @@ glyph-block Mark-Above : begin
create-glyph 'barupAbove' 0x1DC4 : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaronRightShape
xMiddle -- markMiddle
width -- CaretCaronWidth
@ -288,7 +290,7 @@ glyph-block Mark-Above : begin
create-glyph 'downbarAbove' 0x1DC5 : glyph-proc
set-width 0
include : StdAnchors.wide
include : StdAnchors.medium
include : CaronLeftShape
xMiddle -- markMiddle
width -- CaretCaronWidth

View file

@ -8,9 +8,15 @@ glyph-block Mark-Adjustment : begin
if currentGlyph.baseAnchors.below : begin
local a : currentGlyph.gizmo.unapply currentGlyph.baseAnchors.below
if (a.y > y) : set-base-anchor 'below' a.x y
if currentGlyph.baseAnchors.leaningBelow : begin
local a : currentGlyph.gizmo.unapply currentGlyph.baseAnchors.leaningBelow
if (a.y > y) : set-base-anchor 'leaningBelow' a.x y
glyph-block-export ExtendAboveBaseAnchors
define [ExtendAboveBaseAnchors y] : glyph-proc
if currentGlyph.baseAnchors.above : begin
local a : currentGlyph.gizmo.unapply currentGlyph.baseAnchors.above
if (a.y < y) : set-base-anchor 'above' a.x y
if currentGlyph.baseAnchors.leaningAbove : begin
local a : currentGlyph.gizmo.unapply currentGlyph.baseAnchors.leaningAbove
if (a.y < y) : set-base-anchor 'leaningAbove' a.x y

View file

@ -3,7 +3,7 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [ScheduleLeaningMark] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
glyph-module
@ -22,14 +22,15 @@ glyph-block Mark-Below : begin
define belowMarkStack (0 - AccentStackOffset)
define StdAnchors : namespace
export : define [impl padding k] : glyph-proc
export : define [impl padding k fLeaning] : glyph-proc
set-mark-anchor 'below' markMiddle (0 + padding * AccentHeight) markMiddle (belowMarkStack - padding * AccentHeight)
set-base-anchor 'belowBraceL' (markMiddle - k * markExtend) belowMarkMid
set-base-anchor 'belowBraceR' (markMiddle + k * markExtend) belowMarkMid
if fLeaning : ScheduleLeaningMark.set currentGlyph
export : define [narrow] : impl 0 0
export : define [mediumNarrow] : impl 0 0.25
export : define [medium] : impl 0 0.5
export : define [narrow] : impl 0 0 true
export : define [mediumNarrow] : impl 0 0.25 true
export : define [medium] : impl 0 0.5 true
export : define [mediumWide] : impl 0 0.75
export : define [wide] : impl 0 1
@ -174,6 +175,7 @@ glyph-block Mark-Below : begin
mirrorAnchor aboveGlyph currentGlyph 'above' 'below'
mirrorAnchor aboveGlyph currentGlyph 'aboveBraceL' 'belowBraceR'
mirrorAnchor aboveGlyph currentGlyph 'aboveBraceR' 'belowBraceL'
if [ScheduleLeaningMark.get aboveGlyph] : ScheduleLeaningMark.set currentGlyph
TurnAboveMarkToBelow 'graveBelow' 0x316 'graveAbove'
TurnAboveMarkToBelow 'acuteBelow' 0x317 'acuteAbove'

View file

@ -3,7 +3,6 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
glyph-module

View file

@ -3,7 +3,6 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
glyph-module

View file

@ -3,7 +3,6 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
glyph-module

View file

@ -3,7 +3,6 @@ $$include '../../meta/macros.ptl'
import [Arcs Quadify ShapeConv] from "typo-geom"
import [mix linreg clamp fallback] from"../../support/utils.mjs"
import [DesignParameters] from"../../meta/aesthetics.mjs"
import [TieMark TieGlyph] from"../../support/gr.mjs"
import [Box] from"../../support/geometry/box.mjs"
glyph-module

View file

@ -300,6 +300,7 @@ class CMarkSet
set this.markAnchors markAnchors
set this.baseAnchors baseAnchors
public [applyToGlyph g] : begin
g.clearAnchors
g.copyAnchors this
export : define [compositeBaseAnchors] : begin

View file

@ -4,8 +4,8 @@ extern Map
extern Set
define MarkClasses {
'above' 'tieAbove' 'topLeft' 'topRight' 'grekUpperTonos' 'aboveBraceL' 'aboveBraceR'
'below' 'tieBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf' 'belowBraceL' 'belowBraceR'
'above' 'tieAbove' 'leaningAbove' 'topLeft' 'topRight' 'grekUpperTonos' 'aboveBraceL' 'aboveBraceR'
'below' 'tieBelow' 'leaningBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf' 'belowBraceL' 'belowBraceR'
'overlay' 'slash' 'strike'
'cvDecompose' 'enclosureInner' 'enclosureInnerFirstHalf' 'enclosureInnerSecondHalf'
@ -13,10 +13,10 @@ define MarkClasses {
}
define MarkInteractions : new Map : list
list 'aboveBraceL' {'aboveBraceL' 'above' 'tieAbove' 'topLeft' 'topRight' 'grekUpperTonos'}
list 'aboveBraceR' {'aboveBraceR' 'above' 'tieAbove' 'topLeft' 'topRight' 'grekUpperTonos'}
list 'belowBraceL' {'belowBraceL' 'below' 'tieBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf'}
list 'belowBraceR' {'belowBraceR' 'below' 'tieBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf'}
list 'aboveBraceL' {'aboveBraceL' 'above' 'tieAbove' 'leaningAbove' 'topLeft' 'topRight' 'grekUpperTonos'}
list 'aboveBraceR' {'aboveBraceR' 'above' 'tieAbove' 'leaningAbove' 'topLeft' 'topRight' 'grekUpperTonos'}
list 'belowBraceL' {'belowBraceL' 'below' 'tieBelow' 'leaningBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf'}
list 'belowBraceR' {'belowBraceR' 'below' 'tieBelow' 'leaningBelow' 'bottomLeft' 'bottomRight' 'trailing' 'lf'}
define MkmkStackingLimit : new Set { 'above' 'below' }

View file

@ -1,7 +1,7 @@
$$include '../meta/macros.ptl'
import [AddCommonFeature AddFeature AddLookup AddFeatureLookup ChainRuleBuilder BeginLookupBlock EndLookupBlock UkMapToLookup UkMap2ToLookup] from"./table-util.mjs"
import [AnyCv Dotless TieMark TieGlyph OgonekTrY IsSuperscript IsSubscript] from"../support/gr.mjs"
import [Dotless TieMark TieGlyph OgonekTrY IsSuperscript IsSubscript LeaningMark LeaningMarkSpacer] from"../support/gr.mjs"
import as UnicodeKnowledge from"../meta/unicode-knowledge.mjs"
extern Set
@ -40,24 +40,18 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define groupLF {}
define dotlessFrom {}
define dotlessTo {}
define TieMarkFrom {}
define TieMarkTo {}
define TieGlyphs {}
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== "."): begin
if g.baseAnchors.lf : groupLF.push gid
if g.baseAnchors.grekUpperTonos : groupGrekUpperTonos.push gid
foreach { gn g } [glyphStore.namedEntries] : if (gn.(0) !== "."): begin
if g.baseAnchors.lf : groupLF.push gn
if g.baseAnchors.grekUpperTonos : groupGrekUpperTonos.push gn
if [Dotless.get g] : begin
dotlessFrom.push gid
dotlessFrom.push gn
dotlessTo.push [Dotless.get g]
if [TieGlyph.get g] : TieGlyphs.push gid
if [TieMark.get g] : begin
TieMarkFrom.push gid
TieMarkTo.push [TieMark.get g]
define [IotaLF] : UkMapToLookup UnicodeKnowledge.iotaBelowToLfTf
define [GrekUpperTonosTf] : UkMapToLookup UnicodeKnowledge.upperGrekMarkToTonosTf
# Dotless transform
export-lookup : AddLookup sink : object
.type 'gsub_chaining'
.ignoreGlyphs [filterMarkByClassNegated markGlyphs 'above']
@ -65,7 +59,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
chain-rule (dotlessFrom ~> dotlessTo) (aboveMark ~> null)
chain-rule groupGrekUpperTonos [GrekUpperTonosTf]
# Iota transform (max 6 middle marks are supported)
# Iota transform
export-lookup : AddLookup sink : object
.type 'gsub_chaining'
.ignoreGlyphs [filterMarkByClassNegated markGlyphs 'below']
@ -84,7 +78,17 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
'brackAbove' { 'leftBrackAbove' 'rightBrackAbove' }
'parenBelow' { 'leftParenBelow' 'rightParenBelow' }
# Tie marks
Ccmp-Group "Tie Mark Transform" : begin
define TieMarkFrom {}
define TieMarkTo {}
define TieGlyphs {}
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== ".") : begin
if [TieGlyph.get g] : TieGlyphs.push gid
if [TieMark.get g] : begin
TieMarkFrom.push gid
TieMarkTo.push [TieMark.get g]
define lookupTieMarkLigature : AddLookup sink : object
.type 'gsub_ligature'
.substitutions : {}.concat
@ -99,13 +103,47 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
inputEnds 3
apply {{.at 1 .lookup lookupTieMarkLigature}}
Ccmp-Group "Leaning Mark Trasnform" : begin
define LeaningAnchorMap : list
list 'above' 'leaningAbove'
list 'below' 'leaningBelow'
foreach { mkCenter mkLeaning } [items-of LeaningAnchorMap] : begin
local basesToConsider {}
local markFrom {}
local markTo {}
local markSpacer {}
local splitMapping {}
foreach { gn g } [glyphStore.namedEntries] : if (gn.(0) !== ".") : begin
if (![markGlyphs.all.has gn] && g.baseAnchors.(mkLeaning)) : basesToConsider.push gn
if (g.markAnchors.(mkCenter) && [LeaningMark.get g] && [LeaningMarkSpacer.get g]) : begin
markFrom.push gn
markTo.push [LeaningMark.get g]
markSpacer.push [LeaningMarkSpacer.get g]
splitMapping.push { gn {[LeaningMarkSpacer.get g] [LeaningMark.get g]} }
define lookupTurnMarkIntoLeaningAndSpacer : AddLookup sink : object
.type 'gsub_multiple'
.substitutions : Object.fromEntries splitMapping
export-lookup : AddLookup sink : object
.type 'gsub_chaining'
.ignoreGlyphs [filterMarkByClassNegated markGlyphs mkCenter]
.rules : list
object
.match { [basesToConsider.concat markSpacer] markFrom }
.inputBegins 1
.inputEnds 2
.apply {{.at 1 .lookup lookupTurnMarkIntoLeaningAndSpacer}}
Ccmp-Group "Rhotic Hook Transform" : begin
define superscripts {}
define subscripts {}
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== "."): begin
if [IsSuperscript.get g] : superscripts.push gid
if [IsSubscript.get g] : subscripts.push gid
foreach { gn g } [glyphStore.namedEntries] : if (gn.(0) !== ".") : begin
if [IsSuperscript.get g] : superscripts.push gn
if [IsSubscript.get g] : subscripts.push gn
export-lookup : AddLookup sink : object
.type 'gsub_chaining'

View file

@ -14,8 +14,14 @@ export class GlyphStore {
namedEntries() {
return this.nameForward.entries();
}
encodedEntries() {
return this.encodingForward.entries();
glyphNames() {
return this.nameForward.keys();
}
*encodedEntries() {
for (const [u, g] of this.encodingForward.entries()) {
const name = this.nameBackward.get(g);
if (name) yield [u, name, g];
}
}
*flattenCodes(g, flatteners) {
{

View file

@ -23,6 +23,10 @@ export class Glyph {
this.ctxTag = null;
}
toString() {
return `<Glyph ${this._m_identifier}>`;
}
get identifier() {
return this._m_identifier;
}
@ -182,6 +186,11 @@ export class Glyph {
this.baseAnchors[id] = new Anchor(mbx, mby).transform(this.gizmo);
}
}
copyBaseAnchorIfAbsent(to, from) {
if (this.baseAnchors[from] && !this.baseAnchors[to]) {
this.baseAnchors[to] = new Anchor(this.baseAnchors[from].x, this.baseAnchors[from].y);
}
}
clearAnchors() {
this.baseAnchors = {};
this.markAnchors = {};

View file

@ -20,6 +20,9 @@ export const LowerYDotAtBelow = LinkedGlyphProp("LowerYDotAtBelow");
export const DependentSelector = LinkedGlyphProp("DependentSelector");
export const MathSansSerif = LinkedGlyphProp("MathSansSerif");
export const VS01 = LinkedGlyphProp("VS01");
export const TieMark = LinkedGlyphProp("TieMark");
export const LeaningMark = LinkedGlyphProp("LeaningMark");
export const LeaningMarkSpacer = LinkedGlyphProp("LeaningMarkSpacer");
function LinkedGlyphProp(key) {
return {
get(glyph) {
@ -30,6 +33,12 @@ function LinkedGlyphProp(key) {
if (typeof toGid !== "string") throw new Error("Must supply a GID instead of a glyph");
if (!glyph.related) glyph.related = {};
glyph.related[key] = toGid;
},
amendName(name) {
return `${key}{${name}}`;
},
amendOtName(name) {
return `${name}.${key}`;
}
};
}
@ -61,25 +70,6 @@ function DecompositionProp(key) {
};
}
export const TieMark = {
tag: "TMRK",
get(glyph) {
if (glyph && glyph.related) return glyph.related.TieMark;
else return null;
},
set(glyph, toGid) {
if (typeof toGid !== "string") throw new Error("Must supply a GID instead of a glyph");
if (!glyph.related) glyph.related = {};
glyph.related.TieMark = toGid;
},
amendName(name) {
return `TieMark{${name}}`;
},
amendOtName(name) {
return name + ".tieMark";
}
};
export const TieGlyph = {
get(glyph) {
if (glyph && glyph.related) return glyph.related.TieGlyph;
@ -109,6 +99,7 @@ export const NeqLigationSlashDotted = BoolProp("NeqLigationSlashDotted");
export const OgonekTrY = BoolProp("OgonekTrY");
export const IsSuperscript = BoolProp("IsSuperscript");
export const IsSubscript = BoolProp("IsSubscript");
export const ScheduleLeaningMark = BoolProp("ScheduleLeaningMark");
export const Joining = {
get(glyph) {
@ -242,6 +233,7 @@ export function getGrTree(gid, grSetList, fnGidToGlyph) {
getGrTreeImpl(gid, grSetList, fnGidToGlyph, sink);
return sink;
}
function getGrTreeImpl(gid, grSetList, fnGidToGlyph, sink) {
if (!grSetList.length) return;
const g = fnGidToGlyph(gid);
@ -463,5 +455,6 @@ export const SvInheritableRelations = [
DependentSelector,
Joining,
NeqLigationSlashDotted,
OgonekTrY
OgonekTrY,
ScheduleLeaningMark
];

View file

@ -80,3 +80,39 @@ export class $NamedParameterPair$ {
this.right = r;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
export const MatchUtil = {
never() {
return false;
},
equal(x) {
return y => y === x;
},
negate(f) {
return x => !f(x);
},
both(a, b) {
return x => a(x) && b(x);
},
either(a, b) {
return x => a(x) || b(x);
}
};
export function constant(x) {
return () => x;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
export const ArrayUtil = {
mapIndexToItems(a, indexes) {
let answer = [];
for (const item of indexes) answer.push(a[item]);
return answer;
},
insertSliceAt(a, i, b) {
a.splice(i, 0, ...b);
}
};