424 lines
15 KiB
Plaintext
424 lines
15 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 * CORRECTION_HX) 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 * CORRECTION_HX) 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 * CORRECTION_HX) 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 * CORRECTION_HX) 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 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 slope : 0.25 + globalTransform.yx
|
|
local middle : [mix (left - stroke * CORRECTION_HX) 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 left 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
|
|
local sm : SMALLSMOOTH * 0.85
|
|
include : spiro-outline
|
|
corner (right - width * CORRECTION_HX) bottom
|
|
curl (right - width * CORRECTION_HX) (top - sm + fix)
|
|
arcvh 8 'no-tiny'
|
|
g2 [mix left (right - width * CORRECTION_HX) 0.5] (top - O - width)
|
|
archv 8 'no-tiny'
|
|
flat left (top - sm - fix)
|
|
corner left (top - sm - fix - 1)
|
|
corner (left - fine) (top - sm - 1)
|
|
curl (left - fine) (top - sm)
|
|
arcvh 8 'no-tiny'
|
|
g2 [mix (left - fine * CORRECTION_HX) right 0.5] (top - O)
|
|
archv 8 'no-tiny'
|
|
flat right (top - sm)
|
|
corner right bottom
|
|
close
|
|
|
|
define [smallo 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
|
|
prepare : widths width 0
|
|
g4 (middle - mc) (u - O)
|
|
archv
|
|
[if ai flat.ai flat] (l + O) (u - sma)
|
|
[if ai curl.ai curl] (l + O) (d + smb)
|
|
arcvh
|
|
g4 (middle + mc) (d + O)
|
|
archv
|
|
[if ai flat.ai flat] (r - O) (d + sma)
|
|
[if ai curl.ai 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 OVERLAYSTROKE
|
|
define [VBar x ydown yup _fine] : glyph-construction
|
|
local fine : fallback _fine STROKE
|
|
include : spiro
|
|
widths.center fine
|
|
flat x ydown [heading [if (ydown < yup) UPWARD DOWNWARD]]
|
|
curl x yup [heading [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 : spiro
|
|
widths.center [fallback fine STROKE]
|
|
flat x y [heading [if (depth > 0) DOWNWARD UPWARD]]
|
|
curl x (y - [if (depth > 0) 0.01 (-0.01)]) [heading [if (depth > 0) DOWNWARD UPWARD]]
|
|
flat (x + extend - [if (extend > 0) 0.01 (-0.01)]) (y - depth)
|
|
curl (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
|
|
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.ess = para.ess * forkedPara.stroke / para.stroke
|
|
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
|