Iosevka/font-src/meta/aesthetics.ptl

317 lines
15 KiB
Text

import '../support/point' as Point
import '../support/transform' as Transform
import [mix linreg clamp fallback] from '../support/utils'
import '../support/anchor' as Anchor
# Parameter generation
export : define [calculateMetrics para] : begin
define UPM 1000
define HalfUPM : UPM / 2
# Key metrics
define Width : Math.round para.width
define SB para.sb
define CAP para.cap
define XH para.xheight
define Descender : fallback para.descender (XH - CAP)
define Contrast : fallback para.contrast 1
# Key metrics for symbols
define symbolMid : fallback para.symbolMid (XH * 0.65)
define parenTop : symbolMid + para.parenSize / 2
define parenBot : symbolMid - para.parenSize / 2
define operTop : symbolMid + para.operSize * (Width - SB * 2)
define operBot : symbolMid - para.operSize * (Width - SB * 2)
define tackTop : symbolMid + para.tackSize * (Width - SB * 2)
define tackBot : symbolMid - para.tackSize * (Width - SB * 2)
define plusTop : symbolMid + para.plusSize * (Width - SB * 2)
define plusBot : symbolMid - para.plusSize * (Width - SB * 2)
define pictTop : symbolMid + para.pictSize * (Width - SB * 2)
define pictBot : symbolMid - para.pictSize * (Width - SB * 2)
define bgopTop : symbolMid + para.bgopSize * (Width - SB * 2)
define bgopBot : symbolMid - para.bgopSize * (Width - SB * 2)
# Transform constructors
define [Italify angle shift] : begin
local slope [Math.tan ([fallback angle para.slantAngle] / 180 * Math.PI)]
return : new Transform 1 slope 0 1 [fallback shift : -slope * symbolMid] 0
define [Upright angle shift] [Italify angle shift :.inverse]
define [Scale sx sy] : new Transform sx 0 0 [fallback sy sx] 0 0
define [Translate x y] : new Transform 1 0 0 1 x y
define [Rotate angle] : new Transform [Math.cos angle] (-[Math.sin angle]) [Math.sin angle] [Math.cos angle] 0 0
define globalTransform : Italify para.slantAngle
define TanSlope globalTransform.yx
define SINSLANT : Math.sin (para.slantAngle / 180 * Math.PI)
define COSSLANT : Math.cos (para.slantAngle / 180 * Math.PI)
define HVContrast : Contrast * COSSLANT + SINSLANT * TanSlope
# Orient parameters
define Upward : new Point (-HVContrast) 0
define Downward : new Point HVContrast 0
define Rightward : new Point TanSlope 1
define Leftward : new Point (- TanSlope) (-1)
define [UpwardT] : new Point (-HVContrast) 0
define [DownwardT] : new Point HVContrast 0
define [RightwardT] : new Point this.gizmo.yx 1
define [LeftwardT] : new Point (- this.gizmo.yx) (-1)
# Style parameters
define O para.overshoot
define OX para.overshootx
define OXHook para.oxhook
define Hook para.hook
define AHook para.ahook
define SHook para.shook
define RHook para.rhook
define JHook para.jhook
define FHook para.fhook
define HookX para.hookx
define Smooth para.smooth
define SmallSmooth para.smallsmooth
define Stroke para.stroke
define DotSize : fallback para.dotsize Stroke
define PeriodSize : fallback para.periodsize DotSize
define HBarPos : designParameters.hBarPos - 0.09 * Stroke / CAP
define OverlayPos designParameters.overlayPos
define Jut para.jut
define LongJut para.longjut
define MidJutSide : Math.max Jut : mix (0.5 * Stroke * HVContrast) LongJut 0.5
define MidJutCenter : Math.max Jut : mix (0.5 * Stroke * HVContrast) LongJut 0.6
define VJut para.vjut
define Accent para.accent
define AccentX para.accentx
define CThin : fallback para.cthin 0.75
define CThinB : fallback para.cthinb 0.5
define SLAB para.slab
define TailAdjX : Width * 0.2
define TailAdjY : XH * 0.25
define LBalance : LongJut * 0.04
define IBalance : fallback para.ibalance (LongJut * 0.04)
define LBalance2 : LongJut * 0.14
define IBalance2 : fallback para.ibalance (LongJut * 0.14)
define JBalance : fallback para.jbalance 0
define JBalance2 : fallback para.jbalance2 (Stroke * 0.25 + LBalance)
define TBalance : fallback para.tbalance JBalance
define TBalance2 : fallback para.tbalance2 TBalance
define RBalance : fallback para.rbalance (JBalance * 0.3)
define RBalance2 : fallback para.rbalance2 0
define FBalance : fallback para.fbalance 0
define OneBalance : fallback para.onebalance 0
# derived metrics
define MONOSPACE : para.diversityM == 1 && para.diversityF == 1 && para.diversityI == 1 && para.diversityII == 1
define WideWidth0 : if MONOSPACE (Width * 2) UPM
define WideWidth1 : if (para.spacing >= 1) WideWidth0 Width
define WideWidth2 : if (para.spacing >= 2) WideWidth0 Width
define Ess : Stroke * [fallback para.essx Contrast]
define EssQuestion : Stroke * [fallback para.essxq Contrast]
define HalfStroke : Stroke / 2
define RightSB : Width - SB
define Middle : Width / 2
define CapMiddle : CAP / 2
define DotRadius : DotSize / 2
define PeriodRadius : PeriodSize / 2
define SideJut : Jut - HalfStroke * HVContrast
define [StrokeWidthBlend min max sw] : linreg 18 min 126 max [fallback sw Stroke]
define SmoothAdjust : StrokeWidthBlend 80 144
define [SmoothAOf smooth width] : smooth - TanSlope * SmoothAdjust / Width * width
define [SmoothBOf smooth width] : smooth + TanSlope * SmoothAdjust / Width * width
define SmoothA : Smooth - TanSlope * SmoothAdjust
define SmoothB : Smooth + TanSlope * SmoothAdjust
define SmallSmoothA : SmallSmooth - TanSlope * SmoothAdjust
define SmallSmoothB : SmallSmooth + TanSlope * SmoothAdjust
define CorrectionOMidX : TanSlope * 0.9 * [StrokeWidthBlend 1.3 0.9]
define CorrectionOMidS : Stroke * CorrectionOMidX
# Blackness parameters
# We will estimate blackness using lower-case 'e'
local DarknessMockWidth : if (Width < HalfUPM) (HalfUPM * [Math.pow (Width / HalfUPM) 0.5]) Width
local DarknessMockWidth2 : HalfUPM * [Math.pow (Width / HalfUPM) 0.5]
define [WHITENESS div] : begin
local w : DarknessMockWidth * [fallback div 1] - SB * 2
return : ((XH - Stroke * 3) * w * (1 / 3)) / (XH * w)
define [adviceBlackness crowdedness div mul] : begin
local gap : DarknessMockWidth * [fallback div 1] - SB * 2
local shrink : (1 - [WHITENESS 1]) / (crowdedness * HVContrast)
return : Math.min Stroke ([fallback mul 1] * gap * shrink)
define [adviceBlackness2 cowX cowY refH div] : Math.min
adviceBlackness cowX (refH / DarknessMockWidth2)
adviceBlackness cowY div
define [MVertStrokeD div] : adviceBlackness designParameters.lllcrowdedness div
define MVertStroke : MVertStrokeD 1
define OverlayStroke : adviceBlackness 3.75
define OperatorStroke : adviceBlackness 3.125
define GeometryStroke : adviceBlackness 4.5
define ShoulderFine : Math.min (Stroke * para.shoulderfineMin) [adviceBlackness 16]
define Superness : fallback para.superness 2
define [superXY x superness] : Math.pow (1 - [Math.pow x [fallback superness Superness]]) (1 / [fallback superness Superness])
define [adviceSSmooth y sign _stroke] : begin
# Handle with extreme care.
local stroke : fallback _stroke Stroke
local strokeFactor : stroke * [clamp 1 2 : linreg 126 1 137 1.025 stroke] * [clamp 0 1 : Math.pow (Width / HalfUPM) 0.5]
local widthFactor : RightSB - SB
local ss : y * 0.21 + 0.375 * strokeFactor + 0.035 * widthFactor
return : ss + sign * TanSlope * (SmoothAdjust + 0.75 * stroke)
define [adviceGlottalStopSmooth y sign] : begin
return : ((y - Stroke) * 0.24 + Stroke * 0.625) + sign * TanSlope * SmoothAdjust
define [shoulderMidSlope _fine _stroke _dir] : begin
local stroke : fallback _stroke Stroke
local fine : fallback _fine ShoulderFine
local dir : fallback _dir 1
return : 0.5 * HVContrast * (stroke - fine) / stroke + dir * TanSlope
return [object
UPM HalfUPM Width SB CAP XH Descender Contrast symbolMid parenTop parenBot operTop operBot
tackTop tackBot plusTop plusBot pictTop pictBot bgopTop bgopBot Italify Upright Scale
Translate Rotate globalTransform TanSlope HVContrast Upward Downward Rightward Leftward
UpwardT DownwardT LeftwardT RightwardT O OX OXHook Hook AHook SHook RHook JHook FHook HookX
Smooth SmallSmooth Stroke DotSize PeriodSize HBarPos OverlayPos
LongJut Jut VJut Accent AccentX CThin CThinB SLAB TailAdjX TailAdjY LBalance
IBalance LBalance2 IBalance2 JBalance JBalance2 TBalance TBalance2 RBalance RBalance2
FBalance OneBalance WideWidth0 WideWidth1 WideWidth2 Ess EssQuestion
HalfStroke RightSB Middle CapMiddle DotRadius PeriodRadius SideJut SmoothA
SmoothB SmallSmoothA SmallSmoothB CorrectionOMidX CorrectionOMidS compositeBaseAnchors
adviceBlackness adviceBlackness2 MVertStroke MVertStrokeD OverlayStroke OperatorStroke
GeometryStroke ShoulderFine Superness superXY adviceSSmooth adviceGlottalStopSmooth
shoulderMidSlope StrokeWidthBlend SmoothAOf SmoothBOf SmoothAdjust MidJutSide MidJutCenter]
export : define [setFontMetrics para metrics fm] : begin
define [object CAP Descender XH Width] metrics
# Metric metadata
# Note: we use 1000upm in design, and (1000 * upmsacle)upm in production, to avoid rounding error.
define asc : para.leading * CAP / (CAP - Descender)
define desc : para.leading * Descender / (CAP - Descender)
define descenderPad : fallback para.descenderPad 0
set fm.OS_2.xAvgCharWidth Width
set fm.head.unitsPerEm 1000
set fm.hhea.ascender asc
set fm.OS_2.usWinAscent (asc + [fallback para.winMetricAscenderPad 0])
set fm.OS_2.sTypoAscender asc
set fm.hhea.descender (Descender - descenderPad)
set fm.OS_2.usWinDescent ([Math.abs desc] + descenderPad + [fallback para.winMetricDescenderPad 0])
set fm.OS_2.sTypoDescender (desc - descenderPad)
set fm.hhea.lineGap (para.leading - asc + Descender)
set fm.OS_2.sTypoLineGap (para.leading - asc + desc)
set fm.OS_2.sxHeight XH
set fm.OS_2.sCapHeight CAP
set fm.post.italicAngle (0 - para.slantAngle)
export : define [compositeBaseAnchors] : begin
local h {.}
foreach a [items-of arguments] : foreach k [items-of [Object.keys a.baseAnchors]] : begin
set h.(k) : new Anchor a.baseAnchors.(k).x a.baseAnchors.(k).y a.baseAnchors.(k).type a.baseAnchors.(k).mbx a.baseAnchors.(k).mby
return {.baseAnchors h .isMarkSet true}
export : define [MarksetDiv p me] : begin
define width : p * me.Width
define middle : p * me.Middle
define rightSB : me.Width * p - me.SB
define [ta anchor] : return : new Anchor
* (anchor.x * me.globalTransform.xx + anchor.y * me.TanSlope + me.globalTransform.x)
* (anchor.x * me.globalTransform.xy + anchor.y * me.globalTransform.yy + me.globalTransform.y)
define markAboveLower {.baseAnchors {.above [ta : new Anchor middle me.XH ]}}
define markAboveOper {.baseAnchors {.above [ta : new Anchor middle me.operTop ]}}
define markAboveTack {.baseAnchors {.above [ta : new Anchor middle me.tackTop ]}}
define markAbovePlus {.baseAnchors {.above [ta : new Anchor middle me.plusTop ]}}
define markAboveCap {.baseAnchors {.above [ta : new Anchor middle me.CAP ]}}
define markBelowLower {.baseAnchors {.below [ta : new Anchor middle me.Descender ]}}
define markBelowTack {.baseAnchors {.below [ta : new Anchor middle me.tackBot ]}}
define markBelowOper {.baseAnchors {.below [ta : new Anchor middle me.operBot ]}}
define markBelowPlus {.baseAnchors {.below [ta : new Anchor middle me.plusBot ]}}
define markBelowZero {.baseAnchors {.below [ta : new Anchor middle 0 ]}}
define markToprightLower {.baseAnchors {.topright [ta : new Anchor rightSB me.XH ]}}
define markToprightCap {.baseAnchors {.topright [ta : new Anchor rightSB me.CAP ]}}
define markBottomrightLower {.baseAnchors {.bottomright [ta : new Anchor rightSB me.Descender ]}}
define markBottomrightZero {.baseAnchors {.bottomright [ta : new Anchor rightSB 0 ]}}
define markTieAbove {.baseAnchors {.tieAbove [ta : new Anchor width (me.XH + me.Accent * 1.38)]}}
define markTieBelow {.baseAnchors {.tieBelow [ta : new Anchor width me.Descender ]}}
define [buildStandardMarkSet] : begin
local a : compositeBaseAnchors.apply null arguments
set a.baseAnchors.overlay : new Anchor
* [mix a.baseAnchors.below.x a.baseAnchors.above.x me.OverlayPos]
* [mix a.baseAnchors.below.y a.baseAnchors.above.y me.OverlayPos]
set a.baseAnchors.slash : new Anchor
* [mix a.baseAnchors.below.x a.baseAnchors.above.x 0.5]
* [mix a.baseAnchors.below.y a.baseAnchors.above.y 0.5]
return a
return : object
capital : buildStandardMarkSet markAboveCap markBelowZero markToprightCap markBottomrightZero markTieAbove markTieBelow
b : buildStandardMarkSet markAboveCap markBelowZero markToprightCap markBottomrightZero markTieAbove markTieBelow
e : buildStandardMarkSet markAboveLower markBelowZero markToprightLower markBottomrightZero markTieAbove markTieBelow
oper : buildStandardMarkSet markAboveOper markBelowOper markToprightLower markBottomrightZero markTieAbove markTieBelow
tack : buildStandardMarkSet markAboveTack markBelowTack markToprightLower markBottomrightZero markTieAbove markTieBelow
plus : buildStandardMarkSet markAbovePlus markBelowPlus markToprightLower markBottomrightZero markTieAbove markTieBelow
p : buildStandardMarkSet markAboveLower markBelowLower markToprightLower markBottomrightLower markTieAbove markTieBelow
if : buildStandardMarkSet markAboveCap markBelowLower markToprightCap markBottomrightLower markTieAbove markTieBelow
export : define designParameters : object
# V shape
straightVShapeSbShrink 0.8
straightSmallYShapeSbShrink 0.8
#
equal_wideness 0.075
logic_narrow_shrink 0.75
GeometricLargeX : lambda [mw uw] : (mw + uw / 2) / mw
geometric_small_x (4 / 7)
arrow_size 0.45
# ()
parenOutside 0.2
parenInside 0.9
parenCurliness 0.7
parenOvershoot 0.0375
# []
bracketOutside 0.1
bracketInside 0.95
# {}
braceOutside 0.05
braceInside 0.95
braceCurlyM1 0.6
braceCurlyM2 0.45
braceOvershoot 0.02
# Crosdedness
lllcrowdedness (3 + 1 / 3)
# Bar position
hBarPos 0.525
eBarPos 0.5
fiveBarPos 0.64
overlayPos 0.52
fBarPos 0.91
gBarPos 0.42
upperEBarPos : lambda [slab] : if slab 0.52 0.53
export : define [GenDivFrame metrics] : lambda [_div _hPack _sbMul] : begin
local div : fallback _div 1
local hPack : Math.max 2 [fallback _hPack 0]
local sbMul : fallback _sbMul : Math.min 1 : (metrics.Width * div - hPack * [metrics.adviceBlackness hPack div]) / (2 * hPack * metrics.SB)
return : object
div div
width : metrics.Width * div
middle : metrics.Middle * div
sb : metrics.SB * sbMul
leftSB : metrics.SB * sbMul
rightSB : metrics.Width * div - metrics.SB * sbMul
mvs : metrics.MVertStrokeD div
markSet: MarksetDiv div metrics