import [Point] from "@iosevka/geometry/point"
import [Transform] from "@iosevka/geometry/transform"
import [Anchor] from "@iosevka/geometry/anchor"
import [mix linreg clamp fallback] from "@iosevka/util"

# Parameter generation
export : define [calculateMetrics para] : begin
	define UPM 1000
	define HalfUPM : UPM / 2

	# Key metrics
	define Width     : Math.round para.width
	define SB        : Math.round para.sb
	define CAP       : Math.round para.cap
	define XH        : Math.round para.xHeight
	define Ascender  : Math.round para.ascender
	define Descender : Math.round : fallback para.descender (XH - Ascender)

	# Key metrics for symbols
	define SymbolMid : Math.round para.symbolMid
	define halfParenSize : Math.ceil (para.parenSize / 2)
	define ParenTop : SymbolMid + halfParenSize
	define ParenBot : SymbolMid - halfParenSize

	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)
	define BgTkTop : SymbolMid + para.bgtkSize * (Width - SB * 2)
	define BgTkBot : SymbolMid - para.bgtkSize * (Width - SB * 2)

	define Contrast  : fallback para.contrast 1

	# Transform constructors
	define [Italify angle shift] : begin
		local slope : Math.tan : [fallback angle para.slopeAngle] / 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 [ApparentTranslate x y] : Translate (x + TanSlope * y) y
	define [Rotate angle] : new Transform [Math.cos angle] [Math.sin (-angle)] [Math.sin angle] [Math.cos angle] 0 0

	define GlobalTransform : Italify para.slopeAngle
	define TanSlope   GlobalTransform.xy
	define SinSlope : Math.sin : para.slopeAngle / 180 * Math.PI
	define CosSlope : Math.cos : para.slopeAngle / 180 * Math.PI
	define HVContrast : Contrast * CosSlope + SinSlope * TanSlope
	define [HSwToV sw] : sw * HVContrast
	define [VSwToH sw] : sw / HVContrast

	# Orient parameters
	define Upward    : new Point Point.Type.Corner (-HVContrast)  0
	define Downward  : new Point Point.Type.Corner (+HVContrast)  0
	define Rightward : new Point Point.Type.Corner   0          (+1)
	define Leftward  : new Point Point.Type.Corner   0          (-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 HookX para.hookx
	define TailX para.tailX
	define TailY para.tailY
	define ArchDepth para.archDepth
	define SmallArchDepth para.smallArchDepth

	# Weight Control
	define BaseFillRate : Math.min 0.95 : [HSwToV : 2 * para.stroke] / (Width - SB * 2)
	define WeightControlFactor : [Math.atanh BaseFillRate] / BaseFillRate
	define [StrokeWeightControlSigmoid x] : Math.tanh : WeightControlFactor * x

	define [AdviceStrokeInSpace availSpace contrast crowdedness mul] : begin
		local nonAdjustedFillRate : crowdedness * contrast * para.stroke / availSpace
		local adjustedFillRate : StrokeWeightControlSigmoid nonAdjustedFillRate
		local strokeWidthScalar : Math.min 1 : mul * adjustedFillRate / nonAdjustedFillRate
		return : para.stroke * strokeWidthScalar
	define [AdviceStroke crowdedness adws mul] : begin
		local spaceH : Width * [fallback adws 1] - SB * 2
		return : AdviceStrokeInSpace spaceH HVContrast crowdedness [fallback mul 1]
	define [AdviceStroke2 crwX crwY refH adws] : begin
		local spaceH : Width * [fallback adws 1] - SB * 2
		local spaceV   refH
		return : Math.min
			AdviceStrokeInSpace spaceH HVContrast crwX 1
			AdviceStrokeInSpace spaceV 1          crwY 1

	define Stroke : AdviceStroke 2
	define HalfStroke : Stroke / 2
	define QuarterStroke : Stroke / 4
	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 VJut para.vjut
	define LongVJut : fallback para.longvjut LongJut
	define MidJutSide   : Math.max Jut : mix [HSwToV HalfStroke] LongJut 0.5
	define MidJutCenter : Math.max Jut : mix [HSwToV HalfStroke] LongJut 0.6
	define AccentStackOffset para.accentStackOffset
	define AccentWidth       para.accentWidth
	define AccentClearance   para.accentClearance
	define AccentHeight      para.accentHeight

	define CThin  : fallback para.cthin  0.75
	define CThinB : fallback para.cthinb 0.50

	define SLAB para.slab

	define [IBalance  df] : df.adws * df.adws * [fallback para.ibalance (LongJut * 0.04)] # Serifed
	define [IBalance2 df] : df.adws * [fallback para.ibalance2 (LongJut * 0.14)]          # Hooky, Tailed
	define JBalance  : fallback para.jbalance  0
	define JBalance2 : fallback para.jbalance2 (LongJut * 0.04 + QuarterStroke)
	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 WideWidth0 : if para.isQuasiProportional UPM (Width * 2)
	define WideWidth1 : if (para.spacing >= 1) WideWidth0 Width
	define WideWidth2 : if (para.spacing >= 2) WideWidth0 Width
	define WideWidth3 : if (para.spacing >= 3) WideWidth0 Width
	define WideWidth4 : if (para.spacing >= 4) WideWidth0 Width

	define [NarrowUnicodeT wd] : function [u] : if (wd === Width) u null
	define [WideUnicodeT   wd] : function [u] : if (wd !== Width) u null

	define EssUpper    : Stroke * [fallback para.essRatioUpper    para.essRatio Contrast]
	define EssLower    : Stroke * [fallback para.essRatioLower    para.essRatio Contrast]
	define EssQuestion : Stroke * [fallback para.essRatioQuestion para.essRatio Contrast]
	define RightSB : Width - SB
	define Middle : Width / 2
	define DotRadius : DotSize / 2
	define PeriodRadius : PeriodSize / 2
	define SideJut : Jut - [HSwToV HalfStroke]
	define VJutStroke : AdviceStroke 3.5

	define DToothlessRise : Hook * 0.25 + Stroke / 16
	define DMBlend          0.80

	define [StrokeWidthBlend min max sw] : linreg para.canonicalStrokeWidthMin min para.canonicalStrokeWidthMax max [fallback sw Stroke]

	define SmoothAdjust : StrokeWidthBlend 80 144
	define [ArchDepthAOf archDepth width] : archDepth - TanSlope * SmoothAdjust / Width * width
	define [ArchDepthBOf archDepth width] : archDepth + TanSlope * SmoothAdjust / Width * width
	define [YSmoothMidR top bot _ada _adb] : begin
		local ada : fallback _ada ArchDepthA
		local adb : fallback _adb ArchDepthB
		local delta : (adb - ada) / 2
		local smOfSma : ada + delta
		local smOfSmb : adb - delta
		local yNotAdjusted : mix top bot : smOfSmb / (smOfSma + smOfSmb)
		return : yNotAdjusted - delta * [Math.min 1 : (top - bot) / (ada + adb)]
	set YSmoothMidR.cr : function [c r _ada _adb] : YSmoothMidR (c + r) (c - r) _ada _adb
	define [YSmoothMidL top bot _ada _adb] : begin
		local ada : fallback _ada ArchDepthA
		local adb : fallback _adb ArchDepthB
		local delta : (adb - ada) / 2
		local smOfSma : ada + delta
		local smOfSmb : adb - delta
		local yNotAdjusted : mix top bot : smOfSma / (smOfSma + smOfSmb)
		return : yNotAdjusted + delta * [Math.min 1 : (top - bot) / (ada + adb)]
	set YSmoothMidL.cr : function [c r _ada _adb] : YSmoothMidL (c + r) (c - r) _ada _adb

	define ArchDepthA : ArchDepth - TanSlope * SmoothAdjust
	define ArchDepthB : ArchDepth + TanSlope * SmoothAdjust
	define SmallArchDepthA : SmallArchDepth - TanSlope * SmoothAdjust
	define SmallArchDepthB : SmallArchDepth + TanSlope * SmoothAdjust

	define CorrectionOMidX : TanSlope * 0.9 * [StrokeWidthBlend 1.3 0.9]
	define CorrectionOMidS : Stroke * CorrectionOMidX

	define OverlayStroke  : AdviceStroke 3.75
	define OperatorStroke : AdviceStroke 2.75
	define GeometryStroke : AdviceStroke 4
	define ShoulderFine : Math.min (Stroke * para.shoulderFineMin) : AdviceStroke 24

	define [UnicodeWeightGrade n _scl _swRef] : begin
		define scl : fallback _scl 1
		define kw : 10 - scl - n / 200
		define [mulPow s] : (0.25 + s / 8) * [StrokeWidthBlend 2 1]
		define kMul : [Math.pow (n / 100) : mulPow scl] / [Math.pow 4 : mulPow 2]
		define kAdj : [fallback _swRef Stroke] / [AdviceStroke 6]
		return : kMul * kAdj * [AdviceStroke kw]

	define [AdviceGlottalStopArchDepth y sign] : begin
		return : ((y - Stroke) * 0.24 + Stroke * 0.625) + sign * TanSlope * SmoothAdjust

	define VERY-FAR : UPM * 16
	define TINY     :  1 / 128

	return [object
		DesignParameters UPM HalfUPM Width SB CAP XH Ascender Descender Contrast SymbolMid ParenTop
		ParenBot OperTop OperBot TackTop TackBot PlusTop PlusBot PictTop PictBot BgOpTop BgOpBot
		BgTkTop BgTkBot Italify Upright Scale Translate ApparentTranslate Rotate GlobalTransform
		TanSlope HVContrast Upward Downward Rightward Leftward O OX OXHook Hook AHook SHook RHook
		JHook HookX TailX TailY ArchDepth SmallArchDepth Stroke HalfStroke QuarterStroke DotSize
		PeriodSize HBarPos OverlayPos Jut VJut LongJut LongVJut VJutStroke AccentStackOffset
		AccentWidth AccentClearance AccentHeight CThin CThinB SLAB IBalance IBalance2 JBalance
		JBalance2 TBalance TBalance2 RBalance RBalance2 FBalance OneBalance WideWidth0 WideWidth1
		WideWidth2 WideWidth3 WideWidth4 EssUpper EssLower EssQuestion RightSB Middle DotRadius
		PeriodRadius ArchDepthA ArchDepthB SmallArchDepthA SmallArchDepthB CorrectionOMidX
		CorrectionOMidS compositeBaseAnchors AdviceStroke AdviceStroke2 AdviceStrokeInSpace
		OverlayStroke OperatorStroke GeometryStroke ShoulderFine UnicodeWeightGrade
		AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust SideJut
		MidJutSide MidJutCenter YSmoothMidR YSmoothMidL DToothlessRise DMBlend HSwToV VSwToH
		NarrowUnicodeT WideUnicodeT VERY-FAR TINY]

export : define [setFontMetrics para metrics fm] : begin
	define [object CAP Descender XH Width SymbolMid] metrics

	define leading      : Math.round para.leading
	define asc          : Math.round : SymbolMid + leading / 2
	define desc         : Math.round : SymbolMid - leading / 2

	define descenderPad : Math.round : fallback para.descenderPad 0
	define winMetricAscenderPad  : Math.round : fallback para.winMetricAscenderPad  0
	define winMetricDescenderPad : Math.round : fallback para.winMetricDescenderPad 0

	set fm.os2.xAvgCharWidth      Width
	set fm.head.unitsPerEm        1000
	set fm.hhea.ascender          asc
	set fm.os2.usWinAscent        (asc + winMetricAscenderPad)
	set fm.os2.sTypoAscender      asc

	set fm.hhea.descender         (Descender - descenderPad)
	set fm.os2.usWinDescent       ([Math.abs desc] + descenderPad + winMetricDescenderPad)
	set fm.os2.sTypoDescender     (desc - descenderPad)

	set fm.hhea.lineGap           (leading - asc + Descender)
	set fm.os2.sTypoLineGap       (leading - asc + desc)

	set fm.os2.sxHeight           XH
	set fm.os2.sCapHeight         CAP

	local slope : Math.tan para.slopeAngle
	set fm.post.italicAngle       : Math.round (0 - para.slopeAngle)
	set fm.hhea.caretSlopeRise    : if para.slopeAngle (1000)                      1
	set fm.hhea.caretSlopeRun     : if para.slopeAngle ((-slope) * 1000)           0
	set fm.hhea.caretOffset       : if para.slopeAngle ((-slope) * para.symbolMid) 0

	# Fixed metrics
	set fm.os2.yStrikeoutPosition    para."os2.yStrikeoutPosition"
	set fm.os2.yStrikeoutSize        para."os2.yStrikeoutSize"
	set fm.os2.ySubscriptXOffset     para."os2.ySubscriptXOffset"
	set fm.os2.ySubscriptXSize       para."os2.ySubscriptXSize"
	set fm.os2.ySubscriptYOffset     para."os2.ySubscriptYOffset"
	set fm.os2.ySubscriptYSize       para."os2.ySubscriptYSize"
	set fm.os2.ySuperscriptXOffset   para."os2.ySuperscriptXOffset"
	set fm.os2.ySuperscriptXSize     para."os2.ySuperscriptXSize"
	set fm.os2.ySuperscriptYOffset   para."os2.ySuperscriptYOffset"
	set fm.os2.ySuperscriptYSize     para."os2.ySuperscriptYSize"
	set fm.post.underlinePosition    para."post.underlinePosition"
	set fm.post.underlineThickness   para."post.underlineThickness"

export : define [copyFontMetrics fm1 fm2] : begin
	set fm2.os2.xAvgCharWidth      fm1.os2.xAvgCharWidth
	set fm2.head.unitsPerEm        fm1.head.unitsPerEm
	set fm2.hhea.ascender          fm1.hhea.ascender
	set fm2.os2.usWinAscent        fm1.os2.usWinAscent
	set fm2.os2.sTypoAscender      fm1.os2.sTypoAscender

	set fm2.hhea.descender         fm1.hhea.descender
	set fm2.os2.usWinDescent       fm1.os2.usWinDescent
	set fm2.os2.sTypoDescender     fm1.os2.sTypoDescender

	set fm2.hhea.lineGap           fm1.hhea.lineGap
	set fm2.os2.sTypoLineGap       fm1.os2.sTypoLineGap

	set fm2.os2.sxHeight           fm1.os2.sxHeight
	set fm2.os2.sCapHeight         fm1.os2.sCapHeight

	set fm2.post.italicAngle       fm1.post.italicAngle
	set fm2.hhea.caretSlopeRise    fm1.hhea.caretSlopeRise
	set fm2.hhea.caretSlopeRun     fm1.hhea.caretSlopeRun
	set fm2.hhea.caretOffset       fm1.hhea.caretOffset

	set fm2.os2.yStrikeoutPosition   fm1.os2.yStrikeoutPosition
	set fm2.os2.yStrikeoutSize       fm1.os2.yStrikeoutSize
	set fm2.os2.ySubscriptXOffset    fm1.os2.ySubscriptXOffset
	set fm2.os2.ySubscriptXSize      fm1.os2.ySubscriptXSize
	set fm2.os2.ySubscriptYOffset    fm1.os2.ySubscriptYOffset
	set fm2.os2.ySubscriptYSize      fm1.os2.ySubscriptYSize
	set fm2.os2.ySuperscriptXOffset  fm1.os2.ySuperscriptXOffset
	set fm2.os2.ySuperscriptXSize    fm1.os2.ySuperscriptXSize
	set fm2.os2.ySuperscriptYOffset  fm1.os2.ySuperscriptYOffset
	set fm2.os2.ySuperscriptYSize    fm1.os2.ySuperscriptYSize

	set fm2.post.underlinePosition   fm1.post.underlinePosition
	set fm2.post.underlineThickness  fm1.post.underlineThickness


class CMarkSet
	public [new markAnchors baseAnchors] : begin
		set this.markAnchors markAnchors
		set this.baseAnchors baseAnchors
	public [applyToGlyph g] : begin
		g.clearAnchors
		g.copyAnchors this

export : define [compositeBaseAnchors] : begin
	local baseAnchorSink {.}
	foreach a [items-of arguments] : foreach k [items-of [Object.keys a.baseAnchors]] : begin
		set baseAnchorSink.(k) : new Anchor a.baseAnchors.(k).x a.baseAnchors.(k).y a.baseAnchors.(k).type a.baseAnchors.(k).mbx a.baseAnchors.(k).mby
	return : new CMarkSet null baseAnchorSink

define [MarksetDiv p sbMul me] : begin
	define width : p * me.Width
	define middle : p * me.Middle
	define leftSB   me.SB
	define rightSB : me.Width * p - me.SB
	define [ta anchor] : return : new Anchor
		me.GlobalTransform.applyX anchor.x anchor.y
		me.GlobalTransform.applyY anchor.x anchor.y

	define [MarkAbove zone]        {.baseAnchors {.above       [ta : new Anchor middle  zone.top]}}
	define [MarkBelow zone]        {.baseAnchors {.below       [ta : new Anchor middle  zone.bot]}}
	define [MarkTopLeft zone]      {.baseAnchors {.topLeft     [ta : new Anchor leftSB  zone.top]}}
	define [MarkTopRight zone]     {.baseAnchors {.topRight    [ta : new Anchor rightSB zone.top]}}
	define [MarkBottomLeft zone]   {.baseAnchors {.bottomLeft  [ta : new Anchor leftSB  zone.bot]}}
	define [MarkBottomRight zone]  {.baseAnchors {.bottomRight [ta : new Anchor rightSB zone.bot]}}

	define markTieAbove            {.baseAnchors {.tieAbove    [ta : new Anchor width  (me.XH + me.AccentStackOffset * 1.38)]}}
	define markTieBelow            {.baseAnchors {.tieBelow    [ta : new Anchor width   me.Descender                        ]}}

	define [buildStandardMarkSet zone] : lambda [] : begin
		if (this && this.baseAnchors) : begin
			throw : new Error "A mark set is now a function. Please call it before inclusion"
		local a : compositeBaseAnchors
			MarkAbove       zone
			MarkBelow       zone
			MarkTopLeft     zone
			MarkTopRight    zone
			MarkBottomLeft  zone
			MarkBottomRight zone
			begin markTieAbove
			begin markTieBelow

		# Overlay on stems
		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]
		# Slash over entire letter
		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]
		# Horizontal or near-horizontal strike on letter counter or bowl
		set a.baseAnchors.strike : 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
		OfZone    buildStandardMarkSet
		capital : buildStandardMarkSet {.top me.CAP      .bot 0}
		b       : buildStandardMarkSet {.top me.Ascender .bot 0}
		e       : buildStandardMarkSet {.top me.XH       .bot 0}
		p       : buildStandardMarkSet {.top me.XH       .bot me.Descender}
		oper    : buildStandardMarkSet {.top me.OperTop  .bot me.OperBot}
		tack    : buildStandardMarkSet {.top me.TackTop  .bot me.TackBot}
		plus    : buildStandardMarkSet {.top me.PlusTop  .bot me.PlusBot}
		bp      : buildStandardMarkSet {.top me.Ascender .bot me.Descender}
		capDesc : buildStandardMarkSet {.top me.CAP      .bot me.Descender}

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_tiny_x           (1    / 7)
	geometric_very_small_x     (2.5  / 7)
	geometric_slightly_small_x (3.25 / 7)
	geometric_small_x          (4    / 7)
	geometric_medium_small_x   (4.75 / 7)
	geometric_medium_x         (5.5  / 7)
	arrow_size                 0.45
	# ()
	parenOutside               0.2
	parenOutsideSwAdj          0.2
	parenInside                0.9
	parenInsideSwAdj           0.35
	parenCurliness             0.7
	parenOvershoot             0.0375
	# []
	bracketOutside             0.2
	bracketOutsideSwAdj        0.2
	bracketInside              0.9
	# {}
	braceOutside               0.05
	braceInside                0.9
	braceCurlyM1               0.6
	braceCurlyM2               0.45
	braceOvershoot             0.02
	# Bar position
	hBarPos                    0.525
	eBarPos                    0.5
	fiveBarPos                 0.64
	overlayPos                 0.52
	fBarPosToXH                0.875
	gBarPos                    0.42
	upperEBarPos               0.52
	# Fine adjustments
	fbarStrokeAdj              0.25
	superness                  2.275
	tightHookSuperness         2.30
	# Serif creation
	serifShiftX                0.60
	# Square dot
	squareDotScalar            0.95

export : define [GenDivFrame metrics] : begin
	# Implementation class of a division frame, used to model a letter's core X-direction structure
	class CDivFrame
		# _adws: scale factor of advance width
		# _hPack: number of horizontal divisions
		# _sbMul: scale factor of sidebearings
		# _mvs: desired stroke width
		# _ox: overshoot correction
		public [new _adws _hPack _sbMul _mvs _ox] : begin
			local ox    : fallback _ox 0
			local adws  : fallback _adws 1
			local hPack : Math.max 1 [fallback _hPack 0]
			local mvs   : fallback _mvs
				if _hPack [metrics.AdviceStroke _hPack adws] metrics.Stroke
			local sbMul : fallback _sbMul
				Math.min 1 : (metrics.Width * adws - hPack * mvs) / (2 * hPack * metrics.SB)

			set this.params       : object adws hPack sbMul mvs ox
			set this.adws           adws
			set this.hPack          hPack
			set this.width        : metrics.Width * adws
			set this.middle       : metrics.Middle * adws
			set this.sb           : metrics.SB * sbMul
			set this.leftSB       : metrics.SB * sbMul
			set this.rightSB      : metrics.Width * adws - metrics.SB * sbMul
			set this.mvs            mvs
			set this.shoulderFine : metrics.ShoulderFine * (mvs / metrics.Stroke)
			set this.markSet      : MarksetDiv adws sbMul metrics

			# No-overshoot metrics -- used for arch depth calculation
			set this.ox                 ox
			set this.widthNoOvershoot : this.width - ox
			set this.divNoOvershoot   : this.widthNoOvershoot / metrics.Width

			set this.archDepth  : this.archDepthOf  metrics.ArchDepth mvs
			set this.archDepthA : this.archDepthAOf metrics.ArchDepth mvs
			set this.archDepthB : this.archDepthBOf metrics.ArchDepth mvs

			set this.smallArchDepth  : this.archDepthOf  metrics.SmallArchDepth mvs
			set this.smallArchDepthA : this.archDepthAOf metrics.SmallArchDepth mvs
			set this.smallArchDepthB : this.archDepthBOf metrics.SmallArchDepth mvs

		public [archDepthOf d _stroke] : begin
			return : Math.max (d * this.divNoOvershoot) (1.125 * [fallback _stroke this.mvs])
		public [archDepthAOf d _stroke] : begin
			return : metrics.ArchDepthAOf [this.archDepthOf d _stroke] this.widthNoOvershoot
		public [archDepthBOf d _stroke] : begin
			return : metrics.ArchDepthBOf [this.archDepthOf d _stroke] this.widthNoOvershoot

		public [slice _divisions _keeps _o] : begin
			local o : fallback _o 0
			local divisions : fallback _divisions this.hPack
			local keeps : fallback _keeps 2

			return : this.sliceFine divisions keeps ((keeps - 1) / (divisions - 1)) 0 o

		public [sliceFine strokes keeps pGap _extraGap _o] : begin
			local o : fallback _o 0
			local extraGap : fallback _extraGap 0

			local oneStroke : metrics.HVContrast * this.mvs
			local totalGap : this.rightSB - this.leftSB - strokes * oneStroke - 2 * o

			local subDfWidth : 2 * this.leftSB + 2 * o + totalGap * pGap + extraGap + oneStroke * keeps
			local subDfDiv : subDfWidth / metrics.Width

			return : new CDivFrame subDfDiv keeps (this.leftSB / metrics.SB) this.mvs o

		public [rest sub _hPack] : begin
			return : new CDivFrame ((this.width - sub.width) / metrics.Width) [fallback _hPack (this.hPack - sub.hPack + 1)] (this.leftSB / metrics.SB) this.mvs this.ox
		public [restCompact kKern sub _hPack] : begin
			local kern : kKern * ((this.width - this.rightSB) + sub.leftSB)
			return : new CDivFrame ((this.width - sub.width + kern) / metrics.Width) [fallback _hPack (this.hPack - sub.hPack + 1)] (this.leftSB / metrics.SB) this.mvs this.ox

		public [applyToGlyph g] : begin
			g.setWidth this.width
			set g.divFrameParams this.params
			return this

		public [adviceStroke c] : metrics.AdviceStroke c this.adws
		public [adviceStroke2 c d h] : metrics.AdviceStroke2 c d h this.adws

	# Factory function for CDivFrame
	define [F _adws _hPack _sbMul _mvs _ox] : begin
		return : new CDivFrame _adws _hPack _sbMul _mvs _ox
	set F.fromParams : lambda [params] : begin
		return : new CDivFrame params.adws params.hPack params.sbMul params.mvs params.ox
	return F
