801 lines
32 KiB
Text
801 lines
32 KiB
Text
$$include '../meta/macros.ptl'
|
|
|
|
import '../support/transform' as : Transform && [object [transformPoint tp] [untransform utp] inverse]
|
|
import '../support/fairify' as fairify
|
|
|
|
import [mix linreg clamp fallback] from '../support/utils'
|
|
import [designParameters] from '../meta/aesthetics'
|
|
|
|
export : define [apply] : begin
|
|
glyph-module-entry
|
|
###### COMMON GLYPH CONSTRUCTIONS
|
|
define [queryFeatureSelector follow para name] : begin
|
|
local fs {.}
|
|
local introduced false
|
|
foreach [{k h} : pairs-of para.variants] : if (h.(follow) && h.__cvmap && h.__cvmap.(follow)) : begin
|
|
local tag h.__cvmap.(follow)
|
|
set fs.(tag) ([fallback name follow] + '.' + h.(follow))
|
|
set introduced true
|
|
return : if introduced fs null
|
|
|
|
define [select-variant] : params [name unicode [to-name name] transform [follow name]] : begin
|
|
if (pickHash && [not pickHash.(name)]) : return nothing
|
|
|
|
local variant : variantSelector.(follow) || para.defaultVariant.(follow)
|
|
if [not variant] : begin
|
|
throw : new Error "Variant for \(name) is not assigned."
|
|
|
|
if (transform && transform.(variant)) : set variant transform.(variant)
|
|
local chosenGlyph glyphs.((name + '.' + variant))
|
|
|
|
create-glyph [fallback to-name name] : glyph-construction
|
|
include chosenGlyph AS_BASE ALSO_METRICS
|
|
if unicode : assign-unicode unicode
|
|
set currentGlyph.featureSelector : queryFeatureSelector follow para name
|
|
set this.cmpPriority chosenGlyph.cmpPriority
|
|
|
|
define [italic-variant name unicode] : create-glyph name : glyph-construction
|
|
define base : if para.isItalic glyphs.(name + '.italic') glyphs.(name + '.upright')
|
|
include base AS_BASE
|
|
set-width base.advanceWidth
|
|
if unicode : assign-unicode unicode
|
|
|
|
define [alias newid unicode oldid] : begin
|
|
create-glyph newid : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(oldid) AS_BASE
|
|
set-width glyphs.(oldid).advanceWidth
|
|
set this.featureSelector glyphs.(oldid).featureSelector
|
|
set this.cmpPriority glyphs.(oldid).cmpPriority
|
|
|
|
define [composite _newid] : begin
|
|
local parts null
|
|
local newid null
|
|
if ([typeof _newid] == 'string') : begin
|
|
set parts : {}.slice.call arguments 1
|
|
set newid _newid
|
|
: else
|
|
set parts : {}.slice.call arguments 0
|
|
set newid ('composite-glyph' + [newtemp])
|
|
|
|
return : create-glyph newid : glyph-construction
|
|
local first true
|
|
foreach [part : items-of parts] : begin
|
|
include part first
|
|
if first : set-width part.advanceWidth
|
|
set first false
|
|
|
|
define [into-unicode code] : glyph-construction
|
|
if code : assign-unicode code
|
|
|
|
# Transformation variants
|
|
define [turned newid unicode id x y mark] : create-glyph [fallback newid : 'turn' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id) [if mark false AS_BASE]
|
|
set-width glyphs.(id).advanceWidth
|
|
if mark : include mark
|
|
include : FlipAround x y
|
|
|
|
# Dual derivatives
|
|
define [hcombine newid unicode id1 id2 spacing] : create-glyph [fallback newid : 'hcombine_' + id1 + '_' + id2] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id1) AS_BASE
|
|
set-width glyphs.(id1).advanceWidth
|
|
apply-transform : Translate (-spacing) 0
|
|
include glyphs.(id2)
|
|
apply-transform : Translate (spacing / 2) 0
|
|
define [dual newid unicode id spacing] : hcombine [fallback newid : 'double' + id] unicode id id spacing
|
|
|
|
define [vcombine newid unicode id1 id2 spacing] : create-glyph [fallback newid : 'vcombine_' + id1 + '_' + id2] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
set-width glyphs.(id1).advanceWidth
|
|
depends-on glyphs.(id1)
|
|
depends-on glyphs.(id2)
|
|
include : create-glyph : glyph-construction
|
|
include glyphs.(id2)
|
|
apply-transform : Upright
|
|
apply-transform : Translate 0 (-spacing)
|
|
include : create-glyph : glyph-construction
|
|
include glyphs.(id1)
|
|
apply-transform : Upright
|
|
apply-transform : Translate 0 (spacing / 2)
|
|
apply-transform : Italify
|
|
define [vdual newid unicode id spacing] : vcombine [fallback newid : 'double' + id] unicode id id spacing
|
|
|
|
# Full-width derivatives
|
|
define [fwl newid unicode id shift wk] : create-glyph [fallback newid : 'fwl' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width [fallback wk FULLWIDTH]
|
|
apply-transform : Translate [fallback shift 0] 0
|
|
|
|
define [fwr newid unicode id shift wk] : create-glyph [fallback newid : 'fwr' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width [fallback wk FULLWIDTH]
|
|
apply-transform : Translate ([fallback wk FULLWIDTH] - WIDTH + [fallback shift 0]) 0
|
|
|
|
define [dwl newid unicode id shift] : create-glyph [fallback newid : 'dwl' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width UPM
|
|
apply-transform : Translate [fallback shift 0] 0
|
|
|
|
define [dwr newid unicode id shift] : create-glyph [fallback newid : 'dwr' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width UPM
|
|
apply-transform : Translate (UPM - WIDTH + [fallback shift 0]) 0
|
|
|
|
define [dwc newid unicode id shift] : create-glyph [fallback newid : 'dwc' + id] : glyph-construction
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width UPM
|
|
apply-transform : Translate ((UPM - WIDTH) / 2 + [fallback shift 0]) 0
|
|
|
|
|
|
|
|
###### COMMON SHAPES
|
|
define [Rect u d l r transformShiftOnly] : create-glyph : glyph-construction
|
|
local my ((u + d) / 2)
|
|
local mx ((l + r) / 2)
|
|
currentGlyph.gizmo = [if transformShiftOnly [Translate 0 0] globalTransform]
|
|
include : spiro-outline
|
|
begin [lambda : set this.gizmo currentGlyph.gizmo]
|
|
corner l d
|
|
corner l u
|
|
corner r u
|
|
corner r d
|
|
close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]]
|
|
if transformShiftOnly : begin
|
|
local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}]
|
|
apply-transform : Translate (mx1 - mx) (my1 - my)
|
|
define [Ring u d l r transformShiftOnly] : create-glyph : glyph-construction
|
|
local my ((u + d) / 2)
|
|
local mx ((l + r) / 2)
|
|
currentGlyph.gizmo = [if transformShiftOnly [Translate 0 0] globalTransform]
|
|
include : spiro-outline
|
|
begin [lambda : set this.gizmo currentGlyph.gizmo]
|
|
g4 mx d
|
|
archv
|
|
g4 l my
|
|
arcvh
|
|
g4 mx u
|
|
archv
|
|
g4 r my
|
|
arcvh
|
|
close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]]
|
|
if transformShiftOnly : begin
|
|
local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}]
|
|
apply-transform : Translate (mx1 - mx) (my1 - my)
|
|
define [RingAt x y r] : Ring (y + r) (y - r) (x - r) (x + r)
|
|
define [DotAt x y r] : Ring (y + r) (y - r) (x - r) (x + r) true
|
|
|
|
define [CircleRing u d l r transformShiftOnly] : create-glyph : glyph-construction
|
|
local my ((u + d) / 2)
|
|
local mx ((l + r) / 2)
|
|
currentGlyph.gizmo = [if transformShiftOnly [Translate 0 0] globalTransform]
|
|
include : spiro-outline
|
|
begin [lambda : set this.gizmo currentGlyph.gizmo]
|
|
g4 mx d
|
|
g4 l my
|
|
g4 mx u
|
|
g4 r my
|
|
close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]]
|
|
if transformShiftOnly : begin
|
|
local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}]
|
|
apply-transform : Translate (mx1 - mx) (my1 - my)
|
|
define [CircleRingAt x y r] : CircleRing (y + r) (y - r) (x - r) (x + r)
|
|
define [CircleDotAt x y r] : CircleRing (y + r) (y - r) (x - r) (x + r) true
|
|
|
|
define [OShape u d l r _width _sma _smb ai] : glyph-construction
|
|
local middle : (l + r) / 2
|
|
local width : fallback _width STROKE
|
|
local sma : fallback _sma SMALLSMOOTHA
|
|
local smb : fallback _smb SMALLSMOOTHB
|
|
local mc : CORRECTION_OMIDX * width
|
|
if (u - d > sma + smb) : then : begin
|
|
include : dispiro
|
|
widths width 0
|
|
g4 (middle - mc) (u - O)
|
|
archv
|
|
[if ai flat.ai flat] (l + OX) (u - sma)
|
|
[if ai curl.ai curl] (l + OX) (d + smb)
|
|
arcvh
|
|
g4 (middle + mc) (d + O)
|
|
archv
|
|
[if ai flat.ai flat] (r - OX) (d + sma)
|
|
[if ai curl.ai curl] (r - OX) (u - smb)
|
|
arcvh
|
|
close
|
|
: else : begin
|
|
local ymiddlea : mix d u (smb / (sma + smb))
|
|
local ymiddleb : mix d u (sma / (sma + smb))
|
|
include : dispiro
|
|
widths width 0
|
|
g4 (middle - mc) (u - O)
|
|
archv
|
|
g4 (l + OX) ymiddlea
|
|
arcvh
|
|
g4 (middle + mc) (d + O)
|
|
archv
|
|
g4 (r - OX) ymiddleb
|
|
arcvh
|
|
close
|
|
define [OShapeOutline u d l r _width _sma _smb ai] : glyph-construction
|
|
local middle : (l + r) / 2
|
|
local width : fallback _width STROKE
|
|
local sma : fallback _sma SMALLSMOOTHA
|
|
local smb : fallback _smb SMALLSMOOTHB
|
|
local mc : CORRECTION_OMIDX * width
|
|
if (u - d > sma + smb) : then : begin
|
|
include : spiro-outline
|
|
g4 (middle - mc) (u - O)
|
|
archv
|
|
[if ai flat.ai flat] (l + OX) (u - sma)
|
|
[if ai curl.ai curl] (l + OX) (d + smb)
|
|
arcvh
|
|
g4 (middle + mc) (d + O)
|
|
archv
|
|
[if ai flat.ai flat] (r - OX) (d + sma)
|
|
[if ai curl.ai curl] (r - OX) (u - smb)
|
|
arcvh
|
|
close
|
|
: else : begin
|
|
local ymiddlea : mix d u (smb / (sma + smb))
|
|
local ymiddleb : mix d u (sma / (sma + smb))
|
|
include : spiro-outline
|
|
g4 (middle - mc) (u - O)
|
|
archv
|
|
g4 (l + OX) ymiddlea
|
|
arcvh
|
|
g4 (middle + mc) (d + O)
|
|
archv
|
|
g4 (r - OX) ymiddleb
|
|
arcvh
|
|
close
|
|
define [OBarLeftShape _top _left] : glyph-construction
|
|
local top : fallback _top XH
|
|
local left : fallback _left SB
|
|
local fine SHOULDERFINE
|
|
local st : shoulderMidSlope fine nothing 1
|
|
local sb : shoulderMidSlope fine nothing (-1)
|
|
local mt : [mix left RIGHTSB 0.5] + (st - CORRECTION_OMIDX) * STROKE
|
|
local mb : [mix left RIGHTSB 0.5] + (sb + CORRECTION_OMIDX) * STROKE
|
|
include : dispiro
|
|
flat (left + (STROKE - fine) * HVCONTRAST) (top - SMALLSMOOTHA - 0.01) [widths fine 0]
|
|
curl (left + (STROKE - fine) * HVCONTRAST) (0 + SMALLSMOOTHB) [widths fine 0]
|
|
arcvh
|
|
g4 (mb) O [widths.heading STROKE 0 {.y (1) .x (-sb)}]
|
|
archv
|
|
[if ((SMALLSMOOTHA + SMALLSMOOTHB) / top > 0.75) flat.ai flat] (RIGHTSB - OX) (0 + SMALLSMOOTHA)
|
|
[if ((SMALLSMOOTHA + SMALLSMOOTHB) / top > 0.75) curl.ai curl] (RIGHTSB - OX) (top - SMALLSMOOTHB)
|
|
arcvh
|
|
g4 (mt) (top - O) [widths.heading STROKE 0 {.y (-1) .x (-st)}]
|
|
archv
|
|
flat (left + (STROKE - fine) * HVCONTRAST) (top - SMALLSMOOTHA) [widths fine 0]
|
|
curl (left + (STROKE - fine) * HVCONTRAST) (top - SMALLSMOOTHA - 0.01) [widths fine 0]
|
|
|
|
define [OBarRightShape top right] : glyph-construction
|
|
include : create-glyph [OBarLeftShape top (WIDTH - [fallback right RIGHTSB])]
|
|
include : FlipAround MIDDLE ([fallback top XH] / 2)
|
|
|
|
define SERIF_SHIFT_X 0.6
|
|
define [LeftwardTopSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x + sw / 2 * HVCONTRAST) y [widths.heading sw 0 LEFTWARD]
|
|
curl (x - length - TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [LeftwardBottomSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x + sw / 2 * HVCONTRAST) y [widths.heading 0 sw LEFTWARD]
|
|
curl (x - length + TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [RightwardTopSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x - sw / 2 * HVCONTRAST) y [widths.heading 0 sw RIGHTWARD]
|
|
curl (x + length - TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [RightwardBottomSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x - sw / 2 * HVCONTRAST) y [widths.heading sw 0 RIGHTWARD]
|
|
curl (x + length + TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [CenterTopSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x + length - TANSLANT * (sw * SERIF_SHIFT_X)) y [widths sw 0]
|
|
curl (x - length - TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [CenterBottomSerif x y length _sw] : glyph-construction
|
|
local sw : fallback _sw STROKE
|
|
include : dispiro
|
|
flat (x + length + TANSLANT * (sw * SERIF_SHIFT_X)) y [widths 0 sw]
|
|
curl (x - length + TANSLANT * (sw * SERIF_SHIFT_X)) y
|
|
|
|
define [DownwardRightSerif x y length sw] : glyph-construction
|
|
include : dispiro
|
|
widths.rhs sw
|
|
flat x y [heading DOWNWARD]
|
|
curl x (y - length) [heading DOWNWARD]
|
|
define [UpwardRightSerif x y length sw] : glyph-construction
|
|
include : dispiro
|
|
widths.lhs sw
|
|
flat x y [heading UPWARD]
|
|
curl x (y + length) [heading UPWARD]
|
|
define [DownwardLeftSerif x y length sw] : glyph-construction
|
|
include : dispiro
|
|
widths.lhs sw
|
|
flat x y [heading DOWNWARD]
|
|
curl x (y - length) [heading DOWNWARD]
|
|
define [UpwardLeftSerif x y length sw] : glyph-construction
|
|
include : dispiro
|
|
widths.rhs sw
|
|
flat x y [heading UPWARD]
|
|
curl x (y + length) [heading UPWARD]
|
|
|
|
define sideSerifK 0.5
|
|
define [AIVSerifs top _left _right] : glyph-construction
|
|
local left : fallback _left SB
|
|
local right : fallback _right RIGHTSB
|
|
if SLAB : begin
|
|
include : CenterTopSerif (left + STROKE * sideSerifK * HVCONTRAST) top JUT
|
|
tag-contour 'serifLT'
|
|
include : CenterTopSerif (right - STROKE * sideSerifK * HVCONTRAST) top JUT
|
|
tag-contour 'serifRT'
|
|
define [AIHSerifs top _left _right] : glyph-construction
|
|
local left : fallback _left SB
|
|
local right : fallback _right RIGHTSB
|
|
if SLAB : begin
|
|
include : AIVSerifs top _left _right
|
|
include : CenterBottomSerif (left + STROKE * sideSerifK * HVCONTRAST) 0 JUT
|
|
include : CenterBottomSerif (right - STROKE * sideSerifK * HVCONTRAST) 0 JUT
|
|
define [AINSerifs top _left _right sw xn] : glyph-construction
|
|
local left : fallback _left SB
|
|
local right : fallback _right RIGHTSB
|
|
local jut : JUT * [fallback xn 1]
|
|
if SLAB : begin
|
|
include : LeftwardTopSerif (left + sw * (sideSerifK - 0.5) * HVCONTRAST) top (jut - sw / 2 * HVCONTRAST)
|
|
include : CenterTopSerif (right - sw * sideSerifK * HVCONTRAST) top jut
|
|
include : CenterBottomSerif (left + sw * sideSerifK * HVCONTRAST) 0 jut
|
|
tag-contour 'serifLB'
|
|
#include : CenterdBottomSerif (right - STROKE * (sideSerifK - 0.5) * HVCONTRAST) 0 (JUT / 2)
|
|
define [AICyrISerifs top _left _right] : glyph-construction
|
|
local left : fallback _left SB
|
|
local right : fallback _right RIGHTSB
|
|
if SLAB : begin
|
|
include : LeftwardBottomSerif left 0 SIDEJUT
|
|
include : RightwardTopSerif right top SIDEJUT
|
|
include : CenterTopSerif (left + STROKE * sideSerifK * HVCONTRAST) top JUT
|
|
include : CenterBottomSerif (right - STROKE * sideSerifK * HVCONTRAST) 0 JUT
|
|
tag-contour 'serifRB'
|
|
define [AIMSerifs top _left _right] : glyph-construction
|
|
local left : fallback _left SB
|
|
local right : fallback _right RIGHTSB
|
|
if SLAB : begin
|
|
include : LeftwardTopSerif (left + STROKE * (sideSerifK - 0.5) * HVCONTRAST) top SIDEJUT
|
|
include : RightwardTopSerif (right - STROKE * (sideSerifK - 0.5) * HVCONTRAST) top SIDEJUT
|
|
include : CenterBottomSerif (left + STROKE * sideSerifK * HVCONTRAST) 0 JUT
|
|
include : CenterBottomSerif (right - STROKE * sideSerifK * HVCONTRAST) 0 JUT
|
|
|
|
|
|
define [diagCor dy dx dyt dxt] : begin
|
|
local ay : Math.max 0 : [Math.abs dy] - [fallback dyt 0]
|
|
local ax : Math.max 0 : [Math.abs dx] - [fallback dxt 0]
|
|
return : [Math.hypot ay ax] / ay
|
|
|
|
define [halfXStrand stb _leftx lefty rightx righty turn straight tension _fine] : glyph-construction
|
|
local sbCor : if stb ((OX * 4) * ([Math.abs (lefty - righty)] / CAP)) 0
|
|
local leftx : _leftx + ((HALFSTROKE * HVCONTRAST + sbCor) * [if (rightx > _leftx) 1 (-1)])
|
|
local fine : (_fine || STROKE) * 0.5
|
|
|
|
local turnyleft : mix lefty righty turn
|
|
local cyleft : mix turnyleft righty tension
|
|
|
|
local straightxleft : mix leftx rightx straight
|
|
local straightyleft : mix cyleft righty straight
|
|
|
|
if stb : begin
|
|
local hst : HALFSTROKE * [diagCor (righty - lefty) (rightx - leftx) 0 STROKE]
|
|
local hse : HALFSTROKE * ([adviceBlackness 3.5] / STROKE)
|
|
include : dispiro
|
|
corner leftx lefty [widths.heading hst hst [if (lefty < righty) UPWARD DOWNWARD]]
|
|
corner rightx righty [widths hse hse]
|
|
|
|
: else : begin
|
|
include : dispiro
|
|
widths.center
|
|
flat leftx lefty [heading [if (lefty < righty) UPWARD DOWNWARD]]
|
|
curl leftx turnyleft [heading [if (lefty < righty) UPWARD DOWNWARD]]
|
|
quadcontrols 0 ((cyleft - turnyleft) / (straightyleft - turnyleft)) 24
|
|
flat straightxleft straightyleft
|
|
curl rightx righty
|
|
|
|
define [xStrand stb _leftx lefty _rightx righty turn straight tension] : glyph-construction
|
|
local middlex : mix _leftx _rightx 0.5
|
|
local middley : mix lefty righty 0.5
|
|
|
|
include : halfXStrand stb _leftx lefty middlex middley turn straight tension
|
|
include : halfXStrand stb _rightx righty middlex middley turn straight tension
|
|
|
|
define [nShoulderKnots] : params [left right [fine SHOULDERFINE] [top XH] [bottom 0] [sma SMALLSMOOTHA] [smb SMALLSMOOTHB] [stroke STROKE]] : begin
|
|
local slope : shoulderMidSlope fine stroke
|
|
local middle : [mix (left - stroke * HVCONTRAST) right 0.5] + (slope - CORRECTION_OMIDX) * stroke
|
|
return : list
|
|
flat left (top - sma - 2) [widths fine 0]
|
|
curl left (top - sma)
|
|
arcvh
|
|
g4 middle (top - O) [widths.heading 0 stroke {.y (1) .x (slope)}]
|
|
archv
|
|
flat right (top - smb)
|
|
curl right bottom [heading DOWNWARD]
|
|
|
|
define [nShoulder] : begin
|
|
local a arguments
|
|
glyph-construction
|
|
include : dispiro : nShoulderKnots.apply null a
|
|
|
|
|
|
define [mShoulderSpiro] : params [left right top bottom width fine diversity] : glyph-construction
|
|
local fix : TANSLANT * STROKE * HVCONTRAST * width / STROKE
|
|
local sm : SMALLSMOOTH * 0.7 * [fallback diversity 1]
|
|
include : spiro-outline
|
|
corner (right - width * HVCONTRAST) bottom
|
|
curl (right - width * HVCONTRAST) (top - sm + fix)
|
|
arcvh 8
|
|
g2 [mix left (right - width * HVCONTRAST) 0.5] (top - O - width)
|
|
archv 8
|
|
flat left (top - sm - fix)
|
|
corner left (top - sm - fix - 1)
|
|
corner (left - fine) (top - sm - 1)
|
|
curl (left - fine) (top - sm)
|
|
arcvh 8
|
|
g2 [mix (left - fine * HVCONTRAST) right 0.5] (top - O)
|
|
archv 8
|
|
flat right (top - sm)
|
|
corner right bottom
|
|
close
|
|
|
|
|
|
define [HBar xleft xright y _fine] : glyph-construction
|
|
include : dispiro
|
|
widths.center [fallback _fine STROKE]
|
|
flat xleft y [heading : Rightward.call this]
|
|
curl xright y [heading : Rightward.call this]
|
|
|
|
define [HBarTop xl xr y _fine] : HBar xl xr (y - [fallback _fine STROKE] * 0.5) _fine
|
|
define [HBarBottom xl xr y _fine] : HBar xl xr (y + [fallback _fine STROKE] * 0.5) _fine
|
|
define [HOverlayBar xleft xright y s] : dispiro
|
|
widths.center [fallback s OVERLAYSTROKE]
|
|
flat xleft y
|
|
curl xright y
|
|
define [VBar x ydown yup _fine] : glyph-construction
|
|
local fine : fallback _fine STROKE
|
|
include : dispiro
|
|
widths.center fine
|
|
flat x ydown [heading : [if (ydown < yup) Upward Downward].call this]
|
|
curl x yup [heading : [if (ydown < yup) Upward Downward].call this]
|
|
|
|
define [VBarLeft x yd yu _fine] : VBar (x + [fallback _fine STROKE] * 0.5 * HVCONTRAST) yd yu _fine
|
|
define [VBarRight x yd yu _fine] : VBar (x - [fallback _fine STROKE] * 0.5 * HVCONTRAST) yd yu _fine
|
|
|
|
define [VerticalHook x y extend depth fine strg] : glyph-construction
|
|
include : dispiro
|
|
widths.center [fallback fine STROKE]
|
|
flat x (y + [fallback strg 0]) [heading [if (depth > 0) DOWNWARD UPWARD]]
|
|
curl x (y - [if (depth > 0) 0.01 (-0.01)]) [heading [if (depth > 0) DOWNWARD UPWARD]]
|
|
arcvh
|
|
flat (x + extend - [if (extend > 0) 0.01 (-0.01)]) (y - depth)
|
|
curl (x + extend) (y - depth)
|
|
|
|
define [LegShape] : params [[ztop nothing (xt <> top)] [zbot nothing (xs <> bottom)] xb [fine STROKE]] : glyph-construction
|
|
include : dispiro
|
|
widths.lhs fine
|
|
flat xt top [heading DOWNWARD]
|
|
curl xb (bottom + LONGJUT)
|
|
alsothruthem {{0.5 0.94}}
|
|
g4.left.end xs (bottom + fine) [heading LEFTWARD]
|
|
|
|
define [LeftHook x y xextend] : glyph-construction
|
|
local fine : adviceBlackness 4.25
|
|
include : dispiro
|
|
widths.lhs fine
|
|
flat [fallback xextend : x + 1] y
|
|
curl x y
|
|
archv 8
|
|
g4.down.end (x - LeftHook.extension) (y - HOOKX) [heading DOWNWARD]
|
|
set LeftHook.extension [Math.max (WIDTH * 0.15) ([adviceBlackness 4.25] * 1.5)]
|
|
|
|
define [HooktopLeftBar stroke bottom] : glyph-construction
|
|
include : dispiro
|
|
widths.lhs [fallback stroke STROKE]
|
|
g4 RIGHTSB (CAP - HOOK)
|
|
hookstart CAPO
|
|
flat SB (CAP - SMALLSMOOTHA)
|
|
curl SB [fallback bottom 0] [heading DOWNWARD]
|
|
|
|
define [CurlyTail] : params [fine rinner xleft bottom right x2 y2 [adj 0.4] [adj2 0.4] [adj3 0]] : begin
|
|
local ltr : right > xleft
|
|
set right : right - fine * [if ltr 1 (-1)]
|
|
local mid : mix [mix xleft right 0.5] (right - rinner * [if ltr 1 (-1)]) adj
|
|
local midu : mix [mix xleft right 0.5] (right - rinner * [if ltr 1 (-1)]) adj2
|
|
return : list
|
|
g4.[if ltr 'right' 'left'].mid (mid + CORRECTION_OMIDX * fine * adj3 * [if ltr 1 (-1)]) (bottom + fine + O) [widths [if ltr 0 fine] [if ltr fine 0]]
|
|
archv 2
|
|
g4 right (bottom + fine + rinner - 0.1)
|
|
g4 right (bottom + fine + rinner + 0.1)
|
|
arcvh 2
|
|
g4 mid (bottom + fine + rinner * 2 - O)
|
|
alsothruthem {{0.25 0.06} {0.52 0.25}} important
|
|
g4 x2 y2
|
|
|
|
define [HCurlyTail fine wide rinner left m1 _right x1 x2 y2] : glyph-construction
|
|
local right : _right - fine
|
|
local mid : right - rinner + O
|
|
include : dispiro
|
|
widths.rhs wide
|
|
flat left wide [heading RIGHTWARD]
|
|
curl m1 wide [heading RIGHTWARD]
|
|
archv 8
|
|
g4 right (wide + rinner - O / 2) [widths.heading 0 fine {.x (-HVCONTRAST) .y ((wide - fine) / (wide + rinner * 2 - O))}]
|
|
arcvh 8
|
|
g4.left.mid mid (wide + rinner * 2 - O) [heading LEFTWARD]
|
|
quadcontrols ((x1 - mid) / (x2 - mid)) 0 8
|
|
g4 x2 y2
|
|
|
|
define [FlatSlashShape middlex middle fine kx ky] : glyph-construction
|
|
include : dispiro
|
|
flat (middlex - LONGJUT * [fallback kx 0.8]) (middle - LONGJUT * [fallback ky 0.4]) [widths fine fine]
|
|
curl (middlex + LONGJUT * [fallback kx 0.8]) (middle + LONGJUT * [fallback ky 0.4])
|
|
|
|
# Spiro shapes
|
|
define [determineMixR w v u sw swash] : begin
|
|
if (!swash && w < v) : return : 1 - [determineMixR v w u sw swash]
|
|
local superness SUPERNESS
|
|
local r : piecewise
|
|
(w <= v) 0.5
|
|
true : 1 / ([Math.pow (1 - [Math.pow (1 - v / w) superness]) (1 / superness)] + 1)
|
|
if swash : begin
|
|
local idepth : w - sw
|
|
local iwidth : u * r - sw
|
|
if (iwidth > 0 && idepth > 0 && iwidth / idepth >= 2) : begin
|
|
local adjust : clamp 0.975 1 (1 - (iwidth / idepth - 2) * 0.0125)
|
|
#console.log iwidth idepth (iwidth / idepth) adjust
|
|
r = r * adjust
|
|
if (r < 0.5) : set r 0.5
|
|
return r
|
|
|
|
define nHookSegments 12
|
|
define [HookShape toStraight toFinish isStart y tight _sw _swItalicAdj] : begin
|
|
local atBottom : toStraight.y > y
|
|
local sw : fallback _sw STROKE
|
|
local swItalicAdj : fallback _swItalicAdj sw
|
|
local ltr : if isStart (toFinish.x < toStraight.x) (toFinish.x > toStraight.x)
|
|
local dtu : if isStart (y > toFinish.y) (y < toFinish.y)
|
|
local doSwash : !tight && para.isItalic && ltr && atBottom && !isStart
|
|
local superness : if tight para.tightHookSuperness SUPERNESS
|
|
|
|
# Adjust terminal's position if necessary
|
|
toFinish.x = toFinish.x + OXHOOK * [if ltr (-1) 1] * [if isStart (-1) 1]
|
|
if (doSwash) : begin
|
|
toFinish.x = toFinish.x + TAILADJX * TANSLANT
|
|
toFinish.y = toFinish.y - TAILADJY * TANSLANT
|
|
|
|
# Compute key middle knot
|
|
local w : Math.abs (toStraight.y - y)
|
|
local v : Math.abs (toFinish.y - y)
|
|
local u : Math.abs (toFinish.x - toStraight.x)
|
|
local mixRatio : determineMixR w v u sw doSwash
|
|
local mxSwMultiplier : [if (tight && tight.shift) tight.shift (1 - (tight || 0))] * [if atBottom 1 (-1)]
|
|
local mx : [mix toStraight.x toFinish.x mixRatio] + mxSwMultiplier * CORRECTION_OMIDX * swItalicAdj
|
|
local keyKnot : g4.[if ltr "right" "left"].mid
|
|
begin mx
|
|
begin y
|
|
if [not tight] nothing : let [s : if ltr RIGHTWARD LEFTWARD]
|
|
heading {.x (s.x * [fallback tight.skew 1]) .y s.y}
|
|
|
|
# Adjust terminal's direction
|
|
do "Adjust terminal's direction"
|
|
local rad : Math.min w (mixRatio * u)
|
|
local skew0 : [clamp 0 w (w - v)] / rad + ([clamp 1 1.5 (mixRatio * u / w)] - 1) * 0.5
|
|
local depth : v + skew0 * sw - sw
|
|
local shallowLimit : sw / 2
|
|
local skew : clamp 0 (1 / 2) : skew0 + [clamp 0 shallowLimit (shallowLimit - depth)] / rad
|
|
local faf toFinish.af
|
|
set toFinish.af : lambda [] : begin
|
|
if faf : faf.apply this arguments
|
|
if this.heads-to : this.heads-to : if doSwash
|
|
then : begin {
|
|
.x (CONTRAST / [Math.sqrt : 1 + skew * skew] * [if dtu (-1) 1])
|
|
.y (skew / [Math.sqrt : 1 + skew * skew] * [if ltr 1 (-1)])
|
|
}
|
|
else : begin {
|
|
.x (CONTRAST * [if dtu (-1) 1])
|
|
.y 0
|
|
}
|
|
if [not doSwash] : set toFinish.y : toFinish.y + skew * sw * [if (y > toFinish.y) (-1) (+1)]
|
|
|
|
# Create the arc knots
|
|
local segBefore {}
|
|
local segAfter {}
|
|
foreach [j : range 1 nHookSegments] : begin
|
|
local fraction : j / nHookSegments
|
|
local mixRatioAdjust : Math.max (1 / 2) : (1 / 2) + [if doSwash 1 : if tight 0 (1 / 8)] * (mixRatio - (1 / 2))
|
|
local fractionAfter : fraction * (1 - mixRatioAdjust) / mixRatioAdjust
|
|
local myfinal : superxy ((1 - mixRatioAdjust) / mixRatioAdjust) superness
|
|
segBefore.push : g4
|
|
mix mx toStraight.x fraction
|
|
mix y toStraight.y (1 - [superxy fraction superness])
|
|
begin unimportant
|
|
segAfter.push : g4
|
|
mix mx toFinish.x fraction
|
|
mix y toFinish.y ((1 - [superxy fractionAfter superness]) / (1 - myfinal))
|
|
begin unimportant
|
|
# if (!tight && w < u * mixRatio) : set segAfter {}
|
|
|
|
if isStart
|
|
: then : return : list
|
|
segAfter.reverse
|
|
* keyKnot
|
|
* segBefore
|
|
: else : return : list
|
|
segBefore.reverse
|
|
* keyKnot
|
|
* segAfter
|
|
|
|
define [hookstart] : params [y tight sw swItalicAdj] : return {
|
|
.type 'interpolate'
|
|
.af [lambda [before after] [HookShape after before true y tight sw swItalicAdj]]
|
|
}
|
|
define [hookend] : params [y tight sw swItalicAdj] : return {
|
|
.type 'interpolate'
|
|
.af [lambda [before after] [HookShape before after false y tight sw swItalicAdj]]
|
|
}
|
|
|
|
define [CyrDescender x shift connex] : glyph-construction
|
|
local descenderOverflow : if SLAB SIDEJUT ((RIGHTSB - SB) * [fallback shift 0.1])
|
|
include : VBarRight (x + descenderOverflow + 0.25 * STROKE) (HALFSTROKE - LONGJUT) STROKE
|
|
if (!SLAB && descenderOverflow > STROKE * 0.75 || connex) : include : HBarTop (x - HALFSTROKE * HVCONTRAST) (x + descenderOverflow) STROKE
|
|
|
|
# Derived subfonts
|
|
define [refair g] : begin
|
|
foreach [j : range 0 g.contours.length] : begin
|
|
set g.contours.(j) : fairify g.contours.(j) globalTransform
|
|
return nothing
|
|
define [Fork gs ps] : begin
|
|
# BFS construct ShouldBuildList
|
|
local sbh {.}
|
|
local found true
|
|
local PENDING 1
|
|
local CHECKED 2
|
|
foreach [glyphid : items-of gs] : set sbh.(glyphid) PENDING
|
|
while found : begin
|
|
set found false
|
|
foreach [glyphid : items-of : Object.keys sbh] : if (sbh.(glyphid) === PENDING) : begin
|
|
set sbh.(glyphid) CHECKED
|
|
if dependencyProfile.(glyphid) : foreach [k : items-of dependencyProfile.(glyphid)] : if [not sbh.(k)] : begin
|
|
set sbh.(k) PENDING
|
|
set found true
|
|
|
|
local shouldBuildList : Object.keys sbh :.filter ([x] => [not [not x]])
|
|
#console.log shouldBuildList
|
|
local shouldBuildUnicodes : shouldBuildList.map ([x] => [if (glyphs.(x) && glyphs.(x).unicode) glyphs.(x).unicode.0 nothing])
|
|
:.filter ([x] => [not [not x]])
|
|
|
|
local p {.}
|
|
foreach [{k v} : pairs-of all ps] : set p.(k) v
|
|
try : begin
|
|
local forkFont : buildFont.call [TempFont] p shouldBuildList shouldBuildUnicodes
|
|
: ex
|
|
: begin
|
|
if ex.glyfMap : return ex.glyfMap
|
|
: else : throw ex
|
|
return forkFont.glyfMap
|
|
|
|
define [Miniature] : params [glyphs crowd scale [slantAngle para.slantAngle] unfair [sbscale (WIDTH / UPM)] [mono false]] : begin
|
|
local forkedPara : Object.create para
|
|
forkedPara.stroke = [adviceBlackness crowd] / scale
|
|
forkedPara.ess = para.ess * forkedPara.stroke / para.stroke
|
|
forkedPara.dotsize = para.dotsize * forkedPara.stroke / para.stroke
|
|
forkedPara.periodsize = para.periodsize * forkedPara.stroke / para.stroke
|
|
forkedPara.sb = SB * sbscale
|
|
forkedPara.slantAngle = slantAngle
|
|
forkedPara.unfair = unfair
|
|
if mono : begin
|
|
forkedPara.diversityM = 1
|
|
return : Fork glyphs forkedPara
|
|
|
|
define [Thinner glyphs p] : begin
|
|
local forkedPara : Object.create para
|
|
forkedPara.width = WIDTH * p
|
|
forkedPara.accentx = ACCENTX * p
|
|
forkedPara.jut = JUT * p
|
|
forkedPara.longjut = LONGJUT * p
|
|
forkedPara.diversityM = 1
|
|
#forkedPara.hookx = HOOKX * p
|
|
return : Fork glyphs forkedPara
|
|
|
|
define [Widen glyphs p psb] : begin
|
|
local forkedPara : Object.create para
|
|
forkedPara.width = WIDTH * p
|
|
forkedPara.sb = SB * [fallback psb p]
|
|
forkedPara.accentx = ACCENTX * p
|
|
forkedPara.jut = JUT * p
|
|
forkedPara.longjut = LONGJUT * p
|
|
forkedPara.hookx = HOOKX * p
|
|
forkedPara.smoothadjust = para.smoothadjust * p
|
|
return : Fork glyphs forkedPara
|
|
|
|
# Composite transformations
|
|
define [FlipAround x y sx sy] : glyph-construction
|
|
apply-transform : Upright
|
|
apply-transform : Translate (-x) (-y)
|
|
apply-transform : Scale [fallback sx (-1)] [fallback sy sx (-1)]
|
|
apply-transform : Translate x y
|
|
apply-transform : Italify
|
|
define ScaleAround FlipAround
|
|
|
|
define [Realign x y sx sy] : glyph-construction
|
|
apply-transform : Upright
|
|
apply-transform : Translate (-x) (-y)
|
|
apply-transform : Translate sx sy
|
|
apply-transform : Italify
|
|
|
|
define [ForceUpright] : glyph-construction
|
|
set this.gizmo : Translate 0 0
|
|
|
|
define [Overlay overlay background] : glyph-construction
|
|
define sw : [adviceBlackness 6] / 2
|
|
local candidates {}
|
|
define segs 3
|
|
if background.anchors : include {.anchors background.anchors}
|
|
|
|
foreach [r : range (0 - segs) till (segs)] : foreach [c : range (0 - segs) till (segs)] : do
|
|
define dx : r / segs * sw
|
|
define dy : c / segs * sw
|
|
candidates.push : glyph-construction
|
|
if background.anchors : include {.anchors background.anchors}
|
|
include overlay
|
|
apply-transform : Translate dx dy
|
|
|
|
foreach [c : items-of overlay.contours] : foreach [z : items-of c] : if z.on : do
|
|
define x z.x
|
|
define y z.y
|
|
candidates.push : glyph-construction
|
|
set this.gizmo : Translate 0 0
|
|
start-from (x - sw) (y - sw)
|
|
line-to (x + sw) (y - sw)
|
|
line-to (x + sw) (y + sw)
|
|
line-to (x - sw) (y + sw)
|
|
|
|
include : difference background [union.apply null candidates]
|
|
include overlay
|
|
|
|
define [CreateWaveShape dist sw] : begin
|
|
define WaveResolution 8
|
|
define WaveMagnitude : dist * (3 / 4) - sw / 2
|
|
define WaveAdj : TANSLANT * WaveMagnitude * (-0.75)
|
|
define [WaveShapeImpl] : params [left right ts te xsJoin xfJoin] : glyph-construction
|
|
local resolution : Math.ceil (WaveResolution * (te - ts))
|
|
local knots {}
|
|
foreach [pr : range 0 till resolution] : begin
|
|
local theta : [mix ts te (pr / resolution)] * Math.PI * 2
|
|
local waveRelY : (-1) * [Math.sin theta] - 0.075 * [Math.sin (theta * 3)]
|
|
local flat : [Math.abs ([mix ts te (pr / resolution)] * 2 % 1)] < 1 / WaveResolution
|
|
knots.push : g2
|
|
(WaveAdj * waveRelY) + [mix left right (pr / resolution)]
|
|
symbolMid + WaveMagnitude * waveRelY
|
|
include : dispiro
|
|
widths.center sw
|
|
if (xsJoin !== nothing) {[straight.right.start xsJoin symbolMid]} {}
|
|
begin knots
|
|
if (xfJoin !== nothing) {[straight.right.end xfJoin symbolMid]} {}
|
|
|
|
define [WaveShape] : params [left right xsJoin xfJoin [unitWidth WIDTH]] : WaveShapeImpl (unitWidth * -left) (unitWidth * (1 + right)) (-left * 2) (2 + right * 2) xsJoin xfJoin
|
|
return WaveShape
|
|
|
|
return [object queryFeatureSelector select-variant italic-variant alias composite into-unicode turned dual hcombine vdual vcombine fwl fwr dwl dwr dwc Rect Ring RingAt DotAt CircleRing CircleRingAt CircleDotAt OShape OShapeOutline OBarLeftShape OBarRightShape LeftwardTopSerif LeftwardBottomSerif RightwardTopSerif RightwardBottomSerif CenterTopSerif CenterBottomSerif DownwardRightSerif UpwardRightSerif DownwardLeftSerif UpwardLeftSerif AIVSerifs AIHSerifs AINSerifs AICyrISerifs AIMSerifs halfXStrand xStrand nShoulderKnots nShoulder mShoulderSpiro HBar HBarTop HBarBottom HOverlayBar VBar VBarLeft VBarRight VerticalHook LegShape LeftHook HooktopLeftBar CurlyTail HCurlyTail FlatSlashShape determineMixR hookstart hookend CyrDescender refair Fork Miniature Thinner Widen FlipAround ScaleAround Realign ForceUpright Overlay diagCor CreateWaveShape]
|