Iosevka/packages/font-glyphs/src/auto-build/composite.ptl
2025-03-16 10:04:27 -04:00

1743 lines
75 KiB
Text

###### Automatic builds
$$include '../meta/macros.ptl'
import [mix linreg clamp fallback] from "@iosevka/util"
import [getGrMesh AnyCvOrCherryPicking CvDecompose Joining hashCv IsCompositeOrLigature NLDAcuteVariant HBSCaronVariant] from "@iosevka/glyph/relation"
import [hashGeometry] from "@iosevka/geometry"
import [Transform] from "@iosevka/geometry/transform"
extern Map
extern Set
glyph-module
define DECOMPOSABLE true
define NON-DECOMPOSABLE false
define CENTERED true
define NOT-CENTERED false
define ALLOW-PROPORTIONAL true
define MONOSPACE-ONLY false
glyph-block Autobuild-Enclosure-Shared : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-export CircNameNoCheck
define [CircNameNoCheck unicode prefix parts suffix] : begin
local baseName : prefix + '{' + unicode + '}{' + [parts.join '}{'] + '}'
return : if suffix (baseName + "." + suffix) baseName
glyph-block-export CircName
define [CircName unicode prefix parts suffix] : begin
local name : CircNameNoCheck unicode prefix parts suffix
if [query-glyph name] : begin
throw : new Error "Glyph exists : \(name)"
return name
glyph-block-export EnsureComponentGlyphT
define [EnsureComponentGlyphT gnPart fnBuildup] : begin
local rs : new Set
return : DeriveMeshT { gnPart } AnyCvOrCherryPicking
function [gns gr] : fnBuildup gns.0
function [gniFrom gniTo] : begin
[query-glyph gniFrom].tryBecomeMirrorOf [query-glyph gniTo] rs
glyph-block-export getGlyphDefaultShift
define [getGlyphDefaultShift bal baly g] : begin
if (g && g.baseAnchors.above && g.baseAnchors.below) : begin
if bal : return : CAP / 2 - [mix baly [mix g.baseAnchors.above.y g.baseAnchors.below.y 0.5] bal]
: else : return : CAP / 2 - [mix g.baseAnchors.above.y g.baseAnchors.below.y 0.5]
return 0
glyph-block-export CollectJobs
define [CollectJobs globallyDecomposable centered allowProportional prefix suffix demands] : begin
local nonDecomposable { }
local decomposableJobs { }
local relApplications { }
local decomposableRelGlyphs : new Set
foreach demand [items-of demands] : do
local unicode demand.0
local parts demand.1
local restInfo : demand.slice 2
local origJobGlyphGn : CircName unicode prefix parts suffix
local demandDecomposable : para.enableCvSs && globallyDecomposable
foreach part [items-of parts] : if [query-glyph part] : begin
local g : query-glyph part
local relatedGlyphs : AnyCvOrCherryPicking.query g
foreach gr [items-of relatedGlyphs] : if [query-glyph : gr.get g] : begin
# Multi-part enclosure, proportinal
if (allowProportional && [query-glyph : gr.get g].advanceWidth != g.advanceWidth)
set demandDecomposable false
# Multi-part enclosure, different Y-offset
if (centered && [getGlyphDefaultShift 0 0 : query-glyph : gr.get g] != [getGlyphDefaultShift 0 0 g])
set demandDecomposable false
local jobsOrig : if demandDecomposable decomposableJobs nonDecomposable
jobsOrig.push { origJobGlyphGn unicode parts :: restInfo }
if demandDecomposable
: then : foreach part [items-of parts] : begin
local mesh : getGrMesh { part } AnyCvOrCherryPicking query-glyph
foreach {gr fromParts toParts} [items-of mesh] : foreach gn [items-of toParts]
decomposableRelGlyphs.add gn
: else : begin
local mesh : getGrMesh parts AnyCvOrCherryPicking query-glyph
foreach {gr fromParts toParts} [items-of mesh] : do
local fromGn : CircNameNoCheck unicode prefix fromParts suffix
local toGn : CircName unicode prefix toParts suffix
nonDecomposable.push { toGn null toParts :: restInfo }
relApplications.push { gr fromGn toGn }
return : object nonDecomposable decomposableJobs decomposableRelGlyphs relApplications
glyph-block-export CreateDerivedFontFromJobs
define [CreateDerivedFontFromJobs aj restGids fn] : begin
define [object nonDecomposable decomposableJobs decomposableRelGlyphs] aj
local pendingGlyphs : new Set restGids
foreach gn decomposableRelGlyphs : pendingGlyphs.add gn
foreach {gnf unicode parts} [items-of nonDecomposable] : foreach gn [items-of parts]
pendingGlyphs.add gn
foreach {gnf unicode parts} [items-of decomposableJobs] : foreach gn [items-of parts]
pendingGlyphs.add gn
return : fn : Array.from pendingGlyphs
glyph-block-export applyRelations
define [applyRelations relApplications] : begin
local rs : new Set
foreach {gr f t} [items-of relApplications] : begin
if [query-glyph f] : begin
gr.set [query-glyph f] t
if [query-glyph t] : [query-glyph t].tryBecomeMirrorOf [query-glyph f] rs
glyph-block AutoBuild-Enclosure : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Fork Miniature MiniatureParaT
glyph-block-import Autobuild-Enclosure-Shared : CircNameNoCheck CircName CollectJobs EnsureComponentGlyphT CreateDerivedFontFromJobs applyRelations getGlyphDefaultShift
define circleWidthClasses {{'NWID' Width 0.12} {'WWID' WideWidth0 0.08}}
define [AdjustDigitCount digits width] : Math.max 1 (digits * Width / width)
define [EnclosureStrokeScale dscale digits width] : dscale / ([AdjustDigitCount digits width] ** 0.66)
define enclosureInnerPartActualWidth : new Map
define [GlyphNameInnerOf gniPrefix subGlyph mp actualWidth accumulatedTfm] : begin
define nameParts : list mp actualWidth accumulatedTfm
hashGeometry subGlyph.geometry
hashCv subGlyph
return : '.ci.' + gniPrefix + '/' + [nameParts.join '/']
define [EnsureInnerSubGlyphImpl inners markClass miniatureFont mp actualWidth accumulatedTfm] : function [gidPart] : begin
define subGlyph : miniatureFont.queryByNameEnsured gidPart
define gniPart : GlyphNameInnerOf inners.gniPrefix subGlyph mp actualWidth accumulatedTfm
if [query-glyph gniPart] : return gniPart
enclosureInnerPartActualWidth.set gniPart (actualWidth)
create-glyph gniPart : glyph-proc
set-width 0
set-mark-anchor 'compositeInner' 0 0
include : inners.buildInnerShape subGlyph
include accumulatedTfm
include : inners.addAnchors mp markClass actualWidth
return gniPart
define [EnsureInnerSubGlyphSeq inners markClass miniatureFont job dimens yCompress kExtraYShift] : begin
define { gn unicode parts w bal baly } job
define [object width mockInnerWidth dscale] dimens
local totalWidth 0
local firstDerivedGyph null
foreach [gidPart : items-of parts] : do
local derivedGlyph : miniatureFont.queryByNameEnsured gidPart
if [not firstDerivedGyph] : set firstDerivedGyph derivedGlyph
set totalWidth : totalWidth + derivedGlyph.advanceWidth
local xCompress : inners.getXScalar parts.length markClass mockInnerWidth totalWidth
set totalWidth : Math.min mockInnerWidth totalWidth
local shift : inners.getShift bal baly firstDerivedGyph
local accumulatedTfm : Transform.Combine
firstDerivedGyph.gizmo.inverse
Scale (dscale * xCompress) (dscale * yCompress)
Translate 0 (dscale * shift + SymbolMid + (kExtraYShift - 0.5) * CAP * dscale)
begin firstDerivedGyph.gizmo
local finalParts {}
foreach partIndex [range 0 parts.length] : do
local gidPart parts.(partIndex)
local actualWidth : [miniatureFont.queryByNameEnsured gidPart].advanceWidth * dscale * xCompress
finalParts.push : EnsureComponentGlyphT gidPart
EnsureInnerSubGlyphImpl inners markClass miniatureFont (parts.length > 1) actualWidth accumulatedTfm
return finalParts
define [EnclosureInnerImpl dimens finalParts] : glyph-proc
define [object width] dimens
local totalInnerWidth 0
foreach [gniPart : items-of finalParts] : begin
set totalInnerWidth : totalInnerWidth + ([enclosureInnerPartActualWidth.get gniPart] || 0)
local x : 0.5 * width - 0.5 * totalInnerWidth
foreach [gniPart : items-of finalParts] : begin
include : with-transform [Translate x 0] : refer-glyph gniPart
set x : x + ([enclosureInnerPartActualWidth.get gniPart] || 0)
define [EnclosureInner dimens inners miniatureFont job] : glyph-proc
define { gn unicode parts w bal baly } job
define [object width] dimens
local finalParts : EnsureInnerSubGlyphSeq inners 'enclosureInner' miniatureFont job dimens 1 0
include : new-glyph : EnclosureInnerImpl dimens finalParts
return finalParts
define [TwoRowEnclosureInner dimens inners miniatureFont job] : glyph-proc
define { gn unicode parts w bal baly } job
define [object width] dimens
local jobFirstHalf { gn unicode [parts.slice 0 (parts.length / 2)] w bal baly }
local jobSecondHalf { gn unicode [parts.slice (parts.length / 2) ] w bal baly }
local finalPartsFirstHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerFirstHalf" miniatureFont jobFirstHalf dimens 0.55 (+0.55)
local finalPartsSecondHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerSecondHalf" miniatureFont jobSecondHalf dimens 0.55 (-0.10)
return : {}.concat finalPartsFirstHalf finalPartsSecondHalf
define [PlayingCardInner dimens inners miniatureFont job] : glyph-proc
define { gn unicode parts w bal baly } job
define [object width] dimens
local jobFirstHalf { gn unicode [parts.slice 0 (parts.length / 2)] w bal baly }
local jobSecondHalf { gn unicode [parts.slice (parts.length / 2) ] w bal baly }
local finalPartsFirstHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerFirstHalf" miniatureFont jobFirstHalf dimens 0.6 (+0.55)
local finalPartsSecondHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerSecondHalf" miniatureFont jobSecondHalf dimens 0.6 (-0.15)
return : {}.concat finalPartsFirstHalf finalPartsSecondHalf
define [CircCrowd digits width] : 2 + 2 * ([AdjustDigitCount digits width] ** (2 / 3)) * [Math.max 1 (HalfUPM / Width)]
define [CircScale digits width] : 0.65 / ([AdjustDigitCount digits width] ** (1 / 2))
define [CircleDimens digits w m] : begin
define width : fallback w Width
define dscale : linreg HalfUPM 0.55 UPM 0.6 width
define spatt : [linreg HalfUPM 0.22 UPM 0.27 width] * (Width / HalfUPM)
define sw0 : [EnclosureStrokeScale dscale digits width] * [AdviceStroke : CircCrowd digits width] / [CircScale digits width]
define sw : Math.max sw0 [fallback m 0]
define top : SymbolMid + CAP * dscale / 2 + (CAP * spatt)
define bot : SymbolMid - CAP * dscale / 2 - (CAP * spatt)
define mosaicLeft 0
define mosaicRight width
define mosaicBot fontMetrics.os2.sTypoDescender
define mosaicTop fontMetrics.os2.sTypoAscender
define left : Math.max
SB + O * 3
Math.min
width / 2 - (top - bot) / 2
width / 2 - CAP / 2 * dscale - sw * 2.5
define right : Math.min
width - SB - O * 3
Math.max
width / 2 + (top - bot) / 2
width / 2 + CAP / 2 * dscale + sw * 2.5
define mockInnerWidth : width + 2 * (Stroke - sw) * dscale
define archDepthA : ArchDepthAOf (SmallArchDepth * (right - left) / (RightSB - SB)) width
define archDepthB : ArchDepthBOf (SmallArchDepth * (right - left) / (RightSB - SB)) width
return : object width mockInnerWidth dscale sw0 sw top bot left right mosaicTop mosaicBot mosaicLeft mosaicRight archDepthA archDepthB
define StandardInners : object
gniPrefix ''
buildInnerShape : function [subGlyph] : return subGlyph
getXScalar : function [nParts markClass mockInnerWidth totalWidth] : begin
Math.min 1 (mockInnerWidth / totalWidth)
getShift getGlyphDefaultShift
getPara : function [pp digits rows width] : MiniatureParaT pp
crowd -- [CircCrowd (digits / rows) width]
scale -- [CircScale (digits / rows) width]
sbscale -- 1
mono -- (digits > 1)
mono2 -- (digits > 1)
addAnchors : function [fMultiPart markClass actualWidth] : glyph-proc
if fMultiPart
: then : set-mark-anchor markClass 0 0 (actualWidth) 0
: else : set-mark-anchor markClass (actualWidth / 2) 0
define PlayingCardInners : object
gniPrefix 'pk'
buildInnerShape StandardInners.buildInnerShape
getPara StandardInners.getPara
getShift : function [] : return 0
getXScalar : function [nParts markClass] : begin
if (nParts > 1 && markClass === 'enclosureInnerFirstHalf')
: then : return 0.5
: else : return 0.6
addAnchors : function [fMultiPart markClass actualWidth] : glyph-proc
if (markClass === 'enclosureInnerFirstHalf')
: then : set-mark-anchor markClass 0 0 actualWidth 0 # left-to-right
: else : set-mark-anchor markClass actualWidth 0 0 0 # right-to-left
define DecomposableInsetInners : object
gniPrefix 'd'
getShift StandardInners.getShift
addAnchors StandardInners.addAnchors
getXScalar StandardInners.getXScalar
buildInnerShape : function [subGlyph] : difference
Rect (1.05 * CAP - O) (-0.05 * CAP + O) O (Width - O)
begin subGlyph
getPara : function [pp digits rows width] : MiniatureParaT pp
crowd -- [CircCrowd (digits / rows) width]
scale -- [CircScale (digits / rows) width]
sbscale -- 1
mono -- true
mono2 -- true
define ItalicInners : object
gniPrefix 'i'
getShift StandardInners.getShift
buildInnerShape StandardInners.buildInnerShape
addAnchors StandardInners.addAnchors
getXScalar StandardInners.getXScalar
getPara : function [pp digits rows width] : begin
define pp1 : pp.createFork : function [a] : begin
set a.shape.slope 'italic'
set a.shape.slopeAngle : mix (para.slopeAngle || 0) 15 (95 / 150)
return : StandardInners.getPara pp1 digits rows width
define [EnclosureT prefix builder inners digits rows demands fnEnclosure] : begin
foreach {suffix ww gap} [items-of circleWidthClasses] : do
define allowProportional : if (digits > 1) MONOSPACE-ONLY ALLOW-PROPORTIONAL
define jobs : CollectJobs builder.decomposable CENTERED allowProportional (prefix + digits) suffix demands
define forkedPara : inners.getPara para digits rows ww
define miniatureFont : CreateDerivedFontFromJobs jobs {} : function [gs] : Fork gs forkedPara
define gnEnclosure : CircName null (prefix + digits + '.enclosure') {} suffix
define [buildImpl job decomposable] : begin
define { gn unicode parts w bal baly } job
if [query-glyph gn] : return nothing
create-glyph gn [if (w == ww) unicode null] : glyph-proc
define dimens : CircleDimens digits ww
set-width dimens.width
include : builder.buildGlyph dimens inners miniatureFont decomposable job gnEnclosure
# if decomposable gnEnclosure null
if [not : query-glyph gnEnclosure] : create-glyph gnEnclosure : fnEnclosure digits ww gap
foreach job [items-of jobs.decomposableJobs] : buildImpl job true
foreach job [items-of jobs.nonDecomposable] : buildImpl job false
applyRelations jobs.relApplications
# Builders and Enclosure Shapes
define CircledBuilder : object
decomposable true
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
include : refer-glyph gnEnclosure
local parts : include : EnclosureInner dimens inners miniatureFont job
if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]
define DecomposableInsetBuilder : object
decomposable true
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
include : CircledBuilder.buildGlyph dimens inners miniatureFont decomp job gnEnclosure
include : radicalize
define TwoRowBoxedBuilder : object
decomposable true
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
include [refer-glyph gnEnclosure] AS_BASE ALSO_METRICS
local parts : include : TwoRowEnclosureInner dimens inners miniatureFont job
foreach [part : items-of parts] : include : refer-glyph part
if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]
define PlayingCardBuilder : object
decomposable true
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
include [refer-glyph gnEnclosure] AS_BASE ALSO_METRICS
local parts : include : PlayingCardInner dimens inners miniatureFont job
foreach [part : items-of parts] : include : refer-glyph part
if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]
define InsetBuilder : object
decomposable false
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : difference
refer-glyph gnEnclosure
EnclosureInner dimens inners miniatureFont job
define InsetWithGapBuilder : object
decomposable false
buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : begin
define [object top bot left right] dimens
local gap : Math.max [AdviceStroke 6] (Width * 0.08)
local [inner] : EnclosureInner dimens inners miniatureFont job
return : difference
intersection
Rect top bot left right
union
refer-glyph gnEnclosure
remove-holes [inner]
with-outlined gap [inner]
inner
define [AddEnclosureMark digits dimens] : glyph-proc
define [object width dscale mockInnerWidth] dimens
if (digits > 1)
set-base-anchor 'enclosureInner' (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0
set-base-anchor 'enclosureInner' (0.5 * width) 0
define [createCircledGlyphs digits demands]
EnclosureT "circle" CircledBuilder StandardInners digits 1 demands CircleEnclosureShape
define [createBackslashCircledGlyphs digits demands]
EnclosureT "circle-slashed" CircledBuilder StandardInners digits 1 demands BackslashCircleEnclosureShape
define [createItalicCircledGlyphs digits demands]
EnclosureT "circle-italic" CircledBuilder ItalicInners digits 1 demands CircleEnclosureShape
define [CircleEnclosureShape digits ww gap] : glyph-proc
define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
set-width width
include : OShape top bot left right sw archDepthA archDepthB
include : AddEnclosureMark digits : CircleDimens digits ww
define [BackslashCircleEnclosureShape digits ww gap] : glyph-proc
include : CircleEnclosureShape digits ww gap
define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
include : intersection
OShapeOutline top bot left right sw archDepthA archDepthB
dispiro
flat 0 [mix bot top 0.77] [widths.center sw]
curl width [mix bot top (1 - 0.77)]
define [createBoxedGlyphs digits demands]
EnclosureT 'boxed' CircledBuilder StandardInners digits 1 demands BoxEnclosureShape
define [BoxEnclosureShape digits ww gap] : glyph-proc
define [object width sw top bot left right] : CircleDimens digits ww
set-width width
include : union
HBar.t left right top sw
HBar.b left right bot sw
VBar.l left bot top sw
VBar.r right bot top sw
include : AddEnclosureMark digits : CircleDimens digits ww
define [createTwoRowBoxedGlyphs digits demands]
EnclosureT 'twoRowBoxed' TwoRowBoxedBuilder StandardInners digits 2 demands TwoRowBoxEnclosureShape
define [TwoRowBoxEnclosureShape digits ww gap] : glyph-proc
define [object width sw top bot left right] : CircleDimens digits ww
set-width width
include : union
HBar.t left right top sw
HBar.b left right bot sw
VBar.l left bot top sw
VBar.r right bot top sw
include : AddEnclosureMarkTwoLine digits : CircleDimens digits ww
define [AddEnclosureMarkTwoLine digits dimens] : glyph-proc
define [object width dscale mockInnerWidth] dimens
set-base-anchor 'enclosureInnerFirstHalf' (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0
set-base-anchor 'enclosureInnerSecondHalf' (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0
define [createPlayingCardGlyphs digits demands]
EnclosureT 'playingCard' PlayingCardBuilder PlayingCardInners digits 2 demands PlayingCardEnclosure.Shape
define [createTrumpCardGlyphs digits demands]
EnclosureT 'trumpCard' CircledBuilder StandardInners digits 1 demands PlayingCardEnclosure.TrumpShape
define [createPlayingCardBackGlyphs digits demands]
EnclosureT 'playingCardBack' InsetBuilder StandardInners digits 1 demands PlayingCardEnclosure.BackShape
define PlayingCardEnclosure : namespace
define [Gap dimens] : begin
local [object left right sw] dimens
return : Math.max ((right - left) / 16) (sw / 2)
define [CornerRadius dimens] : begin
define [object sw left right] dimens
return : 1.5 * sw + [Gap dimens]
define [BorderShape dimens kSw] : glyph-proc
local [object width sw top bot left right] dimens
local r : CornerRadius dimens
include : dispiro
widths.rhs (kSw * sw)
curl (right - r) top [heading Rightward]
archv
flat right (top - r) [heading Downward]
curl right (bot + r) [heading Downward]
arcvh
flat (right - r) bot [heading Leftward]
curl (left + r) bot [heading Leftward]
archv
flat left (bot + r) [heading Upward]
curl left (top - r) [heading Upward]
arcvh
flat (left + r) top [heading Rightward]
close
define [BackFillShape dimens] : glyph-proc
local [object width sw top bot left right] dimens
local gap : Gap dimens
local rD : [CornerRadius dimens] - sw - gap
local topD : top - sw - gap
local botD : bot + sw + gap
local leftD : left + sw + gap
local rightD : right - sw - gap
include : spiro-outline
widths.rhs sw
curl (rightD - rD) topD [heading Rightward]
archv
flat rightD (topD - rD) [heading Downward]
curl rightD (botD + rD) [heading Downward]
arcvh
flat (rightD - rD) botD [heading Leftward]
curl (leftD + rD) botD [heading Leftward]
archv
flat leftD (botD + rD) [heading Upward]
curl leftD (topD - rD) [heading Upward]
arcvh
flat (leftD + rD) topD [heading Rightward]
close
define [TwoRowMarks dimens] : glyph-proc
local [object left right sw] dimens
local gap : Gap dimens
set-base-anchor 'enclosureInnerFirstHalf' (left + sw + gap) 0
set-base-anchor 'enclosureInnerSecondHalf' (right - sw - gap) 0
export : define [Shape digits ww] : glyph-proc
local dimens : CircleDimens [Math.max digits 3] ww
set-width dimens.width
include : BorderShape dimens 1
include : TwoRowMarks dimens
export : define [TrumpShape digits ww] : glyph-proc
local dimens : CircleDimens [Math.max digits 3] ww
set-width dimens.width
include : BorderShape dimens 1
include : AddEnclosureMark digits : CircleDimens digits ww
export : define [BackShape digits ww] : glyph-proc
local dimens : CircleDimens [Math.max digits 3] ww
set-width dimens.width
include : BorderShape dimens 0.5
include : BackFillShape dimens
include : AddEnclosureMark digits : CircleDimens digits ww
define [createDashedBoxedGlyphs digits demands]
EnclosureT 'dashed-boxed' CircledBuilder StandardInners digits 1 demands DashedBoxEnclosureShape
define [DashedBoxEnclosureShape digits ww cap] : glyph-proc
define [object width sw top bot left right] : CircleDimens digits ww
set-width width
include : difference
union
HBar.t left right top sw
HBar.b left right bot sw
VBar.l left bot top sw
VBar.r right bot top sw
union
VBar.m [mix left right 0.25] bot top sw
VBar.m [mix left right 0.50] bot top sw
VBar.m [mix left right 0.75] bot top sw
HBar.m left right [mix bot top 0.25] sw
HBar.m left right [mix bot top 0.50] sw
HBar.m left right [mix bot top 0.75] sw
include : AddEnclosureMark digits : CircleDimens digits ww
define [createInsetCircledGlyphs digits demands]
EnclosureT 'inset-circle' InsetBuilder StandardInners digits 1 demands InsetCircleEnclosureShape
define [InsetCircleEnclosureShape digits ww gap] : glyph-proc
define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
set-width width
include : OShapeOutline top bot left right sw archDepthA archDepthB
include : AddEnclosureMark digits : CircleDimens digits ww
define [createInsetBoxedGlyphs digits demands]
EnclosureT 'inset-boxed' InsetBuilder StandardInners digits 1 demands InsetBoxEnclosureShape
define [InsetBoxEnclosureShape digits ww gap] : glyph-proc
define [object width top bot left right] : CircleDimens digits ww
set-width width
include : Rect top bot left right
include : AddEnclosureMark digits : CircleDimens digits ww
define [createDecomposableInsetCircledGlyphs digits demands]
EnclosureT 'inset-circle-decomp' DecomposableInsetBuilder DecomposableInsetInners digits 1 demands DecomposableInsetCircleEnclosureShape
define [DecomposableInsetCircleEnclosureShape digits ww gap] : glyph-proc
define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
set-width width
include : difference
OShapeOutline top bot left right sw archDepthA archDepthB
DecomposableInsetKnockout digits ww
include : AddEnclosureMark digits : CircleDimens digits ww
define [createDecomposableInsetBoxedGlyphs digits demands]
EnclosureT 'inset-boxed-decomp' DecomposableInsetBuilder DecomposableInsetInners digits 1 demands DecomposableInsetBoxEnclosureShape
define [DecomposableInsetBoxEnclosureShape digits ww gap] : glyph-proc
define [object width top bot left right] : CircleDimens digits ww
set-width width
include : difference
Rect top bot left right
DecomposableInsetKnockout digits ww
include : AddEnclosureMark digits : CircleDimens digits ww
define [DecomposableInsetKnockout digits ww] : begin
define [object top bot left right dscale mockInnerWidth] : CircleDimens digits ww
local xMid : mix left right 0.5
local yMid : mix bot top 0.5
local halfHeight : CAP * 0.55 * dscale
local halfWidth : [Math.min (digits * Width) mockInnerWidth] * 0.5 * dscale
return : Rect (yMid + halfHeight) (yMid - halfHeight) (xMid - halfWidth) (xMid + halfWidth)
define [createCrossInsetBoxedGlyphs digits demands]
EnclosureT 'cross-inset-boxed' InsetWithGapBuilder StandardInners digits 1 demands CrossInsetSquareShape
define [CrossInsetSquareShape digits ww gap] : glyph-proc
define [object width sw top bot left right] : CircleDimens digits ww
set-width width
include : difference
Rect top bot left right
ExtLineCenter (-0.1) sw left bot right top
ExtLineCenter (-0.1) sw right bot left top
include : AddEnclosureMark digits : CircleDimens digits ww
define [createInsetDiamondGlyphs digits demands]
EnclosureT 'inset-diamond' InsetBuilder StandardInners digits 1 demands InsetDiamondEnclosureShape
define [InsetDiamondEnclosureShape digits ww gap] : glyph-proc
define [object width top bot left right] : CircleDimens digits ww
set-width width
include : spiro-outline
corner (left + O) [mix bot top 0.5]
corner [mix left right 0.5] (bot + O)
corner (right - O) [mix bot top 0.5]
corner [mix left right 0.5] (top - O)
close
include : AddEnclosureMark digits : CircleDimens digits ww
define [createInsetMosaicGlyphs digits demands]
EnclosureT 'inset-mosaic' InsetBuilder StandardInners digits 1 demands InsetMosaicEnclosureShape
define [InsetMosaicEnclosureShape digits ww gap] : glyph-proc
define [object width mosaicTop mosaicBot mosaicLeft mosaicRight] : CircleDimens digits ww
set-width width
include : ForceUpright
include : Rect mosaicTop mosaicBot mosaicLeft mosaicRight
include : AddEnclosureMark digits : CircleDimens digits ww
define [createDoubleCircledGlyphs digits demands]
EnclosureT 'double-circle' CircledBuilder StandardInners digits 1 demands DoubleCircledEnclosureShape
define [DoubleCircledEnclosureShape digits ww gap] : glyph-proc
define [object width sw0 sw top bot left right archDepthA archDepthB] : CircleDimens digits ww (ww * gap)
set-width width
define sw1 : Math.min sw0 (sw / 3)
include : OShape top bot left right sw1 archDepthA archDepthB
include : OShape
top - sw + sw1
bot + sw - sw1
left + [HSwToV sw] - [HSwToV sw1]
right - [HSwToV sw] + [HSwToV sw1]
begin sw1
archDepthA - sw + sw1
archDepthB - sw + sw1
include : AddEnclosureMark digits : CircleDimens digits ww
define [BraceCrowd digits width] : 2.75 + [AdjustDigitCount digits width]
define [BraceScale digits width] : 0.65 / ([AdjustDigitCount digits width] ** (1 / 2))
define [bracedDottedDimens digits width] : begin
define dscale : linreg Width 0.55 UPM 0.65 width
define pscale : linreg Width 0.6 UPM 0.75 width
define sw0 : [EnclosureStrokeScale dscale digits width] * [AdviceStroke : BraceCrowd digits width] / [BraceScale digits width]
define sw : Math.min Stroke sw0
define l : Math.max (SB + O * 3) (width / 2 - [Math.max (Width * digits) CAP] / 2)
define r : width - l
define mockInnerWidth : width + 2 * (Stroke - sw) * dscale
return : object width sw dscale pscale l r mockInnerWidth
define [BracedT rawPrefix digits demands fnBraceShape] : foreach {suffix ww} [items-of circleWidthClasses] : do
define prefix : rawPrefix + digits
define jobs : CollectJobs DECOMPOSABLE CENTERED ALLOW-PROPORTIONAL prefix suffix demands
define miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
crowd -- [BraceCrowd digits ww]
scale -- [BraceScale digits ww]
sbscale -- 1
define gnb : CircName prefix ('.braced-brace' + digits) {} suffix
if [not : query-glyph gnb] : create-glyph gnb : fnBraceShape digits ww
define [CreateGlyphImpl jobDecomposable job] : begin
local {gn unicode parts w bal baly} job
if [not : query-glyph gn] : create-glyph gn [if (w == ww) unicode null] : glyph-proc
define dimens : bracedDottedDimens digits ww
define [object width] dimens
set-width width
include : refer-glyph gnb
local parts : include : EnclosureInner dimens StandardInners miniatureFont job
if jobDecomposable : CvDecompose.set currentGlyph [{gnb}.concat parts]
foreach job [items-of jobs.decomposableJobs] : CreateGlyphImpl true job
foreach job [items-of jobs.nonDecomposable] : CreateGlyphImpl false job
applyRelations jobs.relApplications
define [createBracedGlyphs digits demands] : BracedT 'braced' digits demands BraceShape
define [BraceShape digits ww] : glyph-proc
define [object width pscale sw l r] : bracedDottedDimens digits ww
local s : TanSlope * SymbolMid / 2
local p : 0.1 * [Math.sqrt : Math.min 1 (width / (digits * Width))]
set-width width
include : dispiro
widths.lhs sw
g4 ([mix l r p] - s) (ParenTop * pscale)
g4.down.mid (l - s + O) (SymbolMid * pscale)
g4 ([mix l r p] - s) (ParenBot * pscale)
include : dispiro
widths.rhs sw
g4 ([mix r l p] + s) (ParenTop * pscale)
g4.down.mid (r + s - O) (SymbolMid * pscale)
g4 ([mix r l p] + s) (ParenBot * pscale)
include : Ungizmo
include : Translate 0 (SymbolMid - SymbolMid * pscale)
include : Regizmo
include : AddEnclosureMark digits : bracedDottedDimens digits ww
define [createHexBracedGlyphs digits demands] : BracedT 'hex-braced' digits demands HexBracedShape
define [HexBracedShape digits ww] : glyph-proc
define [object width pscale sw l r] : bracedDottedDimens digits ww
local s : TanSlope * SymbolMid / 2
local p : (1 / 6) * [Math.sqrt : Math.min 1 (width / (digits * Width))]
set-width width
include : dispiro
widths.lhs sw
corner ([mix l r p] - s) (ParenTop * pscale)
corner (l - s + O) (ParenTop * pscale - p * (r - l))
include : dispiro
widths.lhs sw
corner (l - s + O) (ParenTop * pscale - p * (r - l))
corner (l - s + O) (ParenBot * pscale + p * (r - l))
include : dispiro
widths.lhs sw
corner (l - s + O) (ParenBot * pscale + p * (r - l))
corner ([mix l r p] - s) (ParenBot * pscale)
include : dispiro
widths.rhs sw
corner ([mix r l p] + s) (ParenTop * pscale)
corner (r + s - O) (ParenTop * pscale - p * (r - l))
include : dispiro
widths.rhs sw
corner (r + s - O) (ParenTop * pscale - p * (r - l))
corner (r + s - O) (ParenBot * pscale + p * (r - l))
include : dispiro
widths.rhs sw
corner (r + s - O) (ParenBot * pscale + p * (r - l))
corner ([mix r l p] + s) (ParenBot * pscale)
include : Ungizmo
include : Translate 0 (SymbolMid - SymbolMid * pscale)
include : Regizmo
include : AddEnclosureMark digits : bracedDottedDimens digits ww
define [DottedCrowd digits width] : 2 + [AdjustDigitCount digits width]
define [DottedScale digits width] : 1 / ([AdjustDigitCount digits width] ** (1 / 2))
define [createDottedGlyphs digits demands] : begin
foreach {suffix ww} [items-of circleWidthClasses] : do
define jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL ('dotted' + digits) suffix demands
local miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs]: Miniature gs
crowd -- [DottedCrowd digits ww]
scale -- [DottedScale digits ww]
sbscale -- 1
define [ensureDottedPartImpl item offset xCompress xTranslate] : lambda [gidPart] : begin
define gniPart : '.dotted-inner.' + gidPart + '@' + [{ item digits offset xCompress xTranslate }.join '/']
if [query-glyph gniPart] : return gniPart
create-glyph gniPart : glyph-proc
set-width 0
set-mark-anchor 'compositeInner' 0 0
include : miniatureFont.queryByNameEnsured gidPart
include : Ungizmo
include : Translate offset 0
include : Scale xCompress 1
include : Translate xTranslate 0
include : Regizmo
return gniPart
define [createDottedGlyphImpl job jobDecomposable] : begin
local {gn unicode partsWithDot w} job
define [object width dscale pscale sw l r] : bracedDottedDimens 1 ww
local totalWidth 0
local offsets { }
foreach [j : range 0 partsWithDot.length] : begin
local gidPart partsWithDot.(j)
if j : set totalWidth : totalWidth - SB
set offsets.(j) totalWidth
set totalWidth : totalWidth + [miniatureFont.queryByNameEnsured gidPart].advanceWidth
set totalWidth : totalWidth - SB
local xCompress : if (totalWidth > width) (width / totalWidth) 1
local xTranslate : [if (totalWidth > width) 0 (width / 2 - totalWidth / 2)] - width
if [not : query-glyph gn] : create-glyph gn [if (w == ww) unicode null] : glyph-proc
set-width width
local ps {gnSpace}
foreach [j : range 0 partsWithDot.length] : begin
local gidPart partsWithDot.(j)
local p : EnsureComponentGlyphT gidPart : ensureDottedPartImpl j offsets.(j) xCompress xTranslate
include : refer-glyph p
ps.push p
include : Translate width 0
if jobDecomposable : CvDecompose.set currentGlyph ps
define gnSpace : '.dotted-space.' + [{ digits suffix }.join '/']
if [not : query-glyph gnSpace] : create-glyph gnSpace : glyph-proc
set-width ww
foreach job [items-of jobs.nonDecomposable] : createDottedGlyphImpl job false
foreach job [items-of jobs.decomposableJobs] : createDottedGlyphImpl job true
applyRelations jobs.relApplications
# Circled & Braced
define [digitGlyphNames j suffix] : begin
local digitNumberToNameMap { 'zero' 'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine' }
local digits : [String j].split '' :.map [function x (x - 0)]
local names { }
foreach digit [items-of digits] : begin
names.push : digitNumberToNameMap.(digit) + [[fallback suffix digitNoSuffix] digit] + '.lnum'
return names
define [digitNoSuffix d] : return ''
define [digitSansSerifSuffix d] : if ((d >= 1 && d <= 5) || d == 7) '/sansSerif' ''
do "Single-digit circled"
local compositions : list
list 0xA9 {'C'} WideWidth2
list 0x1F12F {'revC'} WideWidth2
list 0x2117 {'P'} WideWidth2
# list 0x267E {'infty'} WideWidth1
list 0x1F10E {'ccCcwArrow'} WideWidth2
list 0x1F16F {'ccHumanFigure'} WideWidth2
list 0x1F1AD {'M'} WideWidth2
list 0x24EA {'zero.lnum'} WideWidth1
list 0x1F10B {'zero.lnum'} WideWidth1 # We don't have serifs for digit 0, so make an alias here
list 0x1F10D {'zero.lnum/forceSlashed'} WideWidth2
foreach [j : range 1 till 9] : compositions.push : list (0x2460 + j - 1) [digitGlyphNames j] WideWidth1
foreach [j : range 1 till 9] : compositions.push : list (0x2780 + j - 1) [digitGlyphNames j digitSansSerifSuffix] WideWidth1
foreach [j : range 0 26] : compositions.push {(0x24B6 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
foreach [j : range 0 26] : compositions.push {(0x24D0 + j) {[glyphStore.queryNameByUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)}
createCircledGlyphs 1 compositions
do "Single-digit backslash-circled"
createBackslashCircledGlyphs 1 : list
list 0x1F10F {'dollar'} WideWidth2
list 0x1F16E {'C'} WideWidth2
do "Single-digit italic circled"
createItalicCircledGlyphs 1 : list
list 0x1F12B {'C'} WideWidth1
list 0x1F12C {'R'} WideWidth1
do "Double-digit circled"
local compositions : list
list null {'sp1'} WideWidth1
list 0x2789 {'one/sansSerif.lnum' 'zero.lnum'} WideWidth1
list 0x1F16D {'C' 'C'} WideWidth2
list 0x1F12D {'C' 'D'} WideWidth1
list 0x1F12E {'W' 'smcpZ'} WideWidth1
foreach [j : range 10 till 20] : compositions.push : list (0x2460 + j - 1) [digitGlyphNames j] WideWidth1
foreach [j : range 21 till 35] : compositions.push : list (0x3251 + j - 21) [digitGlyphNames j] WideWidth1
foreach [j : range 36 till 50] : compositions.push : list (0x32B1 + j - 36) [digitGlyphNames j] WideWidth1
createCircledGlyphs 2 compositions
do "Single-letter inset circled"
local compositions : list
foreach [j : range 0 26] : compositions.push {(0x1F150 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
createInsetCircledGlyphs 1 compositions
do "Single-digit inset circled"
local compositions : list
list 0x24FF {'zero.lnum'} WideWidth1
list 0x1F10C {'zero.lnum'} WideWidth1 # We don't have serifs for digit 0, so make an alias here
foreach [j : range 1 till 9] : compositions.push : list (0x2776 + j - 1) [digitGlyphNames j] WideWidth1
foreach [j : range 1 till 9] : compositions.push : list (0x278A + j - 1) [digitGlyphNames j digitSansSerifSuffix] WideWidth1
createDecomposableInsetCircledGlyphs 1 compositions
do "Double-digit inset circled"
local compositions : list
list 0x2793 { "one/sansSerif.lnum" "zero.lnum" } WideWidth1
foreach [j : range 10 till 10] : compositions.push : list (0x2776 + j - 1) [digitGlyphNames j] WideWidth1
foreach [j : range 11 till 20] : compositions.push : list (0x24EB + j - 11) [digitGlyphNames j] WideWidth1
createDecomposableInsetCircledGlyphs 2 compositions
do "Single-digit boxed"
local compositions {}
foreach [j : range 0 26] : compositions.push {(0x1F130 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
compositions.push : list 0x1F1A5 {'d'} WideWidth1
createBoxedGlyphs 1 compositions
do "Double-digit boxed"
createBoxedGlyphs 2 : list
list 0x1F14A {'H' 'V'} WideWidth1
list 0x1F14B {'M' 'V'} WideWidth1
list 0x1F14C {'S' 'D'} WideWidth1
list 0x1F14D {'S' 'S'} WideWidth1
list 0x1F14F {'W' 'C'} WideWidth1
list 0x1F191 {'C' 'L'} WideWidth1
list 0x1F194 {'I' 'D'} WideWidth1
list 0x1F196 {'N' 'G'} WideWidth1
list 0x1F197 {'O' 'K'} WideWidth1
list 0x1F19A {'V' 'S'} WideWidth1
list 0x1F19B {'three.lnum' 'D'} WideWidth1
list 0x1F19D {'two.lnum' 'K'} WideWidth1
list 0x1F19E {'four.lnum' 'K'} WideWidth1
list 0x1F19F {'eight.lnum' 'K'} WideWidth1
list 0x1F1A6 {'H' 'C'} WideWidth1
do "Triple-digit boxed"
createBoxedGlyphs 3 : list
list 0x1F14E {'P' 'P' 'V'} WideWidth1
list 0x1F195 {'N' 'E' 'W'} WideWidth1
list 0x1F198 {'S' 'O' 'S'} WideWidth1
list 0x1F199 {'U' 'P' 'exclam'} WideWidth1
list 0x1F1A0 {'five.lnum' 'period' 'one.lnum'} WideWidth1
list 0x1F1A1 {'seven.lnum' 'period' 'one.lnum'} WideWidth1
list 0x1F1A3 {'six.lnum' 'zero.lnum' 'P'} WideWidth1
list 0x1F1A7 {'H' 'D' 'R'} WideWidth1
list 0x1F1AA {'S' 'H' 'V'} WideWidth1
list 0x1F1AB {'U' 'H' 'D'} WideWidth1
list 0x1F1AC {'V' 'O' 'D'} WideWidth1
do "Quadruple-digit boxed"
createBoxedGlyphs 4 : list
list 0x1F192 {'C' 'O' 'O' 'L'} WideWidth1
list 0x1F193 {'F' 'R' 'E' 'E'} WideWidth1
list 0x1F1A2 {'two.lnum' 'two.lnum' 'period' 'two.lnum'} WideWidth1
list 0x1F1A4 {'one.lnum' 'two.lnum' 'zero.lnum' 'P'} WideWidth1
do "Triple-digit two-row boxed"
createTwoRowBoxedGlyphs 3 : list
list 0x1F19C { 'two.lnum' 'N' 'D' 'S' 'C' 'R' } WideWidth1
list 0x1F1A8 { 'H' 'I' 'hyphen' 'R' 'E' 'S' } WideWidth1
do "Quadruple-digit two-row boxed"
createTwoRowBoxedGlyphs 4 : list
list 0x1F1A9 { 'L' 'O' 'S' 'S' 'L' 'E' 'S' 'S' } WideWidth1
do "Playing cards"
# Here we always construct the two-digit cards to ensure that all digit and suit glyphs
# are aligned across all cards.
local compositions : list
list 0x1F0A1 { 'A' 'sp1' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0AB { 'J/noDescend' 'sp1' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0AC { 'C' 'sp1' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0AD { 'Q' 'sp1' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0AE { 'K' 'sp1' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0B1 { 'A' 'sp1' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0BB { 'J/noDescend' 'sp1' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0BC { 'C' 'sp1' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0BD { 'Q' 'sp1' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0BE { 'K' 'sp1' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0C1 { 'A' 'sp1' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0CB { 'J/noDescend' 'sp1' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0CC { 'C' 'sp1' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0CD { 'Q' 'sp1' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0CE { 'K' 'sp1' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0D1 { 'A' 'sp1' 'clubSuit' 'zwsp' } WideWidth4
list 0x1F0DB { 'J/noDescend' 'sp1' 'clubSuit' 'zwsp' } WideWidth4
list 0x1F0DC { 'C' 'sp1' 'clubSuit' 'zwsp' } WideWidth4
list 0x1F0DD { 'Q' 'sp1' 'clubSuit' 'zwsp' } WideWidth4
list 0x1F0DE { 'K' 'sp1' 'clubSuit' 'zwsp' } WideWidth4
list 0x1F0AA { 'one.lnum' 'zero.lnum' 'spadeSuit' 'zwsp' } WideWidth4
list 0x1F0BA { 'one.lnum' 'zero.lnum' 'whiteHeartSuit' 'zwsp' } WideWidth4
list 0x1F0CA { 'one.lnum' 'zero.lnum' 'whiteDiamondSuit' 'zwsp' } WideWidth4
list 0x1F0DA { 'one.lnum' 'zero.lnum' 'clubSuit' 'zwsp' } WideWidth4
foreach [j : range 2 till 9] : begin
compositions.push : list (0x1F0A0 + j) [[digitGlyphNames j].concat {'sp1' 'spadeSuit' 'zwsp'}] WideWidth4
compositions.push : list (0x1F0B0 + j) [[digitGlyphNames j].concat {'sp1' 'whiteHeartSuit' 'zwsp'}] WideWidth4
compositions.push : list (0x1F0C0 + j) [[digitGlyphNames j].concat {'sp1' 'whiteDiamondSuit' 'zwsp'}] WideWidth4
compositions.push : list (0x1F0D0 + j) [[digitGlyphNames j].concat {'sp1' 'clubSuit' 'zwsp'}] WideWidth4
createPlayingCardGlyphs 2 compositions
do "Single-digit trump cards"
createTrumpCardGlyphs 1 : list
list 0x1F0BF {'vShadeStar.NWID'} WideWidth4
list 0x1F0CF {'blackStar.NWID'} WideWidth4
list 0x1F0DF {'whiteStar.NWID'} WideWidth4
list 0x1F0E0 {'zero.lnum/forceUnslashed'} WideWidth4
list 0x1F0E1 {'I'} WideWidth4
list 0x1F0E5 {'V'} WideWidth4
list 0x1F0EA {'X'} WideWidth4
do "Double-digit trump cards"
createTrumpCardGlyphs 2 : list
list 0x1F0E2 {'I' 'I'} WideWidth4
list 0x1F0E4 {'I' 'V'} WideWidth4
list 0x1F0E6 {'V' 'I'} WideWidth4
list 0x1F0E9 {'I' 'X'} WideWidth4
list 0x1F0EB {'X' 'I'} WideWidth4
list 0x1F0EF {'X' 'V'} WideWidth4
list 0x1F0F4 {'X' 'X'} WideWidth4
do "Triple-digit trump cards"
createTrumpCardGlyphs 3 : list
list 0x1F0E3 {'I' 'I' 'I'} WideWidth4
list 0x1F0E7 {'V' 'I' 'I'} WideWidth4
list 0x1F0EC {'X' 'I' 'I'} WideWidth4
list 0x1F0EE {'X' 'I' 'V'} WideWidth4
list 0x1F0F0 {'X' 'V' 'I'} WideWidth4
list 0x1F0F3 {'X' 'I' 'X'} WideWidth4
list 0x1F0F5 {'X' 'X' 'I'} WideWidth4
do "Quadruple-digit trump cards"
createTrumpCardGlyphs 4 : list
list 0x1F0E8 {'V' 'I' 'I' 'I'} WideWidth4
list 0x1F0ED {'X' 'I' 'I' 'I'} WideWidth4
list 0x1F0F1 {'X' 'V' 'I' 'I'} WideWidth4
do "Quintuple-digit trump cards"
createTrumpCardGlyphs 5 : list
list 0x1F0F2 {'X' 'V' 'I' 'I' 'I'} WideWidth4
do "Playing card back"
createPlayingCardBackGlyphs 1 : list
list 0x1F0A0 {'sp1'} WideWidth4
do "Single-digit dashed-boxed"
local compositions {}
foreach [j : range 0 26] : compositions.push {(0x1F1E6 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
createDashedBoxedGlyphs 1 compositions
do "Triple-digit dashed-boxed"
createDashedBoxedGlyphs 3 : list
list 0xFFFC {'O' 'B' 'J/noDescend'} WideWidth1
do "Single-digit inset boxed"
local compositions {}
foreach [j : range 0 26] : compositions.push {(0x1F170 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
createInsetBoxedGlyphs 1 compositions
do "Single-digit inset diamond"
createInsetDiamondGlyphs 1 : list
list 0xFFFD { "question" } WideWidth2
do "Double-digit inset boxed"
createDecomposableInsetBoxedGlyphs 2 : list
list 0x1F18B {'I' 'C'} WideWidth1
list 0x1F18C {'P' 'A'} WideWidth1
list 0x1F18D {'S' 'A'} WideWidth1
list 0x1F18E {'A' 'B'} WideWidth1
list 0x1F18F {'W' 'C'} WideWidth1
do "Single-digit negative square"
createCrossInsetBoxedGlyphs 1 : list
list 0x1F18A { "P" } WideWidth1
do "Single-digit inset mosaic"
local compositions {}
compositions.push { 0x1FBB1 { [[glyphStore.queryNameByUnicode (0x2714)].replace [regex '.WWID$'] ".NWID"] } WideWidth4 }
compositions.push { 0x1FBB4 { [[glyphStore.queryNameByUnicode (0x21B2)].replace [regex '.WWID$'] ".NWID"] } WideWidth4 }
compositions.push { 0x1FBC4 { "question" } WideWidth4 }
createInsetMosaicGlyphs 1 compositions
do "Single-digit double circled"
local compositions {}
foreach [j : range 1 till 9] : compositions.push : list (0x24F5 + j - 1) [digitGlyphNames j] WideWidth1
createDoubleCircledGlyphs 1 compositions
do "Double-digit double circled"
local compositions {}
foreach [j : range 10 till 10] : compositions.push : list (0x24F5 + j - 1) [digitGlyphNames j] WideWidth1
createDoubleCircledGlyphs 2 compositions
do "Single-digit braced"
local compositions {}
foreach [j : range 1 till 9] : compositions.push : list (0x2474 + j - 1) [digitGlyphNames j] WideWidth1
foreach [j : range 0 26] : compositions.push {(0x249C + j) {[glyphStore.queryNameByUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)}
foreach [j : range 0 26] : compositions.push {(0x1F110 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
createBracedGlyphs 1 compositions
do "Double-digit braced"
local compositions {}
foreach [j : range 10 till 20] : compositions.push : list (0x2474 + j - 1) [digitGlyphNames j] WideWidth1
createBracedGlyphs 2 compositions
do "Single-digit hex braced"
createHexBracedGlyphs 1 : list
list 0x1F12A {'S'} WideWidth1
do "Single-digit dotted"
local compositions : list
list 0x1F100 {'zero.lnum' 'period'} WideWidth1
foreach [j : range 1 till 9] : compositions.push : list (0x2488 + j - 1) [[digitGlyphNames j].concat {'period'}] WideWidth1
createDottedGlyphs 1 compositions
do "Single-digit comma"
local compositions {}
foreach [j : range 0 till 9] : compositions.push : list (0x1F101 + j) [[digitGlyphNames j].concat {'comma'}] WideWidth1
createDottedGlyphs 1 compositions
do "Double-digit dotted"
local compositions : list
foreach [j : range 10 till 20] : compositions.push : list (0x2488 + j - 1) [[digitGlyphNames j].concat {'period'}] WideWidth1
createDottedGlyphs 2 compositions
glyph-block Autobuild-Fractions : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Miniature Thner
glyph-block-import Autobuild-Enclosure-Shared : CollectJobs EnsureComponentGlyphT CreateDerivedFontFromJobs applyRelations
define [createFracImpl prefix demands layout] : begin
local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix '' demands
define miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
crowd -- layout.crowd
scale -- (layout.scaleFactor + 0.05)
mono -- true
mono2 -- true
define [FracBase nRows numWidth] : begin
local gnFracBase ".frac-base{\(prefix)}{\(nRows)}{\(numWidth)}"
if [not : query-glyph gnFracBase] : create-glyph gnFracBase : layout.baseShape nRows numWidth
return gnFracBase
define [FracShift iRow nRows numWidth denWidth] : begin
local gnFracShift ".frac-shift{\(prefix)}{\(iRow)}{\(nRows)}{\(numWidth)}{\(denWidth)}"
if [not : query-glyph gnFracShift] : create-glyph gnFracShift : layout.shiftShape iRow nRows numWidth denWidth
return gnFracShift
define [FracPartImpl subGlyphName] : begin
local gnn ".frac-inner{\(prefix)}{\(subGlyphName)}"
if [not : query-glyph gnn] : create-glyph gnn : glyph-proc
define subGlyph : miniatureFont.queryByNameEnsured subGlyphName
set-width 0
set-mark-anchor 'fracBuildUp' 0 0 (subGlyph.advanceWidth * layout.scaleFactor) 0
include subGlyph
include : Ungizmo
include : Translate 0 0
include : Scale layout.scaleFactor
include : Regizmo
return gnn
define [createFractionImpl job jobDecomposable] : begin
local {gnf unicode gnParts} job
if [not : query-glyph gnf] : create-glyph gnf unicode : glyph-proc
local rows : layout.breakRows gnParts
local decomposition {}
local lastRowWidth 0
foreach j [range 0 rows.length] : begin
local gnList {}
local thisRowWidth 0
foreach gnSubRowElement [items-of rows.(j)] : begin
set thisRowWidth : thisRowWidth + [miniatureFont.queryByNameEnsured gnSubRowElement].advanceWidth
gnList.push : EnsureComponentGlyphT gnSubRowElement FracPartImpl
if (j == 0)
: then : begin
local gnBase : FracBase rows.length thisRowWidth
include [refer-glyph gnBase] AS_BASE ALSO_METRICS
decomposition.push gnBase
: else : begin
local gnShift : FracShift j rows.length lastRowWidth thisRowWidth
include : refer-glyph gnShift
decomposition.push gnShift
foreach gnRowElement [items-of gnList] : begin
include : refer-glyph gnRowElement
decomposition.push gnRowElement
set lastRowWidth thisRowWidth
if jobDecomposable : CvDecompose.set currentGlyph decomposition
foreach job [items-of jobs.nonDecomposable] : createFractionImpl job false
foreach job [items-of jobs.decomposableJobs] : createFractionImpl job true
applyRelations jobs.relApplications
define [FractionLayout letterHeight fine scaleFactor closing] : begin
define dist : XH * (1 - scaleFactor - closing)
define partOffsetY : letterHeight * scaleFactor + dist
return : object
crowd : begin 3.5
scaleFactor : begin scaleFactor
breakRows : function [a] { {a.0} [a.slice 1] }
baseShape : function [nRows firstRowWidth] : glyph-proc
set-width Width
if fine : include : HBar.m SB RightSB SymbolMid (fine * 0.75)
set-base-anchor 'fracBuildUp' (Middle - firstRowWidth * scaleFactor / 2) (SymbolMid + dist / 2)
shiftShape : function [iRow nRows numWidth denWidth] : glyph-proc
local offset : -(numWidth / 2 + denWidth / 2) * scaleFactor
set-width 0
set-mark-anchor 'fracBuildUp' 0 0 offset (-partOffsetY)
define [ControlPictureLayout crowd scaleFactor pGap] : begin
define gap : XH * pGap
return : object
crowd : begin crowd
scaleFactor : begin scaleFactor
breakRows : function [a] : a.map : function [x] {x}
baseShape : function [nRows firstRowWidth] : glyph-proc
set-width Width
set-base-anchor 'fracBuildUp' SB (SymbolMid + (CAP * scaleFactor * nRows + gap * (nRows - 1)) / 2 - CAP * scaleFactor)
shiftShape : function [iRow nRows numWidth denWidth] : glyph-proc
define [startPos w p] : SB + (RightSB - SB - w * scaleFactor) * p / (nRows - 1)
local offset : [startPos denWidth iRow] - [startPos numWidth (iRow - 1)] - numWidth * scaleFactor
set-width 0
set-mark-anchor 'fracBuildUp' 0 0 offset (-(CAP * scaleFactor + gap))
define [createFractions records] : createFracImpl 'frac' records : FractionLayout CAP [AdviceStroke 3] 0.55 0.05
define [createFractionsSmall records] : createFracImpl 'fracSmall' records : FractionLayout XH [AdviceStroke 3] 0.55 0.05
define [createControlPictures2 records] : createFracImpl 'ctrlPict2' records : ControlPictureLayout 3.75 0.55 0.2
define [createControlPictures3 records] : createFracImpl 'ctrlPict3' records : ControlPictureLayout 5 0.375 0.1
createFractions : list
list 0x00BC { 'one.lnum' 'four.lnum' }
list 0x00BD { 'one.lnum' 'two.lnum' }
list 0x00BE { 'three.lnum' 'four.lnum' }
list 0x2150 { 'one.lnum' 'seven.lnum' }
list 0x2151 { 'one.lnum' 'nine.lnum' }
list 0x2152 { 'one.lnum' 'one.lnum' 'zero.lnum' }
list 0x2153 { 'one.lnum' 'three.lnum' }
list 0x2154 { 'two.lnum' 'three.lnum' }
list 0x2155 { 'one.lnum' 'five.lnum' }
list 0x2156 { 'two.lnum' 'five.lnum' }
list 0x2157 { 'three.lnum' 'five.lnum' }
list 0x2158 { 'four.lnum' 'five.lnum' }
list 0x2159 { 'one.lnum' 'six.lnum' }
list 0x215A { 'five.lnum' 'six.lnum' }
list 0x215B { 'one.lnum' 'eight.lnum' }
list 0x215C { 'three.lnum' 'eight.lnum' }
list 0x215D { 'five.lnum' 'eight.lnum' }
list 0x215E { 'seven.lnum' 'eight.lnum' }
list 0x215F { 'one.lnum' 'sp1' }
list 0x2189 { 'zero.lnum' 'three.lnum' }
list 0x214D { 'A' 'S' }
createFractionsSmall : list
list 0x2100 { 'a' 'c' }
list 0x2101 { 'a' 's' }
list 0x2105 { 'c' 'o' }
list 0x2106 { 'c' 'u' }
createControlPictures2 : list
list 0xE0A1 {"L" "N"}
list 0xE0A3 {"C" "N"}
list 0x2408 {"B" "S"}
list 0x2409 {"H" "T"}
list 0x240A {"L" "F"}
list 0x240B {"V" "T"}
list 0x240C {"F" "F"}
list 0x240D {"C" "R"}
list 0x240E {"S" "O"}
list 0x240F {"S" "I"}
list 0x2419 {"E" "M"}
list 0x241C {"F" "S"}
list 0x241D {"G" "S"}
list 0x241E {"R" "S"}
list 0x241F {"U" "S"}
list 0x2420 {"S" "P"}
list 0x2424 {"N" "L"}
createControlPictures3 : list
list 0x2400 {"N" "U" "L"}
list 0x2401 {"S" "O" "H"}
list 0x2402 {"S" "T" "X"}
list 0x2403 {"E" "T" "X"}
list 0x2404 {"E" "O" "T"}
list 0x2405 {"E" "N" "Q"}
list 0x2406 {"A" "C" "K"}
list 0x2407 {"B" "E" "L"}
list 0x2410 {"D" "L" "E"}
list 0x2411 {"D" "C" "one.lnum"}
list 0x2412 {"D" "C" "two.lnum"}
list 0x2413 {"D" "C" "three.lnum"}
list 0x2414 {"D" "C" "four.lnum"}
list 0x2415 {"N" "A" "K"}
list 0x2416 {"S" "Y" "N"}
list 0x2417 {"E" "T" "B"}
list 0x2418 {"C" "A" "N"}
list 0x241A {"S" "U" "B"}
list 0x241B {"E" "S" "C"}
list 0x2421 {"D" "E" "L"}
glyph-block AutoBuild-Accented-Equal : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Miniature
glyph-block-import Mark-Above : aboveMarkBot
glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations
define [createAccentedOp gnBase crowd scale shiftX shiftY demands] : begin
define prefix : 'accent-op{' + gnBase + '}{' + [{crowd scale shiftX shiftY}.join '-'] + '}'
local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED MONOSPACE-ONLY prefix '' demands
local dFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
crowd -- crowd
scale -- scale
mono -- true
mono2 -- true
define [ComponentImpl offset totalWidth] : lambda [gidPart] : begin
define gni : '.accented-op-part.' + gidPart + '@' + [{ prefix offset totalWidth }.join '/']
if [query-glyph gni] : return gni
create-glyph gni : glyph-proc
set-width 0
set-mark-anchor 'compositeInner' 0 0
include : dFont.queryByNameEnsured gidPart
include : Ungizmo
include : Translate (-totalWidth / 2 + offset) 0
include : Scale scale
include : Translate (Middle + shiftX - Width) shiftY
include : Regizmo
return gni
define [createAccentedOpImpl job decomposable] : begin
local { gn unicode parts } job
local totalWidth 0
local offsets { }
foreach [j : range 0 parts.length] : begin
local gidPart parts.(j)
set offsets.(j) totalWidth
set totalWidth : totalWidth + [dFont.queryByNameEnsured gidPart].advanceWidth
if [not : query-glyph gn] : create-glyph gn unicode : glyph-proc
set-width Width
local ps { gnBase }
foreach [j : range 0 parts.length] : begin
local gidPart parts.(j)
local p : EnsureComponentGlyphT gidPart : ComponentImpl offsets.(j) totalWidth
include : refer-glyph p
ps.push p
include : Translate Width 0
include : refer-glyph gnBase
if decomposable : CvDecompose.set currentGlyph ps
foreach job [items-of jobs.nonDecomposable] : createAccentedOpImpl job false
foreach job [items-of jobs.decomposableJobs] : createAccentedOpImpl job true
applyRelations jobs.relApplications
createAccentedOp 'equal' 7 0.4 0 aboveMarkBot : list
list 0x225e {"m"}
list 0x225F {"question/hookPart" "question/dotPart"}
createAccentedOp 'equal' 5 0.8 0 aboveMarkBot : list
list 0x2258 {"symbolMidTie"}
createAccentedOp 'equal' 7 0.5 0 (aboveMarkBot - (SymbolMid - XH / 2)) : list
list 0x2259 {"triangularWedge.NWID"}
list 0x225a {"triangularVee.NWID"}
list 0x225b {"blackStar.NWID"}
list 0x225c {"whiteTriangleUp.NWID"}
list 0x2a6e {"opAsterisk"}
createAccentedOp 'sqrt' 5 0.5 (-Width / 4) [mix OperBot OperTop 0.6] : list
list 0x221b {"three.lnum"}
list 0x221c {"four.lnum"}
createAccentedOp 'equal' 8 0.3 0 aboveMarkBot : list
list 0x225d {"d" "e" "f"}
createAccentedOp 'markDemoBaseSpace' 6 0.40 0 (aboveMarkBot - (CAP * 0.40 - XH * 0.40)) : list
list 0xAE {"R" "combRingCapDiv1"}
createAccentedOp 'markDemoBaseSpace' 6 0.45 0 (aboveMarkBot - (CAP * 0.45 - XH * 0.45)) : list
list 0x2122 {"T" "M"}
list 0x2120 {"S" "M"}
list 0x1F16A {"M" "C"}
list 0x1F16B {"M" "D"}
list 0x1F16C {"M" "R"}
glyph-block Autobuild-Ligatures : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Thinner
glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations
define [createLigatures prefix _shrink1 _shrinkN wadj1 wadjN kKern demands] : for-width-kinds WideWidth2
local plainLigature : FMosaicWide && para.isQuasiProportional
local ww : if FMosaicWide MosaicWidth (MosaicWidth * para.advanceScaleMM)
local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix MosaicNameSuffix demands
local shrink1 : if plainLigature 1 [clamp 0 1 (_shrink1 * [mix Width ww 0.5] / Width)]
local shrinkN : if plainLigature 1 [clamp 0 1 (_shrinkN * [mix Width ww 0.5] / Width)]
local df1 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink1
local dfN : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrinkN
define [LigaturePlaceholderImpl aw markPlacement] : begin
define gni : '.ligature-placeholder@' + [{aw markPlacement}.join '/']
if [query-glyph gni] : return gni
create-glyph gni : glyph-proc
set-width aw
set-base-anchor 'enclosureInner' markPlacement 0
return gni
define [LigaturePartImpl df offset1 compress markDist] : lambda [gidPart] : begin
define gni : '.ligature-part.' + gidPart + '@' + [{ prefix compress offset1 markDist }.join '/']
if [query-glyph gni] : return gni
create-glyph gni : glyph-proc
set-width 0
include : df.queryByNameEnsured gidPart
include : Ungizmo
include : Translate offset1 0
include : Scale compress 1
include : Regizmo
set-mark-anchor 'enclosureInner' 0 0 markDist 0
return gni
define [LigatureImpl job decomposable] : begin
local { gn unicode components desiredWidth } job
local ps {}
local dfgs {}
foreach { i component } [components.entries] : begin
set dfgs.(i) : [if i dfN df1].queryByNameEnsured component
if [query-glyph gn] : return nothing
if plainLigature : begin
# Glyph built as a pure ligature. This case is always decomposable
create-glyph gn [MangleUnicode unicode desiredWidth] : glyph-proc
local decomposition { }
local aw 0
foreach { i component } [components.entries] : do
local componentG : query-glyph component
include : with-transform [Translate aw 0] : refer-glyph component
set aw : aw + componentG.advanceWidth
decomposition.push component
set-width aw
CvDecompose.set currentGlyph decomposition
IsCompositeOrLigature.set currentGlyph
: else : begin
# Glyph is not a pure ligature, do it in the hard way
local sumChildrenWidth 0
foreach {i dfg} [dfgs.entries] : begin
set sumChildrenWidth : sumChildrenWidth + dfg.advanceWidth * [if i wadjN wadj1]
local glyphWidth : if (sumChildrenWidth < ww) MosaicWidth ww
local compressRefWidth : (glyphWidth - SB * 1.25) / (glyphWidth - SB * 2) * glyphWidth
local kern : kKern * glyphWidth
local estKernedUncompressedWidth : sumChildrenWidth - kern * (dfgs.length - 1)
if (dfgs.length > 1) : foreach [cycle : range 0 4] : begin
if (kKern == 0) : begin
set kern : clamp 0 (SB * 7 / 8) ((estKernedUncompressedWidth - compressRefWidth) / (dfgs.length - 1))
set estKernedUncompressedWidth : sumChildrenWidth - kern * (dfgs.length - 1)
local compress : clamp 0 1 (compressRefWidth / estKernedUncompressedWidth)
create-glyph gn [MangleUnicode unicode desiredWidth] : glyph-proc
local decomposition { }
local baseOffset : glyphWidth / 2 - estKernedUncompressedWidth * compress / 2
foreach { i component } [components.entries] : do
local componentAdvance : compress * (dfgs.(i).advanceWidth * [if i wadjN wadj1] - kern)
local componentRefOffset : dfgs.(i).advanceWidth * ([if i wadjN wadj1] - 1) / 2
if (i === 0) : begin
local placeholder : LigaturePlaceholderImpl glyphWidth baseOffset
decomposition.push placeholder
include [refer-glyph placeholder] AS_BASE ALSO_METRICS
local part : EnsureComponentGlyphT component
LigaturePartImpl dfN componentRefOffset compress componentAdvance
decomposition.push part
include [refer-glyph part]
if decomposable : CvDecompose.set currentGlyph decomposition
IsCompositeOrLigature.set currentGlyph
foreach job [items-of jobs.nonDecomposable] : LigatureImpl job false
foreach job [items-of jobs.decomposableJobs] : LigatureImpl job true
applyRelations jobs.relApplications
# Dutch IJ
define ijShrink : clamp 0.6 0.75 : StrokeWidthBlend 0.6 0.75
createLigatures 'compatLigature1' ijShrink ijShrink 1 1 [if (para.advanceScaleI < 1) 0 0.2] : list
list 0x132 { 'I' 'J' }
list 0x133 { 'i' 'j' }
list 0xEF11 { 'IAcute' 'JAcute' }
list 0xEF12 { 'iAcute' 'jAcute' }
# Link Gr for acute variants
NLDAcuteVariant.set [glyphStore.queryByUnicodeEnsured 0x132] [glyphStore.queryNameByUnicodeEnsured 0xEF11]
NLDAcuteVariant.set [glyphStore.queryByUnicodeEnsured 0x133] [glyphStore.queryNameByUnicodeEnsured 0xEF12]
define stdShrink : clamp 0.75 0.9 : StrokeWidthBlend 0.75 0.9
createLigatures 'compatLigature2' stdShrink stdShrink 1 1 0 : list
list 0x1C4 { 'D' 'ZCaron' }
list 0x1C5 { 'D' 'zCaron' }
list 0x1C6 { 'd' 'zCaron' }
list 0x1C7 { 'L' 'J' }
list 0x1C8 { 'L' 'j' }
list 0x1C9 { 'l' 'j' }
list 0x1CA { 'N' 'J' }
list 0x1CB { 'N' 'j' }
list 0x1CC { 'n' 'j' }
list 0x1F1 { 'D' 'Z' }
list 0x1F2 { 'D' 'z' }
list 0x1F3 { 'd' 'z' }
list 0x478 { 'cyrl/O' 'cyrl/u' }
list 0x479 { 'cyrl/uk/o' 'cyrl/u' }
list 0x20A7 { 'P' 't' }
list 0x20A8 { 'R' 's' }
list 0x20AF { 'D' 'grek/rho' }
list 0x2116 { 'N' 'numeroRightHalf' }
list 0x1F190 { 'D' 'J' } WideWidth1
# Link Gr for caron variants
HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F1] [glyphStore.queryNameByUnicodeEnsured 0x1C4]
HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F2] [glyphStore.queryNameByUnicodeEnsured 0x1C5]
HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F3] [glyphStore.queryNameByUnicodeEnsured 0x1C6]
createLigatures 'romanNumerals1' 1 1 1 1 0 : list
list 0x2160 { 'I' }
list 0x2164 { 'V' }
list 0x2169 { 'X' }
list 0x216C { 'L' }
list 0x216D { 'C' }
list 0x216E { 'D' }
list 0x216F { 'M' }
list 0x2170 { 'i' }
list 0x2174 { 'v' }
list 0x2179 { 'x' }
list 0x217C { 'l' }
list 0x217D { 'c' }
list 0x217E { 'd' }
list 0x217F { 'm' }
createLigatures 'romanNumerals2' stdShrink stdShrink 1 1 0 : list
list 0x2161 { 'I' 'I' }
list 0x2163 { 'I' 'V' }
list 0x2165 { 'V' 'I' }
list 0x2168 { 'I' 'X' }
list 0x216A { 'X' 'I' }
list 0x2171 { 'i' 'i' }
list 0x2173 { 'i' 'v' }
list 0x2175 { 'v' 'i' }
list 0x2178 { 'i' 'x' }
list 0x217A { 'x' 'i' }
define romanShrink : clamp 0.625 0.875 : StrokeWidthBlend 0.625 0.875
createLigatures 'romanNumerals3' romanShrink romanShrink 1 1 0 : list
list 0x2162 { 'I' 'I' 'I' }
list 0x2166 { 'V' 'I' 'I' }
list 0x216B { 'X' 'I' 'I' }
list 0x2172 { 'i' 'i' 'i' }
list 0x2176 { 'v' 'i' 'i' }
list 0x217B { 'x' 'i' 'i' }
define romanShrink4 : clamp 0.5 0.875 : StrokeWidthBlend 0.5 0.875
createLigatures 'romanNumerals4' romanShrink4 romanShrink4 1 1 0 : list
list 0x2167 { 'V' 'I' 'I' 'I' }
list 0x2177 { 'v' 'i' 'i' 'i' }
createLigatures 'temperature' 0.7 0.8 0.75 0.9 0 : list
list 0x2103 { 'degree' 'C' }
list 0x2109 { 'degree' 'F' }
glyph-block Autobuild-Pnonetic-Ligatures : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Thinner
glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations
glyph-block-import Autobuild-Transformed-Shared : ToSuperscript ToSubscript
define [createPhoneticLigatures tfm prefix adws mockNParts _shrink kKern demands] : begin
local ww0 : Width * adws
local wwM : ww0 / [fallback tfm.crowdAdjScale 1]
local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix "" demands
local shrink : clamp 0 1 _shrink
local kern 0
foreach [cycle : range 0 8] : begin
set kern : kKern * (2 * SB * shrink + (HalfStroke * [HSwToV shrink] - OX * 2))
local tmpShrink : (wwM + kern * (mockNParts - 1)) / (mockNParts * Width)
set shrink : Math.max _shrink : clamp 0 1 tmpShrink
local thinFont : CreateDerivedFontFromJobs jobs {} : function [gs]
Thinner gs shrink true tfm.crowd tfm.crowdAdjScale
define [LigaturePlaceholderImpl aw markPlacement mak] : begin
define gni : '.phonetic-ligature-placeholder@' + [{ prefix aw markPlacement mak }.join '/']
if [query-glyph gni] : return gni
create-glyph gni : glyph-proc
set-width aw
if mak : include : [DivFrame adws].markSet.(mak)
set-base-anchor 'enclosureInner' markPlacement 0
set-base-anchor 'slash' (aw / 2) (Ascender / 2)
include : tfm adws
return gni
define [LigaturePartImpl thinFont compress markDist maskPos] : lambda [gidPart] : begin
define gni : '.phonetic-ligature-part.' + gidPart + '@' + [{ prefix compress markDist maskPos }.join '/']
if [query-glyph gni] : return gni
create-glyph gni : glyph-proc
set-width 0
include : difference
thinFont.queryByNameEnsured gidPart
MaskRight maskPos
include : Ungizmo
include : Scale compress 1
include : Regizmo
set-mark-anchor 'enclosureInner' 0 0 markDist 0
include : tfm adws
return gni
define [LigatureImpl job decomposable] : if [not : query-glyph gn] : begin
local { gn unicode components mak } job
local sumChildrenWidth 0
local effectiveGlyphCount 0
local originals {}
local dfgs {}
foreach { i component } [components.entries] : begin
set originals.(i) : query-glyph component
set dfgs.(i) : thinFont.queryByNameEnsured component
if (originals.(i).advanceWidth > 0) : inc effectiveGlyphCount
set sumChildrenWidth : sumChildrenWidth + dfgs.(i).advanceWidth
local refW : sumChildrenWidth - kern * (effectiveGlyphCount - 1)
local compRefWw wwM
local compress : clamp 0 1 (compRefWw / refW)
if [not : query-glyph gn] : create-glyph gn unicode : glyph-proc
local decomposition { }
local baseOffset : ww0 / 2 - refW * compress / 2
foreach { i component } [components.entries] : do
local currentIsMark : 0 == originals.(i).advanceWidth
local componentAdvance : if currentIsMark 0 : compress * (dfgs.(i).advanceWidth - kern)
local maskPos : dfgs.(i).advanceWidth - kern + [if ((i + 1) < effectiveGlyphCount) (dfgs.(i + 1).advanceWidth / 2) ww0]
if (i === 0) : begin
local placeholder : LigaturePlaceholderImpl ww0 baseOffset mak
decomposition.push placeholder
include [refer-glyph placeholder] AS_BASE ALSO_METRICS
if currentIsMark : then : begin
include [refer-glyph component]
: else : begin
local part : EnsureComponentGlyphT component
LigaturePartImpl thinFont compress componentAdvance maskPos
decomposition.push part
include [refer-glyph part]
if decomposable : CvDecompose.set currentGlyph decomposition
foreach job [items-of jobs.nonDecomposable] : LigatureImpl job false
foreach job [items-of jobs.decomposableJobs] : LigatureImpl job true
applyRelations jobs.relApplications
define [ToLetter] : glyph-proc
define stdShrink : clamp 0.625 0.9 : StrokeWidthBlend 0.625 0.9
createPhoneticLigatures ToLetter 'phonetic1' [Math.max 1 : para.advanceScaleF * para.advanceScaleMM] 2 stdShrink 1 : list
list 0xFB00 { 'f' 'f' } null
list 0xFB01 { 'f/compLigLeft1' 'dotlessi/compLigRight' } null
list 0xFB02 { 'f/compLigLeft3' 'l/compLigRight' } null
createPhoneticLigatures ToLetter 'phonetic2' para.advanceScaleMM 2 stdShrink 1 : list
list 0x02A3 { 'd/phoneticLeft' 'z/phoneticRight' } 'b'
list 0x02A4 { 'd/phoneticLeft' 'ezh/phoneticRight' } 'bp'
list 0x02A5 { 'd/phoneticLeft' 'zCurlyTail/phoneticRight' } 'b'
list 0x02A6 { 't/phoneticLeft2' 's/phoneticRight' } 'b'
list 0x02A7 { 't/teshLeft' 'esh' } 'bp'
list 0x02A8 { 't/phoneticLeft1' 'cCurlyTail' } 'b'
list 0x02A9 { 'f/phoneticLeft' 'eng/phoneticRight' } 'bp'
list 0x02AA { 'l/phoneticLeft' 's/phoneticRight' } 'b'
list 0x02AB { 'l/phoneticLeft' 'z' } 'b'
list 0xAB66 { 'd/phoneticLeft' 'zRTail/phoneticRight' } 'bp'
list 0xAB67 { 't/phoneticLeft1' 'sRTail' } 'bp'
list 0x1DF12 { 'd/phoneticLeft' 'ezhPalatalHook/phoneticRight' } 'bp'
list 0x1DF17 { 't/teshLeft' 'eshPalatalHook' } 'bp'
list 0x1DF19 { 'd/phoneticLeft' 'ezhRetroflexHook/phoneticRight' } 'bp'
list 0x1DF1C { 't/teshLeft' 'eshRetroflexHook/teshRight' } 'bp'
list 0xFB05 { 'longs/compLigLeft' 't/compLigRight' } null
list 0xFB06 { 's/compLigLeft' 't/compLigRight' } null
createPhoneticLigatures ToLetter 'phonetic3' [Math.max para.advanceScaleMM : para.advanceScaleF * [mix 1 para.advanceScaleMM 2]] 3 stdShrink 1 : list
list 0xFB03 { 'f/compLigLeft2' 'f/compLigLeft1' 'dotlessi/compLigRight' } null
list 0xFB04 { 'f/compLigLeft4' 'f/compLigLeft3' 'l/compLigRight' } null
createPhoneticLigatures ToLetter 'phoneticSmcp' (para.advanceScaleM * para.advanceScaleMM) 3 1 0.5 : list
list 0x2121 { 'smcpT' 'smcpE' 'smcpL' } 'e'
list 0x213B { 'smcpF' 'smcpA' 'smcpX' } 'e'
createPhoneticLigatures ToSuperscript 'phoneticSuperscript' 1 2 stdShrink 1 : list
list 0x10787 { 'd/phoneticLeft' 'z/phoneticRight' } 'b'
list 0x1078A { 'd/phoneticLeft' 'ezh/phoneticRight' } 'bp'
list 0x10789 { 'd/phoneticLeft' 'zCurlyTail/phoneticRight' } 'bp'
list 0x107AC { 't/phoneticLeft2' 's/phoneticRight' } 'b'
list 0x107AE { 't/teshLeft' 'esh' } 'bp'
list 0x107AB { 't/phoneticLeft1' 'cCurlyTail' } 'b'
list 0x10790 { 'f/phoneticLeft' 'eng/phoneticRight' } 'bp'
list 0x10799 { 'l/phoneticLeft' 's/phoneticRight' } 'b'
list 0x1079A { 'l/phoneticLeft' 'z' } 'b'
list 0x10788 { 'd/phoneticLeft' 'zRTail/phoneticRight' } 'bp'
list 0x107AD { 't/phoneticLeft1' 'sRTail' } 'p'
createPhoneticLigatures ToSubscript 'tenSubscript' 1 2 1 0.5 : list
list 0x23E8 { 'one.lnum' 'zero.lnum' } 'capital'
createPhoneticLigatures ToLetter 'thSlash' para.advanceScaleMM 2 stdShrink 1 : list
list 0x1D7A { 't/phoneticLeft1' 'h' 'wideSlash' } 'b'
glyph-block Autobuild-Double-Emotions : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Thinner
glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations
define [createDoubleEmotions prefix adws _shrink1 _shrink2 wadj1 wadj2 demands] : for-width-kinds WideWidth2
define CWidth : if FMosaicWide MosaicWidth (Width * adws)
define shrink1 : if FMosaicWide 1 _shrink1
define shrink2 : if FMosaicWide 1 _shrink2
define kern : SB * shrink1 + SB * shrink2 + HalfStroke * [mix shrink1 shrink2 0.5] - OX * 2
define jobs : CollectJobs NON-DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix MosaicNameSuffix demands
define df1 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink1 true
define df2 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink2 true
foreach [{gn unicode { c1 m1 c2 m2 } mak} : items-of jobs.nonDecomposable] : if [not : query-glyph gn] : begin
create-glyph gn [MangleUnicode unicode] : glyph-proc
set-width CWidth
if mak : include : [DivFrame (CWidth / Width)].markSet.(mak)
define dfg1 : df1.queryByNameEnsured c1
define dfm1 : df1.queryByNameEnsured m1
define dfg2 : df2.queryByNameEnsured c2
define dfm2 : df2.queryByNameEnsured m2
local sumChildrenWidth : dfg1.advanceWidth * wadj1 + dfg2.advanceWidth * wadj2
local refW : sumChildrenWidth - kern
include : union dfg2 [with-transform [Translate (dfg2.advanceWidth) 0] dfm2]
include : Translate (dfg1.advanceWidth * wadj1 - kern) 0
include : union dfg1 [with-transform [Translate (dfg1.advanceWidth) 0] dfm1]
include : Ungizmo
include : Translate ((-refW) / 2) 0
include : Scale [clamp 0 1 ((CWidth - SB * 1.25) / (CWidth - SB * 2) * CWidth / refW)] 1
include : Translate (CWidth / 2) 0
include : Regizmo
applyRelations jobs.relApplications
define stdShrink : clamp 0.625 0.9 : StrokeWidthBlend 0.625 0.9
createDoubleEmotions 'doubleemotion' para.advanceScaleM stdShrink stdShrink 1 1 : list
list 0x203c { 'exclam' 'zwsp' 'exclam' 'zwsp' }
list 0x2047 { 'question/hookPart' 'question/dotPart' 'question/hookPart' 'question/dotPart' }
list 0x2048 { 'question/hookPart' 'question/dotPart' 'exclam' 'zwsp' }
list 0x2049 { 'exclam' 'zwsp' 'question/hookPart' 'question/dotPart' }
glyph-block Autobuild-Grouped-Digits : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
define [createGroupedDigits shrink crowd numberGlyphIDs] : begin
create-glyph '.nd-shade' : glyph-proc
set-width 0
set-mark-anchor 'compositeInner' 0 0
include : intersection
HBar.b 0 Width (Descender * 0.75) [AdviceStroke 4]
glyph-proc
include : refer-glyph "denseShade.WWID"
include : Translate ((-Width) / 2) 0
include : Translate (-Width) 0
foreach [gid : items-of numberGlyphIDs] : foreach [nd : items-of {0 1 2 3 4 5 6}]
create-glyph (gid + ".nd" + nd) : glyph-proc
include : refer-glyph gid
if (nd >= 3 && nd <= 5) : begin
include : with-transform [Translate Width 0] : refer-glyph '.nd-shade'
CvDecompose.set currentGlyph { gid '.nd-shade' }
: else : begin
CvDecompose.set currentGlyph { gid }
createGroupedDigits 0.9 3.0 {
'zero.lnum' 'one.lnum' 'two.lnum' 'three.lnum' 'four.lnum'
'five.lnum' 'six.lnum' 'seven.lnum' 'eight.lnum' 'nine.lnum'
}