###### Automatic builds
$$include '../meta/macros.ptl'

import [mix linreg clamp fallback] from "@iosevka/util"
import [getGrMesh AnyCvOrCherryPicking CvDecompose Joining hashCv IsCompositeOrLigature NLDAcuteVariant HBSCaronVariant] from "@iosevka/glyph/relation"
import [hashGeometry] from "@iosevka/geometry"
import [Transform] from "@iosevka/geometry/transform"
extern Map
extern Set

glyph-module

define DECOMPOSABLE       true
define NON-DECOMPOSABLE   false
define CENTERED           true
define NOT-CENTERED       false
define ALLOW-PROPORTIONAL true
define MONOSPACE-ONLY     false

glyph-block Autobuild-Enclosure-Shared : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives

	glyph-block-export CircNameNoCheck
	define [CircNameNoCheck unicode prefix parts suffix] : begin
		local baseName : prefix + '{' + unicode + '}{' + [parts.join '}{'] + '}'
		return : if suffix (baseName + "." + suffix) baseName

	glyph-block-export CircName
	define [CircName unicode prefix parts suffix] : begin
		local name : CircNameNoCheck unicode prefix parts suffix
		if [query-glyph name] : begin
			throw : new Error "Glyph exists : \(name)"
		return name

	glyph-block-export EnsureComponentGlyphT
	define [EnsureComponentGlyphT gnPart fnBuildup] : begin
		local rs : new Set
		return : DeriveMeshT { gnPart } AnyCvOrCherryPicking
			function [gns gr] : fnBuildup gns.0
			function [gniFrom gniTo] : begin
				[query-glyph gniFrom].tryBecomeMirrorOf [query-glyph gniTo] rs

	glyph-block-export getGlyphDefaultShift
	define [getGlyphDefaultShift bal baly g] : begin
		if (g && g.baseAnchors.above && g.baseAnchors.below) : begin
			if bal : return : CAP / 2 - [mix baly [mix g.baseAnchors.above.y g.baseAnchors.below.y 0.5] bal]
			: else : return : CAP / 2 - [mix g.baseAnchors.above.y g.baseAnchors.below.y 0.5]
		return 0

	glyph-block-export CollectJobs
	define [CollectJobs globallyDecomposable centered allowProportional prefix suffix demands] : begin
		local nonDecomposable       { }
		local decomposableJobs      { }
		local relApplications       { }
		local decomposableRelGlyphs : new Set
		foreach demand [items-of demands] : do
			local unicode    demand.0
			local parts      demand.1
			local restInfo : demand.slice 2
			local origJobGlyphGn : CircName unicode prefix parts suffix

			local demandDecomposable : para.enableCvSs && globallyDecomposable
			foreach part [items-of parts] : if [query-glyph part] : begin
				local g : query-glyph part
				local relatedGlyphs : AnyCvOrCherryPicking.query g
				foreach gr [items-of relatedGlyphs] : if [query-glyph : gr.get g] : begin
					# Multi-part enclosure, proportinal
					if (allowProportional && [query-glyph : gr.get g].advanceWidth != g.advanceWidth)
						set demandDecomposable false
					# Multi-part enclosure, different Y-offset
					if (centered && [getGlyphDefaultShift 0 0 : query-glyph : gr.get g] != [getGlyphDefaultShift 0 0 g])
						set demandDecomposable false

			local jobsOrig : if demandDecomposable decomposableJobs nonDecomposable
			jobsOrig.push { origJobGlyphGn unicode parts :: restInfo }

			if demandDecomposable
			: then : foreach part [items-of parts] : begin
				local mesh : getGrMesh { part } AnyCvOrCherryPicking query-glyph
				foreach {gr fromParts toParts} [items-of mesh] : foreach gn [items-of toParts]
					decomposableRelGlyphs.add gn
			: else : begin
				local mesh : getGrMesh parts AnyCvOrCherryPicking query-glyph
				foreach {gr fromParts toParts} [items-of mesh] : do
					local fromGn : CircNameNoCheck unicode prefix fromParts suffix
					local toGn   : CircName        unicode prefix toParts   suffix
					nonDecomposable.push { toGn null toParts :: restInfo }
					relApplications.push { gr fromGn toGn }

		return : object nonDecomposable decomposableJobs decomposableRelGlyphs relApplications

	glyph-block-export CreateDerivedFontFromJobs
	define [CreateDerivedFontFromJobs aj restGids fn] : begin
		define [object nonDecomposable decomposableJobs decomposableRelGlyphs] aj

		local pendingGlyphs : new Set restGids
		foreach gn decomposableRelGlyphs : pendingGlyphs.add gn
		foreach {gnf unicode parts} [items-of nonDecomposable] : foreach gn [items-of parts]
			pendingGlyphs.add gn
		foreach {gnf unicode parts} [items-of decomposableJobs] : foreach gn [items-of parts]
			pendingGlyphs.add gn

		return : fn : Array.from pendingGlyphs

	glyph-block-export applyRelations
	define [applyRelations relApplications] : begin
		local rs : new Set
		foreach {gr f t} [items-of relApplications] : begin
			if [query-glyph f] : begin
				gr.set [query-glyph f] t
				if [query-glyph t] : [query-glyph t].tryBecomeMirrorOf [query-glyph f] rs

glyph-block AutoBuild-Enclosure : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Fork Miniature MiniatureParaT
	glyph-block-import Autobuild-Enclosure-Shared : CircNameNoCheck CircName CollectJobs EnsureComponentGlyphT CreateDerivedFontFromJobs applyRelations getGlyphDefaultShift

	define circleWidthClasses {{'NWID' Width 0.12} {'WWID' WideWidth0 0.08}}
	define [AdjustDigitCount digits width] : Math.max 1 (digits * Width / width)
	define [EnclosureStrokeScale dscale digits width] : dscale / ([AdjustDigitCount digits width] ** 0.66)

	define enclosureInnerPartActualWidth : new Map

	define [GlyphNameInnerOf gniPrefix subGlyph mp actualWidth accumulatedTfm] : begin
		define nameParts : list mp actualWidth accumulatedTfm
			hashGeometry subGlyph.geometry
			hashCv subGlyph
		return : '.ci.' + gniPrefix + '/' + [nameParts.join '/']

	define [EnsureInnerSubGlyphImpl inners markClass miniatureFont mp actualWidth accumulatedTfm] : function [gidPart] : begin
		define subGlyph : miniatureFont.queryByNameEnsured gidPart
		define gniPart : GlyphNameInnerOf inners.gniPrefix subGlyph mp actualWidth accumulatedTfm
		if [query-glyph gniPart] : return gniPart

		enclosureInnerPartActualWidth.set gniPart (actualWidth)
		create-glyph gniPart : glyph-proc
			set-width 0
			set-mark-anchor 'compositeInner' 0 0
			include : inners.buildInnerShape subGlyph
			include accumulatedTfm
			include : inners.addAnchors mp markClass actualWidth
		return gniPart

	define [EnsureInnerSubGlyphSeq inners markClass miniatureFont job dimens yCompress kExtraYShift] : begin
		define { gn unicode parts w bal baly }      job
		define [object width mockInnerWidth dscale] dimens

		local totalWidth 0
		local firstDerivedGyph null
		foreach [gidPart : items-of parts] : do
			local derivedGlyph : miniatureFont.queryByNameEnsured gidPart
			if [not firstDerivedGyph] : set firstDerivedGyph derivedGlyph
			set totalWidth : totalWidth + derivedGlyph.advanceWidth
		local xCompress : inners.getXScalar parts.length markClass mockInnerWidth totalWidth
		set totalWidth : Math.min mockInnerWidth totalWidth

		local shift : inners.getShift bal baly firstDerivedGyph
		local accumulatedTfm : Transform.Combine
			firstDerivedGyph.gizmo.inverse
			Scale (dscale * xCompress) (dscale * yCompress)
			Translate 0 (dscale * shift + SymbolMid + (kExtraYShift - 0.5) * CAP * dscale)
			begin firstDerivedGyph.gizmo

		local finalParts {}
		foreach partIndex [range 0 parts.length] : do
			local gidPart parts.(partIndex)
			local actualWidth : [miniatureFont.queryByNameEnsured gidPart].advanceWidth * dscale * xCompress
			finalParts.push : EnsureComponentGlyphT gidPart
				EnsureInnerSubGlyphImpl inners markClass miniatureFont (parts.length > 1) actualWidth accumulatedTfm

		return finalParts

	define [EnclosureInnerImpl dimens finalParts] : glyph-proc
		define [object width] dimens

		local totalInnerWidth 0
		foreach [gniPart : items-of finalParts] : begin
			set totalInnerWidth : totalInnerWidth + ([enclosureInnerPartActualWidth.get gniPart] || 0)
		local x : 0.5 * width - 0.5 * totalInnerWidth
		foreach [gniPart : items-of finalParts] : begin
			include : with-transform [Translate x 0] : refer-glyph gniPart
			set x : x + ([enclosureInnerPartActualWidth.get gniPart] || 0)

	define [EnclosureInner dimens inners miniatureFont job] : glyph-proc
		define { gn unicode parts w bal baly }      job
		define [object width] dimens

		local finalParts : EnsureInnerSubGlyphSeq inners 'enclosureInner' miniatureFont job dimens 1 0

		include : new-glyph : EnclosureInnerImpl dimens finalParts
		return finalParts

	define [TwoRowEnclosureInner dimens inners miniatureFont job] : glyph-proc
		define { gn unicode parts w bal baly }      job
		define [object width] dimens
		local jobFirstHalf  { gn unicode [parts.slice 0 (parts.length / 2)] w bal baly }
		local jobSecondHalf { gn unicode [parts.slice (parts.length / 2)  ] w bal baly }
		local finalPartsFirstHalf  : EnsureInnerSubGlyphSeq inners "enclosureInnerFirstHalf"  miniatureFont jobFirstHalf  dimens 0.55 (+0.55)
		local finalPartsSecondHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerSecondHalf" miniatureFont jobSecondHalf dimens 0.55 (-0.10)

		return : {}.concat finalPartsFirstHalf finalPartsSecondHalf

	define [PlayingCardInner dimens inners miniatureFont job] : glyph-proc
		define { gn unicode parts w bal baly }      job
		define [object width] dimens
		local jobFirstHalf  { gn unicode [parts.slice 0 (parts.length / 2)] w bal baly }
		local jobSecondHalf { gn unicode [parts.slice (parts.length / 2)  ] w bal baly }

		local finalPartsFirstHalf  : EnsureInnerSubGlyphSeq inners "enclosureInnerFirstHalf"  miniatureFont jobFirstHalf  dimens 0.6 (+0.55)
		local finalPartsSecondHalf : EnsureInnerSubGlyphSeq inners "enclosureInnerSecondHalf" miniatureFont jobSecondHalf dimens 0.6 (-0.15)

		return : {}.concat finalPartsFirstHalf finalPartsSecondHalf

	define [CircCrowd digits width] : 2 + 2 * ([AdjustDigitCount digits width] ** (2 / 3)) * [Math.max 1 (HalfUPM / Width)]
	define [CircScale digits width] : 0.65  / ([AdjustDigitCount digits width] ** (1 / 2))

	define [CircleDimens digits w m] : begin
		define width : fallback w Width
		define dscale :  linreg HalfUPM 0.55 UPM 0.6  width
		define spatt  : [linreg HalfUPM 0.22 UPM 0.27 width] * (Width / HalfUPM)
		define sw0 : [EnclosureStrokeScale dscale digits width] * [AdviceStroke : CircCrowd digits width] / [CircScale digits width]
		define sw : Math.max sw0 [fallback m 0]
		define top : SymbolMid + CAP * dscale / 2 + (CAP * spatt)
		define bot : SymbolMid - CAP * dscale / 2 - (CAP * spatt)
		define mosaicLeft 0
		define mosaicRight width
		define mosaicBot fontMetrics.os2.sTypoDescender
		define mosaicTop fontMetrics.os2.sTypoAscender
		define left : Math.max
			SB + O * 3
			Math.min
				width / 2 - (top - bot) / 2
				width / 2 - CAP / 2 * dscale - sw * 2.5
		define right : Math.min
			width - SB - O * 3
			Math.max
				width / 2 + (top - bot) / 2
				width / 2 + CAP / 2 * dscale + sw * 2.5
		define mockInnerWidth : width + 2 * (Stroke - sw) * dscale
		define archDepthA : ArchDepthAOf (SmallArchDepth * (right - left) / (RightSB - SB)) width
		define archDepthB : ArchDepthBOf (SmallArchDepth * (right - left) / (RightSB - SB)) width
		return : object width mockInnerWidth dscale sw0 sw top bot left right mosaicTop mosaicBot mosaicLeft mosaicRight archDepthA archDepthB

	define StandardInners : object
		gniPrefix  ''
		buildInnerShape : function [subGlyph] : return subGlyph
		getXScalar : function [nParts markClass mockInnerWidth totalWidth] : begin
			Math.min 1 (mockInnerWidth / totalWidth)
		getShift getGlyphDefaultShift
		getPara : function [pp digits rows width] : MiniatureParaT pp
			crowd      -- [CircCrowd (digits / rows) width]
			scale      -- [CircScale (digits / rows) width]
			sbscale    -- 1
			mono       -- (digits > 1)
			mono2      -- (digits > 1)
		addAnchors : function [fMultiPart markClass actualWidth] : glyph-proc
			if fMultiPart
			: then : set-mark-anchor markClass 0 0 (actualWidth) 0
			: else : set-mark-anchor markClass (actualWidth / 2) 0

	define PlayingCardInners : object
		gniPrefix  'pk'
		buildInnerShape StandardInners.buildInnerShape
		getPara         StandardInners.getPara
		getShift : function [] : return 0
		getXScalar : function [nParts markClass] : begin
			if (nParts > 1 && markClass === 'enclosureInnerFirstHalf')
			: then : return 0.5
			: else : return 0.6
		addAnchors : function [fMultiPart markClass actualWidth] : glyph-proc
			if (markClass === 'enclosureInnerFirstHalf')
			: then : set-mark-anchor markClass 0 0 actualWidth 0 # left-to-right
			: else : set-mark-anchor markClass actualWidth 0 0 0 # right-to-left

	define DecomposableInsetInners : object
		gniPrefix  'd'
		getShift        StandardInners.getShift
		addAnchors      StandardInners.addAnchors
		getXScalar      StandardInners.getXScalar
		buildInnerShape : function [subGlyph] : difference
			Rect (1.05 * CAP - O) (-0.05 * CAP + O) O (Width - O)
			begin subGlyph
		getPara : function [pp digits rows width] : MiniatureParaT pp
			crowd      -- [CircCrowd (digits / rows) width]
			scale      -- [CircScale (digits / rows) width]
			sbscale    -- 1
			mono       -- true
			mono2      -- true

	define ItalicInners : object
		gniPrefix 'i'
		getShift        StandardInners.getShift
		buildInnerShape StandardInners.buildInnerShape
		addAnchors      StandardInners.addAnchors
		getXScalar      StandardInners.getXScalar
		getPara : function [pp digits rows width] : begin
			define pp1 : pp.createFork : function [a] : begin
				set a.shape.slope 'italic'
				set a.shape.slopeAngle : mix (para.slopeAngle || 0) 15 (95 / 150)
			return : StandardInners.getPara pp1 digits rows width

	define [EnclosureT prefix builder inners digits rows demands fnEnclosure] : begin
		foreach {suffix ww gap} [items-of circleWidthClasses] : do
			define allowProportional : if (digits > 1) MONOSPACE-ONLY ALLOW-PROPORTIONAL
			define jobs : CollectJobs builder.decomposable CENTERED allowProportional (prefix + digits) suffix demands
			define forkedPara : inners.getPara para digits rows ww
			define miniatureFont : CreateDerivedFontFromJobs jobs {} : function [gs] : Fork gs forkedPara
			define gnEnclosure : CircName null (prefix + digits + '.enclosure') {} suffix

			define [buildImpl job decomposable] : begin
				define { gn unicode parts w bal baly } job
				if [query-glyph gn] : return nothing
				create-glyph gn [if (w == ww) unicode null] : glyph-proc
					define dimens : CircleDimens digits ww
					set-width dimens.width
					include : builder.buildGlyph dimens inners miniatureFont decomposable job gnEnclosure
						# if decomposable gnEnclosure null

			if [not : query-glyph gnEnclosure] : create-glyph gnEnclosure : fnEnclosure digits ww gap
			foreach job [items-of jobs.decomposableJobs] : buildImpl job true
			foreach job [items-of jobs.nonDecomposable] : buildImpl job false
			applyRelations jobs.relApplications

	# Builders and Enclosure Shapes
	define CircledBuilder : object
		decomposable true
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
			include : refer-glyph gnEnclosure
			local parts : include : EnclosureInner dimens inners miniatureFont job
			if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]

	define DecomposableInsetBuilder : object
		decomposable true
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
			include : CircledBuilder.buildGlyph dimens inners miniatureFont decomp job gnEnclosure
			include : radicalize

	define TwoRowBoxedBuilder : object
		decomposable true
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
			include [refer-glyph gnEnclosure] AS_BASE ALSO_METRICS
			local parts : include : TwoRowEnclosureInner dimens inners miniatureFont job
			foreach [part : items-of parts] : include : refer-glyph part
			if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]

	define PlayingCardBuilder : object
		decomposable true
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : glyph-proc
			include [refer-glyph gnEnclosure] AS_BASE ALSO_METRICS
			local parts : include : PlayingCardInner dimens inners miniatureFont job
			foreach [part : items-of parts] : include : refer-glyph part
			if decomp : CvDecompose.set currentGlyph [{gnEnclosure}.concat parts]

	define InsetBuilder : object
		decomposable false
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : difference
			refer-glyph gnEnclosure
			EnclosureInner dimens inners miniatureFont job

	define InsetWithGapBuilder : object
		decomposable false
		buildGlyph : function [dimens inners miniatureFont decomp job gnEnclosure] : begin
			define [object top bot left right] dimens
			local gap : Math.max [AdviceStroke 6] (Width * 0.08)
			local [inner] : EnclosureInner dimens inners miniatureFont job
			return : difference
				intersection
					Rect top bot left right
					union
						refer-glyph gnEnclosure
						remove-holes [inner]
						with-outlined gap [inner]
				inner

	define [AddEnclosureMark digits dimens] : glyph-proc
		define [object width dscale mockInnerWidth] dimens
		if (digits > 1)
			set-base-anchor 'enclosureInner' (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0
			set-base-anchor 'enclosureInner' (0.5 * width) 0


	define [createCircledGlyphs digits demands]
		EnclosureT "circle" CircledBuilder StandardInners digits 1 demands CircleEnclosureShape
	define [createBackslashCircledGlyphs digits demands]
		EnclosureT "circle-slashed" CircledBuilder StandardInners digits 1 demands BackslashCircleEnclosureShape
	define [createItalicCircledGlyphs digits demands]
		EnclosureT "circle-italic" CircledBuilder ItalicInners digits 1 demands CircleEnclosureShape
	define [CircleEnclosureShape digits ww gap] : glyph-proc
		define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
		set-width width
		include : OShape top bot left right sw archDepthA archDepthB
		include : AddEnclosureMark digits : CircleDimens digits ww
	define [BackslashCircleEnclosureShape digits ww gap] : glyph-proc
		include : CircleEnclosureShape digits ww gap
		define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
		include : intersection
			OShapeOutline top bot left right sw archDepthA archDepthB
			dispiro
				flat 0     [mix bot top 0.77] [widths.center sw]
				curl width [mix bot top (1 - 0.77)]

	define [createBoxedGlyphs digits demands]
		EnclosureT 'boxed' CircledBuilder StandardInners digits 1 demands BoxEnclosureShape
	define [BoxEnclosureShape digits ww gap] : glyph-proc
		define [object width sw top bot left right] : CircleDimens digits ww
		set-width width
		include : union
			HBar.t left  right top sw
			HBar.b left  right bot sw
			VBar.l left  bot   top sw
			VBar.r right bot   top sw
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createTwoRowBoxedGlyphs digits demands]
		EnclosureT 'twoRowBoxed' TwoRowBoxedBuilder StandardInners digits 2 demands TwoRowBoxEnclosureShape
	define [TwoRowBoxEnclosureShape digits ww gap] : glyph-proc
		define [object width sw top bot left right] : CircleDimens digits ww
		set-width width
		include : union
			HBar.t left  right top sw
			HBar.b left  right bot sw
			VBar.l left  bot   top sw
			VBar.r right bot   top sw
		include : AddEnclosureMarkTwoLine digits : CircleDimens digits ww
	define [AddEnclosureMarkTwoLine digits dimens] : glyph-proc
		define [object width dscale mockInnerWidth] dimens
		set-base-anchor 'enclosureInnerFirstHalf'  (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0
		set-base-anchor 'enclosureInnerSecondHalf' (0.5 * width - 0.5 * dscale * [Math.min (Width * digits) mockInnerWidth]) 0

	define [createPlayingCardGlyphs digits demands]
		EnclosureT 'playingCard' PlayingCardBuilder PlayingCardInners digits 2 demands PlayingCardEnclosure.Shape
	define [createTrumpCardGlyphs digits demands]
		EnclosureT 'trumpCard' CircledBuilder StandardInners digits 1 demands PlayingCardEnclosure.TrumpShape
	define [createPlayingCardBackGlyphs digits demands]
		EnclosureT 'playingCardBack' InsetBuilder StandardInners digits 1 demands PlayingCardEnclosure.BackShape
	define PlayingCardEnclosure : namespace
		define [Gap dimens] : begin
			local [object left right sw] dimens
			return : Math.max ((right - left) / 16) (sw / 2)

		define [CornerRadius dimens] : begin
			define [object sw left right] dimens
			return : 1.5 * sw + [Gap dimens]

		define [BorderShape dimens kSw] : glyph-proc
			local [object width sw top bot left right] dimens
			local r : CornerRadius dimens
			include : dispiro
				widths.rhs (kSw * sw)
				curl (right - r) top [heading Rightward]
				archv
				flat right (top - r) [heading Downward]
				curl right (bot + r) [heading Downward]
				arcvh
				flat (right - r) bot [heading Leftward]
				curl (left + r) bot [heading Leftward]
				archv
				flat left (bot + r) [heading Upward]
				curl left (top - r) [heading Upward]
				arcvh
				flat (left + r) top [heading Rightward]
				close

		define [BackFillShape dimens] : glyph-proc
			local [object width sw top bot left right] dimens
			local gap : Gap dimens
			local rD : [CornerRadius dimens] - sw - gap
			local topD : top - sw - gap
			local botD : bot + sw + gap
			local leftD : left + sw + gap
			local rightD : right - sw - gap

			include : spiro-outline
				widths.rhs sw
				curl (rightD - rD) topD [heading Rightward]
				archv
				flat rightD (topD - rD) [heading Downward]
				curl rightD (botD + rD) [heading Downward]
				arcvh
				flat (rightD - rD) botD [heading Leftward]
				curl (leftD + rD) botD [heading Leftward]
				archv
				flat leftD (botD + rD) [heading Upward]
				curl leftD (topD - rD) [heading Upward]
				arcvh
				flat (leftD + rD) topD [heading Rightward]
				close

		define [TwoRowMarks dimens] : glyph-proc
			local [object left right sw] dimens
			local gap : Gap dimens
			set-base-anchor 'enclosureInnerFirstHalf'  (left + sw + gap)  0
			set-base-anchor 'enclosureInnerSecondHalf' (right - sw - gap) 0

		export : define [Shape digits ww] : glyph-proc
			local dimens : CircleDimens [Math.max digits 3] ww
			set-width dimens.width
			include : BorderShape dimens 1
			include : TwoRowMarks dimens

		export : define [TrumpShape digits ww] : glyph-proc
			local dimens : CircleDimens [Math.max digits 3] ww
			set-width dimens.width
			include : BorderShape dimens 1
			include : AddEnclosureMark digits : CircleDimens digits ww

		export : define [BackShape digits ww] : glyph-proc
			local dimens : CircleDimens [Math.max digits 3] ww
			set-width dimens.width
			include : BorderShape dimens 0.5
			include : BackFillShape dimens
			include : AddEnclosureMark digits : CircleDimens digits ww

	define [createDashedBoxedGlyphs digits demands]
		EnclosureT 'dashed-boxed' CircledBuilder StandardInners digits 1 demands DashedBoxEnclosureShape
	define [DashedBoxEnclosureShape digits ww cap] : glyph-proc
		define [object width sw top bot left right] : CircleDimens digits ww
		set-width width
		include : difference
			union
				HBar.t left  right top sw
				HBar.b left  right bot sw
				VBar.l left  bot   top sw
				VBar.r right bot   top sw
			union
				VBar.m [mix left right 0.25] bot top sw
				VBar.m [mix left right 0.50] bot top sw
				VBar.m [mix left right 0.75] bot top sw
				HBar.m left right [mix bot top 0.25] sw
				HBar.m left right [mix bot top 0.50] sw
				HBar.m left right [mix bot top 0.75] sw
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createInsetCircledGlyphs digits demands]
		EnclosureT 'inset-circle' InsetBuilder StandardInners digits 1 demands InsetCircleEnclosureShape
	define [InsetCircleEnclosureShape digits ww gap] : glyph-proc
		define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
		set-width width
		include : OShapeOutline top bot left right sw archDepthA archDepthB
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createInsetBoxedGlyphs digits demands]
		EnclosureT 'inset-boxed' InsetBuilder StandardInners digits 1 demands InsetBoxEnclosureShape
	define [InsetBoxEnclosureShape digits ww gap] : glyph-proc
		define [object width top bot left right] : CircleDimens digits ww
		set-width width
		include : Rect top bot left right
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createDecomposableInsetCircledGlyphs digits demands]
		EnclosureT 'inset-circle-decomp' DecomposableInsetBuilder DecomposableInsetInners digits 1 demands DecomposableInsetCircleEnclosureShape
	define [DecomposableInsetCircleEnclosureShape digits ww gap] : glyph-proc
		define [object width sw top bot left right archDepthA archDepthB] : CircleDimens digits ww
		set-width width
		include : difference
			OShapeOutline top bot left right sw archDepthA archDepthB
			DecomposableInsetKnockout digits ww
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createDecomposableInsetBoxedGlyphs digits demands]
		EnclosureT 'inset-boxed-decomp' DecomposableInsetBuilder DecomposableInsetInners digits 1 demands DecomposableInsetBoxEnclosureShape
	define [DecomposableInsetBoxEnclosureShape digits ww gap] : glyph-proc
		define [object width top bot left right] : CircleDimens digits ww
		set-width width
		include : difference
			Rect top bot left right
			DecomposableInsetKnockout digits ww
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [DecomposableInsetKnockout digits ww] : begin
		define [object top bot left right dscale mockInnerWidth] : CircleDimens digits ww
		local xMid : mix left right 0.5
		local yMid : mix bot top 0.5
		local halfHeight : CAP * 0.55 * dscale
		local halfWidth : [Math.min (digits * Width) mockInnerWidth] * 0.5 * dscale
		return : Rect (yMid + halfHeight) (yMid - halfHeight) (xMid - halfWidth) (xMid + halfWidth)

	define [createCrossInsetBoxedGlyphs digits demands]
		EnclosureT 'cross-inset-boxed' InsetWithGapBuilder StandardInners digits 1 demands CrossInsetSquareShape
	define [CrossInsetSquareShape digits ww gap] : glyph-proc
		define [object width sw top bot left right] : CircleDimens digits ww
		set-width width
		include : difference
			Rect top bot left right
			ExtLineCenter (-0.1) sw left bot right top
			ExtLineCenter (-0.1) sw right bot left top
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createInsetDiamondGlyphs digits demands]
		EnclosureT 'inset-diamond' InsetBuilder StandardInners digits 1 demands InsetDiamondEnclosureShape
	define [InsetDiamondEnclosureShape digits ww gap] : glyph-proc
		define [object width top bot left right] : CircleDimens digits ww
		set-width width
		include : spiro-outline
			corner (left + O)  [mix bot top 0.5]
			corner [mix left right 0.5] (bot + O)
			corner (right - O) [mix bot top 0.5]
			corner [mix left right 0.5] (top - O)
			close
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createInsetMosaicGlyphs digits demands]
		EnclosureT 'inset-mosaic' InsetBuilder StandardInners digits 1 demands InsetMosaicEnclosureShape
	define [InsetMosaicEnclosureShape digits ww gap] : glyph-proc
		define [object width mosaicTop mosaicBot mosaicLeft mosaicRight] : CircleDimens digits ww
		set-width width
		include : ForceUpright
		include : Rect mosaicTop mosaicBot mosaicLeft mosaicRight
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [createDoubleCircledGlyphs digits demands]
		EnclosureT 'double-circle' CircledBuilder StandardInners digits 1 demands DoubleCircledEnclosureShape
	define [DoubleCircledEnclosureShape digits ww gap] : glyph-proc
		define [object width sw0 sw top bot left right archDepthA archDepthB] : CircleDimens digits ww (ww * gap)
		set-width width
		define sw1 : Math.min sw0 (sw / 3)
		include : OShape top bot left right sw1 archDepthA archDepthB
		include : OShape
			top - sw + sw1
			bot + sw - sw1
			left + [HSwToV sw] - [HSwToV sw1]
			right - [HSwToV sw] + [HSwToV sw1]
			begin sw1
			archDepthA - sw + sw1
			archDepthB - sw + sw1
		include : AddEnclosureMark digits : CircleDimens digits ww

	define [BraceCrowd digits width] : 2.75 +  [AdjustDigitCount digits width]
	define [BraceScale digits width] : 0.65 / ([AdjustDigitCount digits width] ** (1 / 2))
	define [bracedDottedDimens digits width] : begin
		define dscale : linreg Width 0.55 UPM 0.65 width
		define pscale : linreg Width 0.6 UPM 0.75 width
		define sw0 : [EnclosureStrokeScale dscale digits width] * [AdviceStroke : BraceCrowd digits width] / [BraceScale digits width]
		define sw : Math.min Stroke sw0
		define l : Math.max (SB + O * 3) (width / 2 - [Math.max (Width * digits) CAP] / 2)
		define r : width - l
		define mockInnerWidth : width + 2 * (Stroke - sw) * dscale
		return : object width sw dscale pscale l r mockInnerWidth

	define [BracedT rawPrefix digits demands fnBraceShape] : foreach {suffix ww} [items-of circleWidthClasses] : do
		define prefix : rawPrefix + digits
		define jobs : CollectJobs DECOMPOSABLE CENTERED ALLOW-PROPORTIONAL prefix suffix demands
		define miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
			crowd   -- [BraceCrowd digits ww]
			scale   -- [BraceScale digits ww]
			sbscale -- 1

		define gnb : CircName prefix ('.braced-brace' + digits) {} suffix
		if [not : query-glyph gnb] : create-glyph gnb : fnBraceShape digits ww

		define [CreateGlyphImpl jobDecomposable job] : begin
			local {gn unicode parts w bal baly} job
			if [not : query-glyph gn] : create-glyph gn [if (w == ww) unicode null] : glyph-proc
				define dimens : bracedDottedDimens digits ww
				define [object width] dimens
				set-width width

				include : refer-glyph gnb
				local parts : include : EnclosureInner dimens StandardInners miniatureFont job
				if jobDecomposable : CvDecompose.set currentGlyph [{gnb}.concat parts]

		foreach job [items-of jobs.decomposableJobs] : CreateGlyphImpl true job
		foreach job [items-of jobs.nonDecomposable]  : CreateGlyphImpl false job
		applyRelations jobs.relApplications

	define [createBracedGlyphs digits demands] : BracedT 'braced' digits demands BraceShape
	define [BraceShape digits ww] : glyph-proc
		define [object width pscale sw l r] : bracedDottedDimens digits ww
		local s : TanSlope * SymbolMid / 2
		local p : 0.1 * [Math.sqrt : Math.min 1 (width / (digits * Width))]
		set-width width
		include : dispiro
			widths.lhs sw
			g4 ([mix l r p] - s) (ParenTop * pscale)
			g4.down.mid (l - s + O) (SymbolMid * pscale)
			g4 ([mix l r p] - s) (ParenBot * pscale)

		include : dispiro
			widths.rhs sw
			g4 ([mix r l p] + s) (ParenTop * pscale)
			g4.down.mid (r + s - O) (SymbolMid * pscale)
			g4 ([mix r l p] + s) (ParenBot * pscale)

		include : Ungizmo
		include : Translate 0 (SymbolMid - SymbolMid * pscale)
		include : Regizmo
		include : AddEnclosureMark digits : bracedDottedDimens digits ww

	define [createHexBracedGlyphs digits demands] : BracedT 'hex-braced' digits demands HexBracedShape
	define [HexBracedShape digits ww] : glyph-proc
		define [object width pscale sw l r] : bracedDottedDimens digits ww
		local s : TanSlope * SymbolMid / 2
		local p : (1 / 6) * [Math.sqrt : Math.min 1 (width / (digits * Width))]
		set-width width

		include : dispiro
			widths.lhs sw
			corner ([mix l r p] - s) (ParenTop * pscale)
			corner (l - s + O)       (ParenTop * pscale - p * (r - l))

		include : dispiro
			widths.lhs sw
			corner (l - s + O)       (ParenTop * pscale - p * (r - l))
			corner (l - s + O)       (ParenBot * pscale + p * (r - l))

		include : dispiro
			widths.lhs sw
			corner (l - s + O)      (ParenBot * pscale + p * (r - l))
			corner ([mix l r p] - s) (ParenBot * pscale)

		include : dispiro
			widths.rhs sw
			corner ([mix r l p] + s) (ParenTop * pscale)
			corner (r + s - O)       (ParenTop * pscale - p * (r - l))

		include : dispiro
			widths.rhs sw
			corner (r + s - O)       (ParenTop * pscale - p * (r - l))
			corner (r + s - O)       (ParenBot * pscale + p * (r - l))

		include : dispiro
			widths.rhs sw
			corner (r + s - O)      (ParenBot * pscale + p * (r - l))
			corner ([mix r l p] + s) (ParenBot * pscale)

		include : Ungizmo
		include : Translate 0 (SymbolMid - SymbolMid * pscale)
		include : Regizmo
		include : AddEnclosureMark digits : bracedDottedDimens digits ww

	define [DottedCrowd digits width] : 2 +  [AdjustDigitCount digits width]
	define [DottedScale digits width] : 1 / ([AdjustDigitCount digits width] ** (1 / 2))
	define [createDottedGlyphs digits demands] : begin
		foreach {suffix ww} [items-of circleWidthClasses] : do
			define jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL ('dotted' + digits) suffix demands

			local miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs]: Miniature gs
				crowd   -- [DottedCrowd digits ww]
				scale   -- [DottedScale digits ww]
				sbscale -- 1

			define [ensureDottedPartImpl item offset xCompress xTranslate] : lambda [gidPart] : begin
				define gniPart : '.dotted-inner.' + gidPart + '@' + [{ item digits offset xCompress xTranslate }.join '/']
				if [query-glyph gniPart] : return gniPart
				create-glyph gniPart : glyph-proc
					set-width 0
					set-mark-anchor 'compositeInner' 0 0
					include : miniatureFont.queryByNameEnsured gidPart
					include : Ungizmo
					include : Translate offset 0
					include : Scale xCompress 1
					include : Translate xTranslate 0
					include : Regizmo
				return gniPart

			define [createDottedGlyphImpl job jobDecomposable] : begin
				local {gn unicode partsWithDot w} job
				define [object width dscale pscale sw l r] : bracedDottedDimens 1 ww

				local totalWidth 0
				local offsets    { }
				foreach [j : range 0 partsWithDot.length] : begin
					local gidPart partsWithDot.(j)
					if j : set totalWidth : totalWidth - SB
					set offsets.(j) totalWidth
					set totalWidth : totalWidth + [miniatureFont.queryByNameEnsured gidPart].advanceWidth
				set totalWidth : totalWidth - SB
				local xCompress : if (totalWidth > width) (width / totalWidth) 1
				local xTranslate : [if (totalWidth > width) 0 (width / 2 - totalWidth / 2)] - width

				if [not : query-glyph gn] : create-glyph gn [if (w == ww) unicode null] : glyph-proc
					set-width width
					local ps {gnSpace}
					foreach [j : range 0 partsWithDot.length] : begin
						local gidPart partsWithDot.(j)
						local p : EnsureComponentGlyphT gidPart : ensureDottedPartImpl j offsets.(j) xCompress xTranslate
						include : refer-glyph p
						ps.push p
					include : Translate width 0
					if jobDecomposable : CvDecompose.set currentGlyph ps

			define gnSpace : '.dotted-space.' + [{ digits suffix }.join '/']
			if [not : query-glyph gnSpace] : create-glyph gnSpace : glyph-proc
				set-width ww

			foreach job [items-of jobs.nonDecomposable]  : createDottedGlyphImpl job false
			foreach job [items-of jobs.decomposableJobs] : createDottedGlyphImpl job true

			applyRelations jobs.relApplications

	# Circled & Braced
	define [digitGlyphNames j suffix] : begin
		local digitNumberToNameMap { 'zero' 'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine' }
		local digits : [String j].split '' :.map [function x (x - 0)]
		local names { }
		foreach digit [items-of digits] : begin
			names.push : digitNumberToNameMap.(digit) + [[fallback suffix digitNoSuffix] digit] + '.lnum'
		return names

	define [digitNoSuffix d] : return ''
	define [digitSansSerifSuffix d] : if ((d >= 1 && d <= 5) || d == 7) '/sansSerif' ''

	do "Single-digit circled"
		local compositions : list
			list 0xA9    {'C'}                       WideWidth2
			list 0x1F12F {'revC'}                    WideWidth2
			list 0x2117  {'P'}                       WideWidth2
			# list 0x267E  {'infty'}                   WideWidth1
			list 0x1F10E {'ccCcwArrow'}              WideWidth2
			list 0x1F16F {'ccHumanFigure'}           WideWidth2
			list 0x1F1AD {'M'}                       WideWidth2
			list 0x24EA  {'zero.lnum'}               WideWidth1
			list 0x1F10B {'zero.lnum'}               WideWidth1 # We don't have serifs for digit 0, so make an alias here
			list 0x1F10D {'zero.lnum/forceSlashed'}  WideWidth2
		foreach [j : range 1 till 9] : compositions.push : list (0x2460 + j - 1) [digitGlyphNames j] WideWidth1
		foreach [j : range 1 till 9] : compositions.push : list (0x2780 + j - 1) [digitGlyphNames j digitSansSerifSuffix] WideWidth1
		foreach [j : range 0 26] : compositions.push {(0x24B6 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		foreach [j : range 0 26] : compositions.push {(0x24D0 + j) {[glyphStore.queryNameByUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)}
		createCircledGlyphs 1 compositions

	do "Single-digit backslash-circled"
		createBackslashCircledGlyphs 1 : list
			list 0x1F10F {'dollar'} WideWidth2
			list 0x1F16E {'C'}      WideWidth2

	do "Single-digit italic circled"
		createItalicCircledGlyphs 1 : list
			list 0x1F12B {'C'} WideWidth1
			list 0x1F12C {'R'} WideWidth1

	do "Double-digit circled"
		local compositions : list
			list null    {'sp1'} WideWidth1
			list 0x2789  {'one/sansSerif.lnum' 'zero.lnum'} WideWidth1
			list 0x1F16D {'C' 'C'} WideWidth2
			list 0x1F12D {'C' 'D'} WideWidth1
			list 0x1F12E {'W' 'smcpZ'} WideWidth1
		foreach [j : range 10 till 20] : compositions.push : list (0x2460 + j - 1)  [digitGlyphNames j] WideWidth1
		foreach [j : range 21 till 35] : compositions.push : list (0x3251 + j - 21) [digitGlyphNames j] WideWidth1
		foreach [j : range 36 till 50] : compositions.push : list (0x32B1 + j - 36) [digitGlyphNames j] WideWidth1
		createCircledGlyphs 2 compositions

	do "Single-letter inset circled"
		local compositions : list
		foreach [j : range 0 26] : compositions.push {(0x1F150 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		createInsetCircledGlyphs 1 compositions

	do "Single-digit inset circled"
		local compositions : list
			list 0x24FF  {'zero.lnum'} WideWidth1
			list 0x1F10C {'zero.lnum'} WideWidth1 # We don't have serifs for digit 0, so make an alias here
		foreach [j : range 1 till 9] : compositions.push : list (0x2776 + j - 1) [digitGlyphNames j] WideWidth1
		foreach [j : range 1 till 9] : compositions.push : list (0x278A + j - 1) [digitGlyphNames j digitSansSerifSuffix] WideWidth1
		createDecomposableInsetCircledGlyphs 1 compositions

	do "Double-digit inset circled"
		local compositions : list
			list 0x2793 { "one/sansSerif.lnum" "zero.lnum" } WideWidth1
		foreach [j : range 10 till 10] : compositions.push : list (0x2776 + j - 1) [digitGlyphNames j] WideWidth1
		foreach [j : range 11 till 20] : compositions.push : list (0x24EB + j - 11) [digitGlyphNames j] WideWidth1
		createDecomposableInsetCircledGlyphs 2 compositions

	do "Single-digit boxed"
		local compositions {}
		foreach [j : range 0 26] : compositions.push {(0x1F130 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		compositions.push : list 0x1F1A5 {'d'} WideWidth1
		createBoxedGlyphs 1 compositions

	do "Double-digit boxed"
		createBoxedGlyphs 2 : list
			list 0x1F14A {'H' 'V'} WideWidth1
			list 0x1F14B {'M' 'V'} WideWidth1
			list 0x1F14C {'S' 'D'} WideWidth1
			list 0x1F14D {'S' 'S'} WideWidth1
			list 0x1F14F {'W' 'C'} WideWidth1
			list 0x1F191 {'C' 'L'} WideWidth1
			list 0x1F194 {'I' 'D'} WideWidth1
			list 0x1F196 {'N' 'G'} WideWidth1
			list 0x1F197 {'O' 'K'} WideWidth1
			list 0x1F19A {'V' 'S'} WideWidth1
			list 0x1F19B {'three.lnum' 'D'} WideWidth1
			list 0x1F19D {'two.lnum' 'K'} WideWidth1
			list 0x1F19E {'four.lnum' 'K'} WideWidth1
			list 0x1F19F {'eight.lnum' 'K'} WideWidth1
			list 0x1F1A6 {'H' 'C'} WideWidth1

	do "Triple-digit boxed"
		createBoxedGlyphs 3 : list
			list 0x1F14E {'P' 'P' 'V'} WideWidth1
			list 0x1F195 {'N' 'E' 'W'} WideWidth1
			list 0x1F198 {'S' 'O' 'S'} WideWidth1
			list 0x1F199 {'U' 'P' 'exclam'} WideWidth1
			list 0x1F1A0 {'five.lnum' 'period' 'one.lnum'} WideWidth1
			list 0x1F1A1 {'seven.lnum' 'period' 'one.lnum'} WideWidth1
			list 0x1F1A3 {'six.lnum' 'zero.lnum' 'P'} WideWidth1
			list 0x1F1A7 {'H' 'D' 'R'} WideWidth1
			list 0x1F1AA {'S' 'H' 'V'} WideWidth1
			list 0x1F1AB {'U' 'H' 'D'} WideWidth1
			list 0x1F1AC {'V' 'O' 'D'} WideWidth1

	do "Quadruple-digit boxed"
		createBoxedGlyphs 4 : list
			list 0x1F192 {'C' 'O' 'O' 'L'} WideWidth1
			list 0x1F193 {'F' 'R' 'E' 'E'} WideWidth1
			list 0x1F1A2 {'two.lnum' 'two.lnum' 'period' 'two.lnum'} WideWidth1
			list 0x1F1A4 {'one.lnum' 'two.lnum' 'zero.lnum' 'P'} WideWidth1

	do "Triple-digit two-row boxed"
		createTwoRowBoxedGlyphs 3 : list
			list 0x1F19C { 'two.lnum' 'N' 'D' 'S' 'C' 'R' } WideWidth1
			list 0x1F1A8 { 'H' 'I' 'hyphen' 'R' 'E' 'S' } WideWidth1

	do "Quadruple-digit two-row boxed"
		createTwoRowBoxedGlyphs 4 : list
			list 0x1F1A9 { 'L' 'O' 'S' 'S' 'L' 'E' 'S' 'S' } WideWidth1

	do "Playing cards"
		# Here we always construct the two-digit cards to ensure that all digit and suit glyphs
		# are aligned across all cards.
		local compositions : list
			list 0x1F0A1 { 'A'             'sp1'       'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0AB { 'J/noDescend'   'sp1'       'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0AC { 'C'             'sp1'       'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0AD { 'Q'             'sp1'       'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0AE { 'K'             'sp1'       'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0B1 { 'A'             'sp1'       'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0BB { 'J/noDescend'   'sp1'       'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0BC { 'C'             'sp1'       'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0BD { 'Q'             'sp1'       'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0BE { 'K'             'sp1'       'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0C1 { 'A'             'sp1'       'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0CB { 'J/noDescend'   'sp1'       'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0CC { 'C'             'sp1'       'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0CD { 'Q'             'sp1'       'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0CE { 'K'             'sp1'       'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0D1 { 'A'             'sp1'       'clubSuit'         'zwsp' } WideWidth4
			list 0x1F0DB { 'J/noDescend'   'sp1'       'clubSuit'         'zwsp' } WideWidth4
			list 0x1F0DC { 'C'             'sp1'       'clubSuit'         'zwsp' } WideWidth4
			list 0x1F0DD { 'Q'             'sp1'       'clubSuit'         'zwsp' } WideWidth4
			list 0x1F0DE { 'K'             'sp1'       'clubSuit'         'zwsp' } WideWidth4
			list 0x1F0AA { 'one.lnum'      'zero.lnum' 'spadeSuit'        'zwsp' } WideWidth4
			list 0x1F0BA { 'one.lnum'      'zero.lnum' 'whiteHeartSuit'   'zwsp' } WideWidth4
			list 0x1F0CA { 'one.lnum'      'zero.lnum' 'whiteDiamondSuit' 'zwsp' } WideWidth4
			list 0x1F0DA { 'one.lnum'      'zero.lnum' 'clubSuit'         'zwsp' } WideWidth4
		foreach [j : range 2 till 9] : begin
			compositions.push : list (0x1F0A0 + j) [[digitGlyphNames j].concat {'sp1' 'spadeSuit'        'zwsp'}] WideWidth4
			compositions.push : list (0x1F0B0 + j) [[digitGlyphNames j].concat {'sp1' 'whiteHeartSuit'   'zwsp'}] WideWidth4
			compositions.push : list (0x1F0C0 + j) [[digitGlyphNames j].concat {'sp1' 'whiteDiamondSuit' 'zwsp'}] WideWidth4
			compositions.push : list (0x1F0D0 + j) [[digitGlyphNames j].concat {'sp1' 'clubSuit'         'zwsp'}] WideWidth4
		createPlayingCardGlyphs 2 compositions

	do "Single-digit trump cards"
		createTrumpCardGlyphs 1 : list
			list 0x1F0BF {'vShadeStar.NWID'} WideWidth4
			list 0x1F0CF {'blackStar.NWID'} WideWidth4
			list 0x1F0DF {'whiteStar.NWID'} WideWidth4
			list 0x1F0E0 {'zero.lnum/forceUnslashed'} WideWidth4
			list 0x1F0E1 {'I'} WideWidth4
			list 0x1F0E5 {'V'} WideWidth4
			list 0x1F0EA {'X'} WideWidth4

	do "Double-digit trump cards"
		createTrumpCardGlyphs 2 : list
			list 0x1F0E2 {'I' 'I'} WideWidth4
			list 0x1F0E4 {'I' 'V'} WideWidth4
			list 0x1F0E6 {'V' 'I'} WideWidth4
			list 0x1F0E9 {'I' 'X'} WideWidth4
			list 0x1F0EB {'X' 'I'} WideWidth4
			list 0x1F0EF {'X' 'V'} WideWidth4
			list 0x1F0F4 {'X' 'X'} WideWidth4

	do "Triple-digit trump cards"
		createTrumpCardGlyphs 3 : list
			list 0x1F0E3 {'I' 'I' 'I'} WideWidth4
			list 0x1F0E7 {'V' 'I' 'I'} WideWidth4
			list 0x1F0EC {'X' 'I' 'I'} WideWidth4
			list 0x1F0EE {'X' 'I' 'V'} WideWidth4
			list 0x1F0F0 {'X' 'V' 'I'} WideWidth4
			list 0x1F0F3 {'X' 'I' 'X'} WideWidth4
			list 0x1F0F5 {'X' 'X' 'I'} WideWidth4

	do "Quadruple-digit trump cards"
		createTrumpCardGlyphs 4 : list
			list 0x1F0E8 {'V' 'I' 'I' 'I'} WideWidth4
			list 0x1F0ED {'X' 'I' 'I' 'I'} WideWidth4
			list 0x1F0F1 {'X' 'V' 'I' 'I'} WideWidth4

	do "Quintuple-digit trump cards"
		createTrumpCardGlyphs 5 : list
			list 0x1F0F2 {'X' 'V' 'I' 'I' 'I'} WideWidth4

	do "Playing card back"
		createPlayingCardBackGlyphs 1 : list
			list 0x1F0A0 {'sp1'} WideWidth4

	do "Single-digit dashed-boxed"
		local compositions {}
		foreach [j : range 0 26] : compositions.push {(0x1F1E6 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		createDashedBoxedGlyphs 1 compositions

	do "Triple-digit dashed-boxed"
		createDashedBoxedGlyphs 3 : list
			list 0xFFFC {'O' 'B' 'J/noDescend'} WideWidth1

	do "Single-digit inset boxed"
		local compositions {}
		foreach [j : range 0 26] : compositions.push {(0x1F170 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		createInsetBoxedGlyphs 1 compositions

	do "Single-digit inset diamond"
		createInsetDiamondGlyphs 1 : list
			list 0xFFFD { "question" } WideWidth2

	do "Double-digit inset boxed"
		createDecomposableInsetBoxedGlyphs 2 : list
			list 0x1F18B {'I' 'C'} WideWidth1
			list 0x1F18C {'P' 'A'} WideWidth1
			list 0x1F18D {'S' 'A'} WideWidth1
			list 0x1F18E {'A' 'B'} WideWidth1
			list 0x1F18F {'W' 'C'} WideWidth1

	do "Single-digit negative square"
		createCrossInsetBoxedGlyphs 1 : list
			list 0x1F18A { "P" } WideWidth1

	do "Single-digit inset mosaic"
		local compositions {}
		compositions.push { 0x1FBB1 { [[glyphStore.queryNameByUnicode (0x2714)].replace [regex '.WWID$'] ".NWID"] } WideWidth4 }
		compositions.push { 0x1FBB4 { [[glyphStore.queryNameByUnicode (0x21B2)].replace [regex '.WWID$'] ".NWID"] } WideWidth4 }
		compositions.push { 0x1FBC4 { "question" } WideWidth4 }
		createInsetMosaicGlyphs 1 compositions

	do "Single-digit double circled"
		local compositions {}
		foreach [j : range 1 till 9] : compositions.push : list (0x24F5 + j - 1) [digitGlyphNames j] WideWidth1
		createDoubleCircledGlyphs 1 compositions

	do "Double-digit double circled"
		local compositions {}
		foreach [j : range 10 till 10] : compositions.push : list (0x24F5 + j - 1) [digitGlyphNames j] WideWidth1
		createDoubleCircledGlyphs 2 compositions

	do "Single-digit braced"
		local compositions {}
		foreach [j : range 1 till 9] : compositions.push : list (0x2474 + j - 1) [digitGlyphNames j] WideWidth1
		foreach [j : range 0 26] : compositions.push {(0x249C + j) {[glyphStore.queryNameByUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)}
		foreach [j : range 0 26] : compositions.push {(0x1F110 + j) {[glyphStore.queryNameByUnicode (['A'.charCodeAt 0] + j)]} WideWidth1}
		createBracedGlyphs 1 compositions

	do "Double-digit braced"
		local compositions {}
		foreach [j : range 10 till 20] : compositions.push : list (0x2474 + j - 1) [digitGlyphNames j] WideWidth1
		createBracedGlyphs 2 compositions

	do "Single-digit hex braced"
		createHexBracedGlyphs 1 : list
			list 0x1F12A {'S'} WideWidth1

	do "Single-digit dotted"
		local compositions : list
			list 0x1F100 {'zero.lnum' 'period'} WideWidth1
		foreach [j : range 1 till 9] : compositions.push : list (0x2488 + j - 1) [[digitGlyphNames j].concat {'period'}] WideWidth1
		createDottedGlyphs 1 compositions

	do "Single-digit comma"
		local compositions {}
		foreach [j : range 0 till 9] : compositions.push : list (0x1F101 + j) [[digitGlyphNames j].concat {'comma'}] WideWidth1
		createDottedGlyphs 1 compositions

	do "Double-digit dotted"
		local compositions : list
		foreach [j : range 10 till 20] : compositions.push : list (0x2488 + j - 1) [[digitGlyphNames j].concat {'period'}] WideWidth1
		createDottedGlyphs 2 compositions

glyph-block Autobuild-Fractions : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Miniature Thner
	glyph-block-import Autobuild-Enclosure-Shared : CollectJobs EnsureComponentGlyphT CreateDerivedFontFromJobs applyRelations

	define [createFracImpl prefix demands layout] : begin
		local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix '' demands
		define miniatureFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
			crowd  --  layout.crowd
			scale  --  (layout.scaleFactor + 0.05)
			mono   --  true
			mono2  --  true

		define [FracBase nRows numWidth] : begin
			local gnFracBase ".frac-base{\(prefix)}{\(nRows)}{\(numWidth)}"
			if [not : query-glyph gnFracBase] : create-glyph gnFracBase : layout.baseShape nRows numWidth
			return gnFracBase

		define [FracShift iRow nRows numWidth denWidth] : begin
			local gnFracShift ".frac-shift{\(prefix)}{\(iRow)}{\(nRows)}{\(numWidth)}{\(denWidth)}"
			if [not : query-glyph gnFracShift] : create-glyph gnFracShift : layout.shiftShape iRow nRows numWidth denWidth
			return gnFracShift

		define [FracPartImpl subGlyphName] : begin
			local gnn ".frac-inner{\(prefix)}{\(subGlyphName)}"
			if [not : query-glyph gnn] : create-glyph gnn : glyph-proc
				define subGlyph : miniatureFont.queryByNameEnsured subGlyphName
				set-width 0
				set-mark-anchor 'fracBuildUp' 0 0 (subGlyph.advanceWidth * layout.scaleFactor) 0

				include subGlyph
				include : Ungizmo
				include : Translate 0 0
				include : Scale layout.scaleFactor
				include : Regizmo
			return gnn

		define [createFractionImpl job jobDecomposable] : begin
			local {gnf unicode gnParts} job
			if [not : query-glyph gnf] : create-glyph gnf unicode : glyph-proc
				local rows : layout.breakRows gnParts
				local decomposition {}
				local lastRowWidth 0
				foreach j [range 0 rows.length] : begin
					local gnList {}
					local thisRowWidth 0
					foreach gnSubRowElement [items-of rows.(j)] : begin
						set thisRowWidth : thisRowWidth + [miniatureFont.queryByNameEnsured gnSubRowElement].advanceWidth
						gnList.push : EnsureComponentGlyphT gnSubRowElement FracPartImpl

					if (j == 0)
					: then : begin
						local gnBase : FracBase rows.length thisRowWidth
						include [refer-glyph gnBase] AS_BASE ALSO_METRICS
						decomposition.push gnBase
					: else : begin
						local gnShift : FracShift j rows.length lastRowWidth thisRowWidth
						include : refer-glyph gnShift
						decomposition.push gnShift

					foreach gnRowElement [items-of gnList] : begin
						include : refer-glyph gnRowElement
						decomposition.push gnRowElement

					set lastRowWidth thisRowWidth

				if jobDecomposable : CvDecompose.set currentGlyph decomposition

		foreach job [items-of jobs.nonDecomposable] : createFractionImpl job false
		foreach job [items-of jobs.decomposableJobs] : createFractionImpl job true

		applyRelations jobs.relApplications


	define [FractionLayout letterHeight fine scaleFactor closing] : begin
		define dist : XH * (1 - scaleFactor - closing)
		define partOffsetY : letterHeight * scaleFactor + dist

		return : object
			crowd        : begin 3.5
			scaleFactor  : begin scaleFactor
			breakRows    : function [a] { {a.0} [a.slice 1] }
			baseShape    : function [nRows firstRowWidth] : glyph-proc
				set-width Width
				if fine : include : HBar.m SB RightSB SymbolMid (fine * 0.75)
				set-base-anchor 'fracBuildUp' (Middle - firstRowWidth * scaleFactor / 2) (SymbolMid + dist / 2)
			shiftShape   : function [iRow nRows numWidth denWidth] : glyph-proc
				local offset : -(numWidth / 2 + denWidth / 2) * scaleFactor
				set-width 0
				set-mark-anchor 'fracBuildUp' 0 0 offset (-partOffsetY)


	define [ControlPictureLayout crowd scaleFactor pGap] : begin
		define gap : XH * pGap

		return : object
			crowd        : begin crowd
			scaleFactor  : begin scaleFactor
			breakRows    : function [a] : a.map : function [x] {x}
			baseShape    : function [nRows firstRowWidth] : glyph-proc
				set-width Width
				set-base-anchor 'fracBuildUp' SB (SymbolMid + (CAP * scaleFactor * nRows + gap * (nRows - 1)) / 2 - CAP * scaleFactor)
			shiftShape   : function [iRow nRows numWidth denWidth] : glyph-proc
				define [startPos w p] : SB + (RightSB - SB - w * scaleFactor) * p / (nRows - 1)
				local offset : [startPos denWidth iRow] - [startPos numWidth (iRow - 1)] - numWidth * scaleFactor

				set-width 0
				set-mark-anchor 'fracBuildUp' 0 0 offset (-(CAP * scaleFactor + gap))

	define [createFractions records]        : createFracImpl 'frac'      records : FractionLayout CAP [AdviceStroke 3] 0.55 0.05
	define [createFractionsSmall records]   : createFracImpl 'fracSmall' records : FractionLayout XH [AdviceStroke 3] 0.55 0.05
	define [createControlPictures2 records] : createFracImpl 'ctrlPict2' records : ControlPictureLayout 3.75 0.55  0.2
	define [createControlPictures3 records] : createFracImpl 'ctrlPict3' records : ControlPictureLayout 5    0.375 0.1

	createFractions : list
		list 0x00BC { 'one.lnum' 'four.lnum' }
		list 0x00BD { 'one.lnum' 'two.lnum' }
		list 0x00BE { 'three.lnum' 'four.lnum' }
		list 0x2150 { 'one.lnum' 'seven.lnum' }
		list 0x2151 { 'one.lnum' 'nine.lnum' }
		list 0x2152 { 'one.lnum' 'one.lnum' 'zero.lnum' }
		list 0x2153 { 'one.lnum' 'three.lnum' }
		list 0x2154 { 'two.lnum' 'three.lnum' }
		list 0x2155 { 'one.lnum' 'five.lnum' }
		list 0x2156 { 'two.lnum' 'five.lnum' }
		list 0x2157 { 'three.lnum' 'five.lnum' }
		list 0x2158 { 'four.lnum' 'five.lnum' }
		list 0x2159 { 'one.lnum' 'six.lnum' }
		list 0x215A { 'five.lnum' 'six.lnum' }
		list 0x215B { 'one.lnum' 'eight.lnum' }
		list 0x215C { 'three.lnum' 'eight.lnum' }
		list 0x215D { 'five.lnum' 'eight.lnum' }
		list 0x215E { 'seven.lnum' 'eight.lnum' }
		list 0x215F { 'one.lnum' 'sp1' }
		list 0x2189 { 'zero.lnum' 'three.lnum' }
		list 0x214D { 'A' 'S' }

	createFractionsSmall : list
		list 0x2100 { 'a' 'c' }
		list 0x2101 { 'a' 's' }
		list 0x2105 { 'c' 'o' }
		list 0x2106 { 'c' 'u' }

	createControlPictures2 : list
		list 0xE0A1 {"L" "N"}
		list 0xE0A3 {"C" "N"}
		list 0x2408 {"B" "S"}
		list 0x2409 {"H" "T"}
		list 0x240A {"L" "F"}
		list 0x240B {"V" "T"}
		list 0x240C {"F" "F"}
		list 0x240D {"C" "R"}
		list 0x240E {"S" "O"}
		list 0x240F {"S" "I"}
		list 0x2419 {"E" "M"}
		list 0x241C {"F" "S"}
		list 0x241D {"G" "S"}
		list 0x241E {"R" "S"}
		list 0x241F {"U" "S"}
		list 0x2420 {"S" "P"}
		list 0x2424 {"N" "L"}

	createControlPictures3 : list
		list 0x2400 {"N" "U" "L"}
		list 0x2401 {"S" "O" "H"}
		list 0x2402 {"S" "T" "X"}
		list 0x2403 {"E" "T" "X"}
		list 0x2404 {"E" "O" "T"}
		list 0x2405 {"E" "N" "Q"}
		list 0x2406 {"A" "C" "K"}
		list 0x2407 {"B" "E" "L"}
		list 0x2410 {"D" "L" "E"}
		list 0x2411 {"D" "C" "one.lnum"}
		list 0x2412 {"D" "C" "two.lnum"}
		list 0x2413 {"D" "C" "three.lnum"}
		list 0x2414 {"D" "C" "four.lnum"}
		list 0x2415 {"N" "A" "K"}
		list 0x2416 {"S" "Y" "N"}
		list 0x2417 {"E" "T" "B"}
		list 0x2418 {"C" "A" "N"}
		list 0x241A {"S" "U" "B"}
		list 0x241B {"E" "S" "C"}
		list 0x2421 {"D" "E" "L"}

glyph-block AutoBuild-Accented-Equal : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Miniature
	glyph-block-import Mark-Above : aboveMarkBot
	glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations

	define [createAccentedOp gnBase crowd scale shiftX shiftY demands] : begin
		define prefix : 'accent-op{' + gnBase + '}{' + [{crowd scale shiftX shiftY}.join '-'] + '}'
		local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED MONOSPACE-ONLY prefix '' demands
		local dFont : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Miniature gs
			crowd  -- crowd
			scale  -- scale
			mono   -- true
			mono2  -- true

		define [ComponentImpl offset totalWidth] : lambda [gidPart] : begin
			define gni : '.accented-op-part.' + gidPart + '@' + [{ prefix offset totalWidth }.join '/']
			if [query-glyph gni] : return gni
			create-glyph gni : glyph-proc
				set-width 0
				set-mark-anchor 'compositeInner' 0 0
				include : dFont.queryByNameEnsured gidPart
				include : Ungizmo
				include : Translate (-totalWidth / 2 + offset) 0
				include : Scale scale
				include : Translate (Middle + shiftX - Width) shiftY
				include : Regizmo
			return gni

		define [createAccentedOpImpl job decomposable] : begin
			local { gn unicode parts } job
			local totalWidth 0
			local offsets    { }
			foreach [j : range 0 parts.length] : begin
				local gidPart parts.(j)
				set offsets.(j)  totalWidth
				set totalWidth : totalWidth + [dFont.queryByNameEnsured gidPart].advanceWidth

			if [not : query-glyph gn] : create-glyph gn unicode : glyph-proc
				set-width Width
				local ps { gnBase }
				foreach [j : range 0 parts.length] : begin
					local gidPart parts.(j)
					local p : EnsureComponentGlyphT gidPart : ComponentImpl offsets.(j) totalWidth
					include : refer-glyph p
					ps.push p
				include : Translate Width 0
				include : refer-glyph gnBase
				if decomposable : CvDecompose.set currentGlyph ps

		foreach job [items-of jobs.nonDecomposable] : createAccentedOpImpl job false
		foreach job [items-of jobs.decomposableJobs] : createAccentedOpImpl job true

		applyRelations jobs.relApplications

	createAccentedOp 'equal' 7 0.4 0 aboveMarkBot : list
		list 0x225e {"m"}
		list 0x225F {"question/hookPart" "question/dotPart"}
	createAccentedOp 'equal' 5 0.8 0 aboveMarkBot : list
		list 0x2258 {"symbolMidTie"}
	createAccentedOp 'equal' 7 0.5 0 (aboveMarkBot - (SymbolMid - XH / 2)) : list
		list 0x2259 {"triangularWedge.NWID"}
		list 0x225a {"triangularVee.NWID"}
		list 0x225b {"blackStar.NWID"}
		list 0x225c {"whiteTriangleUp.NWID"}
		list 0x2a6e {"opAsterisk"}
	createAccentedOp 'sqrt' 5 0.5 (-Width / 4) [mix OperBot OperTop 0.6] : list
		list 0x221b {"three.lnum"}
		list 0x221c {"four.lnum"}
	createAccentedOp 'equal' 8 0.3 0 aboveMarkBot : list
		list 0x225d {"d" "e" "f"}
	createAccentedOp 'markDemoBaseSpace' 6 0.40 0 (aboveMarkBot - (CAP * 0.40 - XH * 0.40)) : list
		list 0xAE    {"R" "combRingCapDiv1"}
	createAccentedOp 'markDemoBaseSpace' 6 0.45 0 (aboveMarkBot - (CAP * 0.45 - XH * 0.45)) : list
		list 0x2122  {"T" "M"}
		list 0x2120  {"S" "M"}
		list 0x1F16A {"M" "C"}
		list 0x1F16B {"M" "D"}
		list 0x1F16C {"M" "R"}

glyph-block Autobuild-Ligatures : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Thinner
	glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations

	define [createLigatures prefix _shrink1 _shrinkN wadj1 wadjN kKern demands] : for-width-kinds WideWidth2
		local plainLigature : FMosaicWide && para.isQuasiProportional
		local ww : if FMosaicWide MosaicWidth (MosaicWidth * para.advanceScaleMM)
		local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix MosaicNameSuffix demands
		local shrink1 : if plainLigature 1 [clamp 0 1 (_shrink1 * [mix Width ww 0.5] / Width)]
		local shrinkN : if plainLigature 1 [clamp 0 1 (_shrinkN * [mix Width ww 0.5] / Width)]
		local df1 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink1
		local dfN : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrinkN

		define [LigaturePlaceholderImpl aw markPlacement] : begin
			define gni : '.ligature-placeholder@' + [{aw markPlacement}.join '/']
			if [query-glyph gni] : return gni
			create-glyph gni : glyph-proc
				set-width aw
				set-base-anchor 'enclosureInner' markPlacement 0
			return gni
		define [LigaturePartImpl df offset1 compress markDist] : lambda [gidPart] : begin
			define gni : '.ligature-part.' + gidPart + '@' + [{ prefix compress offset1 markDist }.join '/']
			if [query-glyph gni] : return gni
			create-glyph gni : glyph-proc
				set-width 0
				include : df.queryByNameEnsured gidPart
				include : Ungizmo
				include : Translate offset1 0
				include : Scale compress 1
				include : Regizmo
				set-mark-anchor 'enclosureInner' 0 0 markDist 0
			return gni

		define [LigatureImpl job decomposable] : begin
			local { gn unicode components desiredWidth } job
			local ps {}

			local dfgs {}
			foreach { i component } [components.entries] : begin
				set dfgs.(i) : [if i dfN df1].queryByNameEnsured component

			if [query-glyph gn] : return nothing

			if plainLigature : begin
				# Glyph built as a pure ligature. This case is always decomposable
				create-glyph gn [MangleUnicode unicode desiredWidth] : glyph-proc
					local decomposition { }
					local aw 0
					foreach { i component } [components.entries] : do
						local componentG : query-glyph component
						include : with-transform [Translate aw 0] : refer-glyph component
						set aw : aw + componentG.advanceWidth
						decomposition.push component
					set-width aw
					CvDecompose.set currentGlyph decomposition
					IsCompositeOrLigature.set currentGlyph
			: else : begin
				# Glyph is not a pure ligature, do it in the hard way
				local sumChildrenWidth 0
				foreach {i dfg} [dfgs.entries] : begin
					set sumChildrenWidth : sumChildrenWidth + dfg.advanceWidth * [if i wadjN wadj1]

				local glyphWidth : if (sumChildrenWidth < ww) MosaicWidth ww
				local compressRefWidth : (glyphWidth - SB * 1.25) / (glyphWidth - SB * 2) * glyphWidth
				local kern : kKern * glyphWidth
				local estKernedUncompressedWidth : sumChildrenWidth - kern * (dfgs.length - 1)
				if (dfgs.length > 1) : foreach [cycle : range 0 4] : begin
					if (kKern == 0) : begin
						set kern : clamp 0 (SB * 7 / 8) ((estKernedUncompressedWidth - compressRefWidth) / (dfgs.length - 1))
					set estKernedUncompressedWidth : sumChildrenWidth - kern * (dfgs.length - 1)

				local compress : clamp 0 1 (compressRefWidth / estKernedUncompressedWidth)

				create-glyph gn [MangleUnicode unicode desiredWidth] : glyph-proc
					local decomposition   { }
					local baseOffset : glyphWidth / 2 - estKernedUncompressedWidth * compress / 2
					foreach { i component } [components.entries] : do
						local componentAdvance : compress * (dfgs.(i).advanceWidth * [if i wadjN wadj1] - kern)
						local componentRefOffset : dfgs.(i).advanceWidth * ([if i wadjN wadj1] - 1) / 2
						if (i === 0) : begin
							local placeholder : LigaturePlaceholderImpl glyphWidth baseOffset
							decomposition.push placeholder
							include [refer-glyph placeholder] AS_BASE ALSO_METRICS
						local part : EnsureComponentGlyphT component
							LigaturePartImpl dfN componentRefOffset compress componentAdvance
						decomposition.push part
						include [refer-glyph part]
					if decomposable : CvDecompose.set currentGlyph decomposition
					IsCompositeOrLigature.set currentGlyph

		foreach job [items-of jobs.nonDecomposable]  : LigatureImpl job false
		foreach job [items-of jobs.decomposableJobs] : LigatureImpl job true

		applyRelations jobs.relApplications

	# Dutch IJ
	define ijShrink : clamp 0.6 0.75 : StrokeWidthBlend 0.6 0.75
	createLigatures 'compatLigature1' ijShrink ijShrink 1 1 [if (para.advanceScaleI < 1) 0 0.2] : list
		list 0x132 { 'I' 'J' }
		list 0x133 { 'i' 'j' }
		list 0xEF11 { 'IAcute' 'JAcute' }
		list 0xEF12 { 'iAcute' 'jAcute' }

	# Link Gr for acute variants
	NLDAcuteVariant.set [glyphStore.queryByUnicodeEnsured 0x132] [glyphStore.queryNameByUnicodeEnsured 0xEF11]
	NLDAcuteVariant.set [glyphStore.queryByUnicodeEnsured 0x133] [glyphStore.queryNameByUnicodeEnsured 0xEF12]

	define stdShrink : clamp 0.75 0.9 : StrokeWidthBlend 0.75 0.9
	createLigatures 'compatLigature2' stdShrink stdShrink 1 1 0 : list
		list 0x1C4 { 'D' 'ZCaron' }
		list 0x1C5 { 'D' 'zCaron' }
		list 0x1C6 { 'd' 'zCaron' }
		list 0x1C7 { 'L' 'J' }
		list 0x1C8 { 'L' 'j' }
		list 0x1C9 { 'l' 'j' }
		list 0x1CA { 'N' 'J' }
		list 0x1CB { 'N' 'j' }
		list 0x1CC { 'n' 'j' }
		list 0x1F1 { 'D' 'Z' }
		list 0x1F2 { 'D' 'z' }
		list 0x1F3 { 'd' 'z' }
		list 0x478 { 'cyrl/O' 'cyrl/u' }
		list 0x479 { 'cyrl/uk/o' 'cyrl/u' }
		list 0x20A7 { 'P' 't' }
		list 0x20A8 { 'R' 's' }
		list 0x20AF { 'D' 'grek/rho' }
		list 0x2116 { 'N' 'numeroRightHalf' }
		list 0x1F190 { 'D' 'J' } WideWidth1

	# Link Gr for caron variants
	HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F1] [glyphStore.queryNameByUnicodeEnsured 0x1C4]
	HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F2] [glyphStore.queryNameByUnicodeEnsured 0x1C5]
	HBSCaronVariant.set [glyphStore.queryByUnicodeEnsured 0x1F3] [glyphStore.queryNameByUnicodeEnsured 0x1C6]

	createLigatures 'romanNumerals1' 1 1 1 1 0 : list
		list 0x2160 { 'I' }
		list 0x2164 { 'V' }
		list 0x2169 { 'X' }
		list 0x216C { 'L' }
		list 0x216D { 'C' }
		list 0x216E { 'D' }
		list 0x216F { 'M' }
		list 0x2170 { 'i' }
		list 0x2174 { 'v' }
		list 0x2179 { 'x' }
		list 0x217C { 'l' }
		list 0x217D { 'c' }
		list 0x217E { 'd' }
		list 0x217F { 'm' }

	createLigatures 'romanNumerals2' stdShrink stdShrink 1 1 0 : list
		list 0x2161 { 'I' 'I' }
		list 0x2163 { 'I' 'V' }
		list 0x2165 { 'V' 'I' }
		list 0x2168 { 'I' 'X' }
		list 0x216A { 'X' 'I' }
		list 0x2171 { 'i' 'i' }
		list 0x2173 { 'i' 'v' }
		list 0x2175 { 'v' 'i' }
		list 0x2178 { 'i' 'x' }
		list 0x217A { 'x' 'i' }

	define romanShrink : clamp 0.625 0.875 : StrokeWidthBlend 0.625 0.875
	createLigatures 'romanNumerals3' romanShrink romanShrink 1 1 0 : list
		list 0x2162 { 'I' 'I' 'I' }
		list 0x2166 { 'V' 'I' 'I' }
		list 0x216B { 'X' 'I' 'I' }
		list 0x2172 { 'i' 'i' 'i' }
		list 0x2176 { 'v' 'i' 'i' }
		list 0x217B { 'x' 'i' 'i' }

	define romanShrink4 : clamp 0.5 0.875 : StrokeWidthBlend 0.5 0.875
	createLigatures 'romanNumerals4' romanShrink4 romanShrink4 1 1 0 : list
		list 0x2167 { 'V' 'I' 'I' 'I' }
		list 0x2177 { 'v' 'i' 'i' 'i' }

	createLigatures 'temperature' 0.7 0.8 0.75 0.9 0 : list
		list 0x2103 { 'degree' 'C' }
		list 0x2109 { 'degree' 'F' }

glyph-block Autobuild-Pnonetic-Ligatures : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Thinner
	glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations
	glyph-block-import Autobuild-Transformed-Shared : ToSuperscript ToSubscript

	define [createPhoneticLigatures tfm prefix adws mockNParts _shrink kKern demands] : begin
		local ww0 : Width * adws
		local wwM : ww0 / [fallback tfm.crowdAdjScale 1]
		local jobs : CollectJobs DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix "" demands
		local shrink : clamp 0 1 _shrink
		local kern 0
		foreach [cycle : range 0 8] : begin
			set kern : kKern * (2 * SB * shrink + (HalfStroke * [HSwToV shrink] - OX * 2))
			local tmpShrink : (wwM + kern * (mockNParts - 1)) / (mockNParts * Width)
			set shrink : Math.max _shrink : clamp 0 1 tmpShrink

		local thinFont : CreateDerivedFontFromJobs jobs {} : function [gs]
			Thinner gs shrink true tfm.crowd tfm.crowdAdjScale

		define [LigaturePlaceholderImpl aw markPlacement mak] : begin
			define gni : '.phonetic-ligature-placeholder@' + [{ prefix aw markPlacement mak }.join '/']
			if [query-glyph gni] : return gni
			create-glyph gni : glyph-proc
				set-width aw
				if mak : include : [DivFrame adws].markSet.(mak)
				set-base-anchor 'enclosureInner' markPlacement 0
				set-base-anchor 'slash' (aw / 2) (Ascender / 2)
				include : tfm adws
			return gni

		define [LigaturePartImpl thinFont compress markDist maskPos] : lambda [gidPart] : begin
			define gni : '.phonetic-ligature-part.' + gidPart + '@' + [{ prefix compress markDist maskPos }.join '/']
			if [query-glyph gni] : return gni
			create-glyph gni : glyph-proc
				set-width 0
				include : difference
					thinFont.queryByNameEnsured gidPart
					MaskRight maskPos
				include : Ungizmo
				include : Scale compress 1
				include : Regizmo
				set-mark-anchor 'enclosureInner' 0 0 markDist 0
				include : tfm adws
			return gni

		define [LigatureImpl job decomposable] : if [not : query-glyph gn] : begin
			local { gn unicode components mak } job

			local sumChildrenWidth    0
			local effectiveGlyphCount 0
			local originals {}
			local dfgs      {}
			foreach { i component } [components.entries] : begin
				set originals.(i) : query-glyph component
				set dfgs.(i) : thinFont.queryByNameEnsured component
				if (originals.(i).advanceWidth > 0) : inc effectiveGlyphCount
				set sumChildrenWidth : sumChildrenWidth + dfgs.(i).advanceWidth

			local refW      : sumChildrenWidth - kern * (effectiveGlyphCount - 1)
			local compRefWw   wwM
			local compress  : clamp 0 1 (compRefWw / refW)

			if [not : query-glyph gn] : create-glyph gn unicode : glyph-proc
				local decomposition   { }
				local baseOffset : ww0 / 2 - refW * compress / 2
				foreach { i component } [components.entries] : do
					local currentIsMark : 0 == originals.(i).advanceWidth

					local componentAdvance : if currentIsMark 0 : compress * (dfgs.(i).advanceWidth - kern)
					local maskPos : dfgs.(i).advanceWidth - kern + [if ((i + 1) < effectiveGlyphCount) (dfgs.(i + 1).advanceWidth / 2) ww0]

					if (i === 0) : begin
						local placeholder : LigaturePlaceholderImpl ww0 baseOffset mak
						decomposition.push placeholder
						include [refer-glyph placeholder] AS_BASE ALSO_METRICS

					if currentIsMark : then : begin
						include [refer-glyph component]
					: else : begin
						local part : EnsureComponentGlyphT component
							LigaturePartImpl thinFont compress componentAdvance maskPos
						decomposition.push part
						include [refer-glyph part]

				if decomposable : CvDecompose.set currentGlyph decomposition

		foreach job [items-of jobs.nonDecomposable]  : LigatureImpl job false
		foreach job [items-of jobs.decomposableJobs] : LigatureImpl job true

		applyRelations jobs.relApplications

	define [ToLetter] : glyph-proc

	define stdShrink : clamp 0.625 0.9 : StrokeWidthBlend 0.625 0.9
	createPhoneticLigatures ToLetter 'phonetic1' [Math.max 1 : para.advanceScaleF * para.advanceScaleMM] 2 stdShrink 1 : list
		list 0xFB00  { 'f'               'f'                     } null
		list 0xFB01  { 'f/compLigLeft1'  'dotlessi/compLigRight' } null
		list 0xFB02  { 'f/compLigLeft3'  'l/compLigRight'        } null

	createPhoneticLigatures ToLetter 'phonetic2' para.advanceScaleMM 2 stdShrink 1 : list
		list 0x02A3  { 'd/phoneticLeft'    'z/phoneticRight'                } 'b'
		list 0x02A4  { 'd/phoneticLeft'    'ezh/phoneticRight'              } 'bp'
		list 0x02A5  { 'd/phoneticLeft'    'zCurlyTail/phoneticRight'       } 'b'
		list 0x02A6  { 't/phoneticLeft2'   's/phoneticRight'                } 'b'
		list 0x02A7  { 't/teshLeft'        'esh'                            } 'bp'
		list 0x02A8  { 't/phoneticLeft1'   'cCurlyTail'                     } 'b'
		list 0x02A9  { 'f/phoneticLeft'    'eng/phoneticRight'              } 'bp'
		list 0x02AA  { 'l/phoneticLeft'    's/phoneticRight'                } 'b'
		list 0x02AB  { 'l/phoneticLeft'    'z'                              } 'b'
		list 0xAB66  { 'd/phoneticLeft'    'zRTail/phoneticRight'           } 'bp'
		list 0xAB67  { 't/phoneticLeft1'   'sRTail'                         } 'bp'
		list 0x1DF12 { 'd/phoneticLeft'    'ezhPalatalHook/phoneticRight'   } 'bp'
		list 0x1DF17 { 't/teshLeft'        'eshPalatalHook'                 } 'bp'
		list 0x1DF19 { 'd/phoneticLeft'    'ezhRetroflexHook/phoneticRight' } 'bp'
		list 0x1DF1C { 't/teshLeft'        'eshRetroflexHook/teshRight'     } 'bp'
		list 0xFB05  { 'longs/compLigLeft' 't/compLigRight'                 } null
		list 0xFB06  { 's/compLigLeft'     't/compLigRight'                 } null

	createPhoneticLigatures ToLetter 'phonetic3' [Math.max para.advanceScaleMM : para.advanceScaleF * [mix 1 para.advanceScaleMM 2]] 3 stdShrink 1 : list
		list 0xFB03  { 'f/compLigLeft2' 'f/compLigLeft1' 'dotlessi/compLigRight' } null
		list 0xFB04  { 'f/compLigLeft4' 'f/compLigLeft3' 'l/compLigRight'        } null

	createPhoneticLigatures ToLetter 'phoneticSmcp' (para.advanceScaleM * para.advanceScaleMM) 3 1 0.5 : list
		list 0x2121  { 'smcpT' 'smcpE' 'smcpL' } 'e'
		list 0x213B  { 'smcpF' 'smcpA' 'smcpX' } 'e'

	createPhoneticLigatures ToSuperscript 'phoneticSuperscript' 1 2 stdShrink 1 : list
		list 0x10787 { 'd/phoneticLeft'  'z/phoneticRight'          } 'b'
		list 0x1078A { 'd/phoneticLeft'  'ezh/phoneticRight'        } 'bp'
		list 0x10789 { 'd/phoneticLeft'  'zCurlyTail/phoneticRight' } 'bp'
		list 0x107AC { 't/phoneticLeft2' 's/phoneticRight'          } 'b'
		list 0x107AE { 't/teshLeft'      'esh'                      } 'bp'
		list 0x107AB { 't/phoneticLeft1' 'cCurlyTail'               } 'b'
		list 0x10790 { 'f/phoneticLeft'  'eng/phoneticRight'        } 'bp'
		list 0x10799 { 'l/phoneticLeft'  's/phoneticRight'          } 'b'
		list 0x1079A { 'l/phoneticLeft'  'z'                        } 'b'
		list 0x10788 { 'd/phoneticLeft'  'zRTail/phoneticRight'     } 'bp'
		list 0x107AD { 't/phoneticLeft1' 'sRTail'                   } 'p'

	createPhoneticLigatures ToSubscript 'tenSubscript' 1 2 1 0.5 : list
		list 0x23E8 { 'one.lnum' 'zero.lnum' } 'capital'

	createPhoneticLigatures ToLetter 'thSlash' para.advanceScaleMM 2 stdShrink 1 : list
		list 0x1D7A { 't/phoneticLeft1' 'h' 'wideSlash' } 'b'

glyph-block Autobuild-Double-Emotions : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Recursive-Build : Thinner
	glyph-block-import Autobuild-Enclosure-Shared : CollectJobs CreateDerivedFontFromJobs EnsureComponentGlyphT applyRelations

	define [createDoubleEmotions prefix adws _shrink1 _shrink2 wadj1 wadj2 demands] : for-width-kinds WideWidth2
		define CWidth : if FMosaicWide MosaicWidth (Width * adws)
		define shrink1 : if FMosaicWide 1 _shrink1
		define shrink2 : if FMosaicWide 1 _shrink2
		define kern : SB * shrink1 + SB * shrink2 + HalfStroke * [mix shrink1 shrink2 0.5] - OX * 2

		define jobs : CollectJobs NON-DECOMPOSABLE NOT-CENTERED ALLOW-PROPORTIONAL prefix MosaicNameSuffix demands
		define df1 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink1 true
		define df2 : CreateDerivedFontFromJobs jobs {} : lambda [gs] : Thinner gs shrink2 true

		foreach [{gn unicode { c1 m1 c2 m2 } mak} : items-of jobs.nonDecomposable] : if [not : query-glyph gn] : begin
			create-glyph gn [MangleUnicode unicode] : glyph-proc
				set-width CWidth
				if mak : include : [DivFrame (CWidth / Width)].markSet.(mak)
				define dfg1 : df1.queryByNameEnsured c1
				define dfm1 : df1.queryByNameEnsured m1
				define dfg2 : df2.queryByNameEnsured c2
				define dfm2 : df2.queryByNameEnsured m2
				local sumChildrenWidth : dfg1.advanceWidth * wadj1 + dfg2.advanceWidth * wadj2
				local refW : sumChildrenWidth - kern
				include : union dfg2 [with-transform [Translate (dfg2.advanceWidth) 0] dfm2]
				include : Translate (dfg1.advanceWidth * wadj1 - kern) 0
				include : union dfg1 [with-transform [Translate (dfg1.advanceWidth) 0] dfm1]
				include : Ungizmo
				include : Translate ((-refW) / 2) 0
				include : Scale [clamp 0 1 ((CWidth - SB * 1.25) / (CWidth - SB * 2) * CWidth / refW)] 1
				include : Translate (CWidth / 2) 0
				include : Regizmo

		applyRelations jobs.relApplications

	define stdShrink : clamp 0.625 0.9 : StrokeWidthBlend 0.625 0.9
	createDoubleEmotions 'doubleemotion' para.advanceScaleM stdShrink stdShrink 1 1 : list
		list 0x203c { 'exclam' 'zwsp' 'exclam' 'zwsp' }
		list 0x2047 { 'question/hookPart' 'question/dotPart' 'question/hookPart' 'question/dotPart' }
		list 0x2048 { 'question/hookPart' 'question/dotPart' 'exclam' 'zwsp' }
		list 0x2049 { 'exclam' 'zwsp' 'question/hookPart' 'question/dotPart' }

glyph-block Autobuild-Grouped-Digits : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives

	define [createGroupedDigits shrink crowd numberGlyphIDs] : begin
		create-glyph '.nd-shade' : glyph-proc
			set-width 0
			set-mark-anchor 'compositeInner' 0 0
			include : intersection
				HBar.b 0 Width (Descender * 0.75) [AdviceStroke 4]
				glyph-proc
					include : refer-glyph "denseShade.WWID"
					include : Translate ((-Width) / 2) 0
			include : Translate (-Width) 0

		foreach [gid : items-of numberGlyphIDs] : foreach [nd : items-of {0 1 2 3 4 5 6}]
			create-glyph (gid + ".nd" + nd) : glyph-proc
				include : refer-glyph gid
				if (nd >= 3 && nd <= 5) : begin
					include : with-transform [Translate Width 0] : refer-glyph '.nd-shade'
					CvDecompose.set currentGlyph { gid '.nd-shade' }
				: else : begin
					CvDecompose.set currentGlyph { gid }

	createGroupedDigits 0.9 3.0 {
		'zero.lnum' 'one.lnum' 'two.lnum' 'three.lnum' 'four.lnum'
		'five.lnum' 'six.lnum' 'seven.lnum' 'eight.lnum' 'nine.lnum'
	}
