471 lines
17 KiB
Plaintext
471 lines
17 KiB
Plaintext
###### COMMON SHAPES
|
|
|
|
define [Ring u d l r transformShiftOnly] : begin {
|
|
local my [[u + d] / 2]
|
|
local mx [[l + r] / 2]
|
|
local s : new Stroke
|
|
if [not transformShiftOnly] : s.set-transform globalTransform
|
|
s.start-from mx d
|
|
:.cubic-to [mx + [l - mx] * CKAPPA] d l [my + [d - my] * CKAPPA] l my
|
|
:.cubic-to l [my + [u - my] * CKAPPA] [mx + [l - mx] * CKAPPA] u mx u
|
|
:.cubic-to [mx + [r - mx] * CKAPPA] u r [my + [u - my] * CKAPPA] r my
|
|
:.cubic-to r [my + [d - my] * CKAPPA] [mx + [r - mx] * CKAPPA] d mx d
|
|
if transformShiftOnly : begin {
|
|
local (.x mx1 .y my1) [tp globalTransform (.x mx .y my)]
|
|
foreach p [items-of s.points] : begin {
|
|
set p.x : p.x + mx1 - mx
|
|
set p.y : p.y + my1 - my
|
|
}
|
|
}
|
|
return s.points
|
|
}
|
|
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 [ORing u d l r sma smb shift] : begin {
|
|
local mx [[l + r] / 2]
|
|
local s : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [mx + shift] d
|
|
:.arc-hv-to l [d + smb]
|
|
:.line-to l [u - sma]
|
|
:.arc-vh-to [mx - shift] u
|
|
:.arc-hv-to r [u - smb]
|
|
:.line-to r [d + sma]
|
|
:.arc-vh-to [mx + shift] d
|
|
return s.points
|
|
}
|
|
define [leftwardTopSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x + HALFSTROKE] y
|
|
:.heads-to LEFTWARD
|
|
:.set-width STROKE 0
|
|
:.line-to [x - length - globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
define [leftwardBottomSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x + HALFSTROKE] y
|
|
:.heads-to LEFTWARD
|
|
:.set-width 0 STROKE
|
|
:.line-to [x - length + globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
define [rightwardTopSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x - HALFSTROKE] y
|
|
:.heads-to RIGHTWARD
|
|
:.set-width 0 STROKE
|
|
:.line-to [x + length - globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
define [rightwardBottomSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x - HALFSTROKE] y
|
|
:.heads-to RIGHTWARD
|
|
:.set-width STROKE 0
|
|
:.line-to [x + length + globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
define [centerTopSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x + length - globalTransform.yx * STROKE] y
|
|
:.set-width STROKE 0
|
|
:.line-to [x - length - globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
define [centerBottomSerif x y length] : begin {
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [x + length + globalTransform.yx * STROKE] y
|
|
:.set-width 0 STROKE
|
|
:.line-to [x - length + globalTransform.yx * STROKE] y
|
|
:.to-outline
|
|
}
|
|
|
|
define [xsStrand _xleft yleft _xright yright _halfstroke0 _halfstroke1 _ess _expansion _roundp] : begin {
|
|
local expansion : _expansion || 0.25
|
|
local halfstroke0 : _halfstroke0 || HALFSTROKE
|
|
local halfstroke1 : _halfstroke1 || HALFSTROKE
|
|
local ess : _ess || [halfstroke0 + halfstroke1] / 2
|
|
local upright : Upright
|
|
# calculate italic correction
|
|
local outline : [new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from _xleft yleft
|
|
:.set-width [2 * halfstroke0] 0
|
|
:.line-to _xleft [yleft - 1000]
|
|
:.max-samples 1
|
|
:.to-outline].0.map : [p] -> [tp upright p]
|
|
local xItalicCorrection : -[outline.3.x - outline.0.x] / [2 * halfstroke0]
|
|
local yItalicCorrection : [outline.3.y - outline.0.y] / [2 * halfstroke0]
|
|
|
|
local roundsize : [_roundp || SMOOTHA * 0.4] * [if [yleft < yright] [-1] 1]
|
|
local roundleft [yleft - roundsize]
|
|
local roundright [yright + roundsize]
|
|
local xleft : _xleft + halfstroke0 * xItalicCorrection
|
|
local xright : _xright - halfstroke1 * xItalicCorrection
|
|
local sxleft : mix xleft xright [0.5 - expansion]
|
|
local sxright : mix xleft xright [0.5 + expansion]
|
|
local syleft : mix roundleft roundright [0.5 - expansion]
|
|
local syright : mix roundleft roundright [0.5 + expansion]
|
|
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from xleft [yleft - halfstroke0 * yItalicCorrection]
|
|
:.set-width halfstroke0 halfstroke0
|
|
:.curve-to xleft roundleft sxleft syleft
|
|
:.set-width ess ess
|
|
:.line-to sxright syright
|
|
:.curve-to xright roundright xright [yright + halfstroke1 * yItalicCorrection]
|
|
:.set-width halfstroke1 halfstroke1
|
|
:.to-outline
|
|
}
|
|
define [sStrand yleft yright _expansion] : begin {
|
|
return : xsStrand SB yleft RIGHTSB yright HALFSTROKE HALFSTROKE HALFSTROKE _expansion [SMOOTHA * 0.4]
|
|
}
|
|
|
|
define [halfXStrand _leftx lefty rightx righty turn straight tension _fine] : begin {
|
|
local leftx : _leftx + [HALFSTROKE * CORRECTION_HX * [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
|
|
|
|
return : new Stroke
|
|
:.set-transform globalTransform
|
|
:.start-from leftx lefty
|
|
:.set-width HALFSTROKE HALFSTROKE
|
|
:.heads-to [if [lefty < righty] UPWARD DOWNWARD]
|
|
:.line-to leftx turnyleft
|
|
:.heads-to [if [lefty < righty] UPWARD DOWNWARD]
|
|
:.curve-to leftx cyleft straightxleft straightyleft
|
|
:.set-width fine fine
|
|
:.line-to rightx righty
|
|
:.to-outline
|
|
}
|
|
|
|
define [xStrand _leftx lefty _rightx righty turn straight tension] : begin {
|
|
local middlex : mix _leftx _rightx 0.5
|
|
local middley : mix lefty righty 0.5
|
|
|
|
return : halfXStrand _leftx lefty middlex middley turn straight tension
|
|
:.concat : halfXStrand _rightx righty middlex middley turn straight tension
|
|
}
|
|
define [nShoulderKnots left _middle right fine _top _bottom _sma _smb _wide] : begin {
|
|
local top : fallback _top XH
|
|
local bottom : fallback _bottom 0
|
|
local sma : fallback _sma SMALLSMOOTHA
|
|
local smb : fallback _smb SMALLSMOOTHB
|
|
local stroke : fallback _wide STROKE
|
|
local middle : fallback _middle [mix [left - stroke * CORRECTION_HX] right 0.5]
|
|
return : list {
|
|
flat left [top - sma - 2] [widths fine 0]
|
|
curl left [top - sma]
|
|
arcvh
|
|
g4 middle [top - O] [widths.heading 0 stroke RIGHTWARD]
|
|
archv
|
|
flat right [top - smb]
|
|
curl right bottom [heading DOWNWARD]
|
|
}
|
|
}
|
|
define [nShoulder left middle right fine _top _bottom _sma _smb _wide] : let [a arguments] : glyph-construction {
|
|
include : spiro : nShoulderKnots.apply null a
|
|
}
|
|
|
|
define [mShoulderSpiro left right top bottom width fine] : glyph-construction {
|
|
local fix : CORRECTION_VS * CORRECTION_HX * width / STROKE
|
|
include : spiro-outline {
|
|
corner [right - width * CORRECTION_HX] bottom
|
|
curl [right - width * CORRECTION_HX] [top - SMALLSMOOTH + fix]
|
|
arcvh 8 'no-tiny'
|
|
g2 [mix left [right - width * CORRECTION_HX] 0.5] [top - O - width]
|
|
archv 8 'no-tiny'
|
|
flat left [top - SMALLSMOOTH - fix]
|
|
corner left [top - SMALLSMOOTH - fix - 1]
|
|
corner [left - fine] [top - SMALLSMOOTH - 1]
|
|
curl [left - fine] [top - SMALLSMOOTH]
|
|
arcvh 8 'no-tiny'
|
|
g2 [mix [left - fine * CORRECTION_HX] right 0.5] [top - O]
|
|
archv 8 'no-tiny'
|
|
flat right [top - SMALLSMOOTH]
|
|
corner right bottom
|
|
close
|
|
}
|
|
}
|
|
|
|
define [XSHookUpper top left _middle right smooth hook _stroke] : glyph-construction {
|
|
local middle : fallback _middle [mix left right SBALANCE]
|
|
local stroke : fallback _stroke STROKE
|
|
include : create-stroke
|
|
:.set-transform globalTransform
|
|
:.start-from [right - OXHOOK] [top - hook]
|
|
:.set-width [if [left < right] stroke 0] [if [left < right] 0 stroke]
|
|
:.curve-to [mix middle right KAPPA_HOOK] [top - O] [middle - CORRECTION_OMIDS] [top - O]
|
|
:.arc-hv-to left [top - smooth]
|
|
}
|
|
define [sHookUpper top smooth hook _middle _stroke] : XSHookUpper top SB _middle RIGHTSB smooth hook _stroke
|
|
define [CHookUpper top smooth hook _middle _stroke] : XSHookUpper top [SB + O] _middle RIGHTSB smooth hook _stroke
|
|
define [twoHookUpper top smooth hook _middle _stroke] : XSHookUpper top RIGHTSB _middle SB smooth hook _stroke
|
|
define [XSHookLower bottom left _middle right smooth hook _stroke] : glyph-construction {
|
|
local middle : fallback _middle [mix left right SBALANCE]
|
|
local stroke : fallback _stroke STROKE
|
|
include : create-stroke
|
|
:.set-transform globalTransform
|
|
:.start-from right [bottom + smooth]
|
|
:.set-width [if [left < right] 0 stroke] [if [left < right] stroke 0]
|
|
:.arc-vh-to [middle + CORRECTION_OMIDS] [bottom + O]
|
|
:.curve-to [mix middle left KAPPA_HOOK] [bottom + O] [left + OXHOOK] [bottom + hook]
|
|
}
|
|
define [sHookLower bottom smooth hook _middle _stroke] : XSHookLower bottom SB _middle RIGHTSB smooth hook _stroke
|
|
define [EHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom [RIGHTSB - O + TAILADJX * globalTransform.yx] _middle [SB + [fallback _o O]] smooth [hook - TAILADJY * globalTransform.yx] _stroke
|
|
define [CHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom [RIGHTSB + TAILADJX * globalTransform.yx] _middle [SB + [fallback _o O]] smooth [hook - TAILADJY * globalTransform.yx] _stroke
|
|
define [RevEHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom SB _middle [RIGHTSB - [fallback _o O]] smooth hook _stroke
|
|
|
|
define [smallo u d l r _width _sma _smb] : 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 {
|
|
prepare : widths width 0
|
|
g4 [middle - mc] [u - O]
|
|
archv
|
|
flat [l + O] [u - sma]
|
|
curl [l + O] [d + smb]
|
|
arcvh
|
|
g4 [middle + mc] [d + O]
|
|
archv
|
|
flat [r - O] [d + sma]
|
|
curl [r - O] [u - smb]
|
|
arcvh
|
|
close
|
|
}
|
|
}
|
|
else : begin {
|
|
local ymiddlea : mix d u [smb / [sma + smb]]
|
|
local ymiddleb : mix d u [sma / [sma + smb]]
|
|
include : spiro {
|
|
prepare : widths width 0
|
|
g4 [middle - mc] [u - O]
|
|
archv
|
|
g4 [l + O] ymiddlea
|
|
arcvh
|
|
g4 [middle + mc] [d + O]
|
|
archv
|
|
g4 [r - O] ymiddleb
|
|
arcvh
|
|
close
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
define [HBar xleft xright y _fine] : glyph-construction {
|
|
local fine : [fallback _fine STROKE] / 2
|
|
include : create-stroke
|
|
:.set-transform globalTransform
|
|
:.start-from xleft y
|
|
:.heads-to RIGHTWARD
|
|
:.set-width fine fine
|
|
:.line-to xright y
|
|
:.heads-to RIGHTWARD
|
|
}
|
|
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] : HBar xleft xright y [adviceBlackness 4.5]
|
|
define [VBar x ydown yup _fine] : glyph-construction {
|
|
local fine : [fallback _fine STROKE] / 2
|
|
include : create-stroke
|
|
:.set-transform globalTransform
|
|
:.start-from x ydown
|
|
:.heads-to [if [ydown < yup] UPWARD DOWNWARD]
|
|
:.set-width fine fine
|
|
:.line-to x yup
|
|
:.heads-to [if [ydown < yup] UPWARD DOWNWARD]
|
|
}
|
|
define [VBarLeft x yd yu _fine] : VBar [x + [fallback _fine STROKE] * 0.5 * CORRECTION_HX] yd yu _fine
|
|
define [VBarRight x yd yu _fine] : VBar [x - [fallback _fine STROKE] * 0.5 * CORRECTION_HX] yd yu _fine
|
|
|
|
define [VerticalHook x y extend depth fine] : glyph-construction {
|
|
include : create-stroke
|
|
:.start-from x y
|
|
:.heads-to [if [depth > 0] DOWNWARD UPWARD]
|
|
:.set-width [[fallback fine STROKE] / 2] [[fallback fine STROKE] / 2]
|
|
:.arc-vh-to [x + extend] [y - depth]
|
|
}
|
|
define [LegShape xt xb xs top bottom _fine] : glyph-construction {
|
|
local fine : fallback _fine STROKE
|
|
include : spiro {
|
|
widths.lhs fine
|
|
flat xt top [heading DOWNWARD]
|
|
curl xb [bottom + LONGJUT]
|
|
alsothruthem ((0.5 0.94)) important
|
|
flat [xs + 1] [bottom + fine] [heading LEFTWARD]
|
|
curl xs [bottom + fine] [heading LEFTWARD]
|
|
}
|
|
}
|
|
define [LeftHook x y xextend] : glyph-construction {
|
|
local fine : adviceBlackness 4.25
|
|
include : spiro {
|
|
widths.lhs fine
|
|
flat [fallback xextend : x + 1] y
|
|
curl x y
|
|
archv
|
|
g4 [x - fine * 1.5] [y - HOOKX]
|
|
}
|
|
}
|
|
|
|
# Common 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
|
|
}
|
|
# Spiro shapes
|
|
define [sband sw rtl _tension _tangle _compression] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
|
local tension : fallback _tension 0.7
|
|
local compression : fallback _compression 1
|
|
local tensionw 0
|
|
local minangle : -para.italicangle / 180 * Math.PI
|
|
local maxangle : Math.atan2 [after.x - before.x] [[mix after.y before.y tension] - [mix before.y after.y tension]]
|
|
set maxangle : Math.atan2 [[Math.sin maxangle] * compression] [Math.cos maxangle]
|
|
local p : fallback _tangle 0.25
|
|
local pts ()
|
|
local samples 32
|
|
foreach j [range 1 samples] : begin {
|
|
local t : j / samples
|
|
local angle : mix minangle maxangle [bez3 0 p 1 1 : if [t < 1/2] [2 * t] [2 * [1 - t]]]
|
|
local k : bez3 0 tensionw [1 - tensionw] 1 t
|
|
if rtl : k = 1 - k
|
|
pts.push : g2 [mix before.x after.x [bez3 0 0 1 1 t]] [mix before.y after.y [bez3 0 tension [1 - tension] 1 t]] [widths.heading [[1 - k] * STROKE] [k * STROKE] (.x [Math.cos angle] .y [Math.sin angle])]
|
|
}
|
|
# throw 'w'
|
|
return pts
|
|
}])
|
|
define [hookstart y p f] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
|
local atBottom : after.y > y
|
|
local ltr : after.x > before.x
|
|
before.x = before.x - OXHOOK * [if ltr [-1] 1]
|
|
local hv : archv
|
|
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.53 [[after.y - y] / [before.y - y]]
|
|
local mx [[mix after.x before.x mixr] + [if atBottom 1 [-1]] * CORRECTION_OMIDS]
|
|
return : list {
|
|
g4 mx y f
|
|
hv.af.call this (.x mx .y y) after hv
|
|
}
|
|
}])
|
|
define [hookend y p f dontextend] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
|
local atBottom : before.y > y
|
|
local ltr : after.x > before.x
|
|
after.x = after.x + OXHOOK * [if ltr [-1] 1]
|
|
local vh : arcvh
|
|
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.525 [[before.y - y] / [after.y - y]]
|
|
local mx [[mix before.x after.x mixr] + [if atBottom 1 [-1]] * CORRECTION_OMIDS]
|
|
if [!dontextend && atBottom && ltr] : begin {
|
|
after.x = after.x + TAILADJX * globalTransform.yx
|
|
after.y = after.y - TAILADJY * globalTransform.yx
|
|
}
|
|
return : list {
|
|
vh.af.call this before (.x mx .y y) vh
|
|
g4 mx y f
|
|
}
|
|
}])
|
|
|
|
# Derived subfonts
|
|
define [Fork glyphs params] : begin {
|
|
local p : Object.create params
|
|
p.upmscale = 1
|
|
local shouldBuildList ()
|
|
foreach glyphid [items-of glyphs] : set shouldBuildList : shouldBuildList.concat (glyphid :: dependencyProfile.(glyphid))
|
|
local forkFont : buildFont p shouldBuildList
|
|
return forkFont.glyfMap
|
|
}
|
|
define [Miniature glyphs fold scale] : begin {
|
|
local forkedPara : Object.create para
|
|
forkedPara.stroke = [adviceBlackness fold] / scale
|
|
forkedPara.sb = SB / 2
|
|
return : Fork glyphs forkedPara
|
|
}
|
|
define [Thinner glyphs p] : begin {
|
|
local forkedPara : Object.create para
|
|
forkedPara.width = WIDTH * 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
|
|
return : Fork glyphs forkedPara
|
|
}
|
|
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]
|
|
if mark : include mark
|
|
include : FlipAround x y
|
|
}
|
|
define [dual newid unicode id spacing] : create-glyph [fallback newid : 'double' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id) AS_BASE
|
|
apply-transform : Translate [-spacing] 0
|
|
include glyphs.(id)
|
|
apply-transform : Translate [spacing / 2] 0
|
|
}
|
|
define [vdual newid unicode id spacing] : create-glyph [fallback newid : 'double' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include : create-glyph : glyph-construction {
|
|
include glyphs.(id)
|
|
apply-transform : Upright
|
|
}
|
|
apply-transform : Translate 0 [-spacing]
|
|
include : create-glyph : glyph-construction {
|
|
include glyphs.(id)
|
|
apply-transform : Upright
|
|
}
|
|
apply-transform : Translate 0 [spacing / 2]
|
|
apply-transform : Italify
|
|
}
|
|
define [fwl newid unicode id] : create-glyph [fallback newid : 'fwl' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width FULLWIDTH
|
|
}
|
|
define [fwr newid unicode id] : create-glyph [fallback newid : 'fwr' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width FULLWIDTH
|
|
apply-transform : Translate [FULLWIDTH - WIDTH] 0
|
|
}
|
|
define [dwl newid unicode id] : create-glyph [fallback newid : 'dwl' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width UPM
|
|
}
|
|
define [dwr newid unicode id] : create-glyph [fallback newid : 'dwr' + id] : glyph-construction {
|
|
if unicode : assign-unicode unicode
|
|
include glyphs.(id)
|
|
set-width UPM
|
|
apply-transform : Translate [UPM - WIDTH] 0
|
|
}
|
|
define [dwc newid unicode id] : 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] 0
|
|
} |