define Glyph [require './support/glyph'].Glyph define Stroke [require './support/stroke'].Stroke define tp [require './support/transform'].transformPoint define utp [require './support/transform'].untransform define inverse [require './support/transform'].inverse define libspiro : require 'libspiro-js' define SpiroExpansionContext [require './support/spiroexpand'].SpiroExpansionContext ### COMMON FUNCTIONS define [mix a b p] : a + (b - a) * p define [linreg x0 y0 x1 y1 x] : y0 + (x - x0) * (y1 - y0) / (x1 - x0) define [bilinear x0 x1 y0 y1 z00 z01 z10 z11 x y] : linreg * y0 linreg x0 z00 x1 z10 x * y1 linreg x0 z01 x1 z11 x * y define [clamp l h x] : if (x < l) l : if (x > h) h x define [fallback] : for [local j 0] (j < arguments.length) [inc j] : if (arguments.(j) !== nothing) : return arguments.(j) define [TempFont] {.glyf {} .head {.} .hhea {.} ."OS/2" {.} .name {.} .post {.}} # Empty font base file define-macro $$include : syntax-rules {'$$include' {'.quote' file}} : begin local path : require 'path' local fs : require 'fs' local f0 [[env.macros.get 'input-path']].1 local parse [require './syntax.js'].parse local absolutePath : path.resolve [path.dirname f0] [formOf file] local input : fs.readFileSync absolutePath 'utf-8' local ast : parse input {.within {.file absolutePath .input input}} return {'.syntactic-closure' ast env} otherwise `nothing define [buildFont para recursive] : begin define variantSelector para.variantSelector define font this define glyphList font.glyf define glyphs {.} define unicodeGlyphs {} define UPM 1000 define serifed : not [not para.serif] # Key metrics define WIDTH para.width define SB para.sb define CAP para.cap define XH para.xheight define DESCENDER para.descender # Key metrics for symbols local parenTop ((XH * 0.625) + (CAP - XH) * 2.5) local parenBot ((XH * 0.625) - (CAP - XH) * 2.5) local parenMid [mix parenTop parenBot 0.5] # Transform constructors define [Italify angle shift] : begin local slope [Math.tan ([fallback angle para.italicangle] / 180 * Math.PI)] return {.xx 1 .yx slope .xy 0 .yy 1 .x [fallback shift : -slope * parenMid] .y 0} define [Upright angle shift] [inverse : Italify angle shift] define [Scale sx sy] {.xx sx .yx 0 .xy 0 .yy [fallback sy sx] .x 0 .y 0} define [Translate x y] {.xx 1 .yx 0 .xy 0 .yy 1 .x x .y y} define [Rotate angle] {.xx [Math.cos angle] .yx (-[Math.sin angle]) .xy [Math.sin angle] .yy [Math.cos angle] .x 0 .y 0} define globalTransform : Italify para.italicAngle define deGlobalTransform : inverse globalTransform define CORRECTION_HX : [fallback para.contrast 1] / [Math.sqrt (1 - globalTransform.yx * globalTransform.yx)] # Orient parameters define UPWARD {.x (-CORRECTION_HX) .y 0} define DOWNWARD {.x CORRECTION_HX .y 0} define RIGHTWARD {.x globalTransform.yx .y 1} define LEFTWARD {.x (- globalTransform.yx) .y (-1)} define [normalize a] : begin local m : Math.hypot a.x a.y return {.x (a.x / m) .y (a.y / m)} # Style parameters define O para.overshoot define OXHOOK para.oxhook define HOOK para.hook define AHOOK para.ahook define SHOOK para.shook define RHOOK para.rhook define JHOOK para.jhook define FHOOK para.fhook define HOOKX para.hookx define SMOOTH para.smooth define SMALLSMOOTH para.smallsmooth define STROKE para.stroke define CONTRAST para.contrast define DOTSIZE : fallback para.dotsize STROKE define PERIODSIZE : fallback para.periodsize DOTSIZE define BARPOS : fallback para.barpos 0.5 define GBARPOS : fallback para.gbarpos 0.5 define PBARPOS : fallback para.pbarpos 0.5 define EBARPOS : fallback para.ebarpos BARPOS define OVERLAYPOS para.overlaypos define FIVEBARPOS para.fivebarpos define LONGJUT para.longjut define JUT para.jut define VJUT para.vjut define ACCENT para.accent define ACCENTX para.accentx define SLAB para.slab define KAPPA para.kappa define BKAPPA : para.bkappa || KAPPA + 0.1 define KAPPA_SPIRO_ARC : KAPPA + 0.1 define CKAPPA : para.ckappa || BKAPPA define KAPPA_HOOK : fallback para.kappa_hook (BKAPPA + 0.1) define KAPPA_AHOOK : fallback para.kappa_ahook KAPPA_HOOK define KAPPA_RHOOK : fallback para.kappa_rhook KAPPA_HOOK define TAILADJX : WIDTH * 0.2 define TAILADJY : XH * 0.25 define LBALANCE : LONGJUT * 0.04 define IBALANCE : fallback para.ibalance (LONGJUT * 0.04) define JBALANCE : fallback para.jbalance 0 define JBALANCE2 : fallback para.jbalance2 (STROKE / 2 + LBALANCE) define TBALANCE : fallback para.tbalance JBALANCE define TBALANCE2 : fallback para.tbalance2 TBALANCE define RBALANCE : fallback para.rbalance (JBALANCE * 0.3) define RBALANCE2 : fallback para.rbalance2 0 define SBALANCE : fallback para.sbalance 0.52 define FBALANCE : fallback para.fbalance 0 define ONEBALANCE : fallback para.onebalance 0 # derived metrics define FULLWIDTH : if para.cjkSpacing (WIDTH * 2) WIDTH define VSTROKE : STROKE * CONTRAST define ESS : STROKE * [fallback para.essx CONTRAST] define XO : XH - O define CAPO : CAP - O define HALFSTROKE : STROKE / 2 define RIGHTSB : WIDTH - SB define FWRSB : FULLWIDTH - SB define MIDDLE : WIDTH / 2 define FWMIDDLE : FULLWIDTH / 2 define CAPMIDDLE : CAP / 2 define CAP_SMOOTH : CAP - SMOOTH define DOTRADIUS : DOTSIZE / 2 define PERIODRADIUS : PERIODSIZE / 2 define SIDEJUT : JUT - HALFSTROKE * CORRECTION_HX define SMOOTHA : SMOOTH - globalTransform.yx * para.smoothadjust define SMOOTHB : SMOOTH + globalTransform.yx * para.smoothadjust define SMALLSMOOTHA : SMALLSMOOTH - globalTransform.yx * para.smoothadjust define SMALLSMOOTHB : SMALLSMOOTH + globalTransform.yx * para.smoothadjust define CORRECTION_VX globalTransform.yx define CORRECTION_VS : STROKE * globalTransform.yx define CORRECTION_OMIDX : globalTransform.yx * 1.2 define CORRECTION_OMIDS : STROKE * CORRECTION_OMIDX # Blackness parameters # We will estimate blackness using lower-case 'e' define WHITENESS : ((XH - STROKE * 3) * (RIGHTSB - SB) * (1 / 3)) / (XH * (RIGHTSB - SB)) define [adviceBlackness crowdedness] : Math.min STROKE ((RIGHTSB - SB) * (1 - WHITENESS) / (crowdedness * CORRECTION_HX)) define MVERTSTROKE : adviceBlackness : fallback para.lllcrowdedness (3 + 1 / 3) define OVERLAYSTROKE : adviceBlackness 4 define OPERATORSTROKE : adviceBlackness 3.2 define SHOULDERFINE : [adviceBlackness 4] / 2 define SUPERNESS : fallback para.superness 2 define [superxy x] : Math.pow (1 - [Math.pow x SUPERNESS]) (1 / SUPERNESS) define [adviceSSmooth y sign] : begin local ss : y * 0.22 + STROKE * 0.22 + 0.02 * (RIGHTSB - SB) return : ss + sign * globalTransform.yx * para.smoothadjust * (ss / SMALLSMOOTH) define [adviceGlottalStopSmooth y sign] : ((y - STROKE) * 0.25 + STROKE / 2) + sign * globalTransform.yx * para.smoothadjust define [shoulderMidSlope _fine _stroke _dir] : 0.5 * CORRECTION_HX * ([fallback _stroke STROKE] - [fallback _fine SHOULDERFINE]) / [fallback _stroke STROKE] + [fallback _dir 1] * globalTransform.yx # Anchor parameters define BASE 'base' define MARK 'mark' define MARKBASE 'markbase' define AS_BASE 'AS-BASE' define [tm anchor] : return { .x (anchor.x * globalTransform.xx + anchor.y * globalTransform.yx + globalTransform.x) .y (anchor.x * globalTransform.xy + anchor.y * globalTransform.yy + globalTransform.y) .type anchor.type } define markAboveLower {.anchors {.above [tm {.x MIDDLE .y XH .type BASE}]}} define markAboveCap {.anchors {.above [tm {.x MIDDLE .y CAP .type BASE}]}} define markBelowLower {.anchors {.below [tm {.x MIDDLE .y DESCENDER .type BASE}]}} define markBelowZero {.anchors {.below [tm {.x MIDDLE .y 0 .type BASE}]}} define markToprightLower {.anchors {.topright [tm {.x RIGHTSB .y XH .type BASE}]}} define markToprightCap {.anchors {.topright [tm {.x RIGHTSB .y CAP .type BASE}]}} define markBottomrightLower {.anchors {.bottomright [tm {.x RIGHTSB .y DESCENDER .type BASE}]}} define markBottomrightZero {.anchors {.bottomright [tm {.x RIGHTSB .y 0 .type BASE}]}} define [anchorDeriv] : begin local h {.} foreach a [items-of arguments] : foreach k [items-of [Object.keys a.anchors]] : begin set h.(k) {.} set {.x h.(k).x .y h.(k).y .type h.(k).type .mbx h.(k).mbx .mby h.(k).mby} a.anchors.(k) return {.anchors h} define [StdAnchorGroup] : begin local a : anchorDeriv.apply null arguments set a.anchors.overlay {.type BASE .x [mix a.anchors.below.x a.anchors.above.x OVERLAYPOS] .y [mix a.anchors.below.y a.anchors.above.y OVERLAYPOS] } set a.anchors.slash {.type BASE .x [mix a.anchors.below.x a.anchors.above.x 0.5] .y [mix a.anchors.below.y a.anchors.above.y 0.5] } return a define capitalMarks : StdAnchorGroup markAboveCap markBelowZero markToprightCap markBottomrightZero define bMarks : StdAnchorGroup markAboveCap markBelowZero markToprightCap markBottomrightZero define eMarks : StdAnchorGroup markAboveLower markBelowZero markToprightLower markBottomrightZero define pMarks : StdAnchorGroup markAboveLower markBelowLower markToprightLower markBottomrightLower define ifMarks : StdAnchorGroup markAboveCap markBelowLower markToprightCap markBottomrightLower ### Necessary macros # Remap Glyph's methods to macros in order to simplify writing define-macro set-width : syntax-rules `[set-width @::args] {'.syntactic-closure' `[currentGlyph.set-width @::args] env} define-macro start-from : syntax-rules `[start-from @::args] {'.syntactic-closure' `[currentGlyph.start-from @::args] env} define-macro line-to : syntax-rules `[line-to @::args] {'.syntactic-closure' `[currentGlyph.line-to @::args] env} define-macro curve-to : syntax-rules `[curve-to @::args] {'.syntactic-closure' `[currentGlyph.curve-to @::args] env} define-macro cubic-to : syntax-rules `[cubic-to @::args] {'.syntactic-closure' `[currentGlyph.cubic-to @::args] env} define-macro arc-hv-to : syntax-rules `[arc-hv-to @::args] {'.syntactic-closure' `[currentGlyph.arc-hv-to @::args] env} define-macro arc-vh-to : syntax-rules `[arc-vh-to @::args] {'.syntactic-closure' `[currentGlyph.arc-vh-to @::args] env} define-macro include : syntax-rules `[include @::args] {'.syntactic-closure' `[currentGlyph.include @::args] env} define-macro create-stroke : syntax-rules `[create-stroke @::args] {'.syntactic-closure' `[currentGlyph.create-stroke @::args] env} define-macro set-anchor : syntax-rules `[set-anchor @::args] {'.syntactic-closure' `[currentGlyph.set-anchor @::args] env} define-macro apply-transform : syntax-rules `[apply-transform @::args] {'.syntactic-closure' `[currentGlyph.apply-transform @::args] env} define-macro reverse-last : syntax-rules `[reverse-last @::args] {'.syntactic-closure' `[currentGlyph.reverse-last @::args] env} define-macro eject-contour : syntax-rules `[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.eject-contour @::args] env} define-macro tag-contour : syntax-rules `[tag-contour @name] {'.syntactic-closure' `(currentGlyph.contours.(currentGlyph.contours.length - 1).tag = @name) env} define-macro dont-export : syntax-rules `[dont-export] {".syntactic-closure" `[set currentGlyph.dontExport true] env} define-macro assign-unicode : syntax-rules `[assign-unicode @code] {".syntactic-closure" `[begin \\ currentGlyph.assign-unicode @code set unicodeGlyphs.(currentGlyph.unicode.((currentGlyph.unicode.length - 1))) currentGlyph ] env} # The macro [glyph-construction] creates a function which builds a glyph. define-macro glyph-construction : syntax-rules `[glyph-construction @::steps] {'.syntactic-closure' `[lambda [_args] [begin \\ local glyphArguments : fallback _args {.} local currentGlyph this currentGlyph.gizmo = globalTransform local _tag currentGlyph.defaultTag if glyphArguments.tag : set currentGlyph.defaultTag glyphArguments.tag begin @::[steps.map formOf] set currentGlyph.defaultTag _tag return nothing ]] env} ### Glyph slots and dependency profile generation (used for recursive subfonts) local dependencyProfile {.} local nTemp 0 local pickHash : if recursive then : let [h {.}] : begin foreach j [items-of recursive] : set h.(j) j * h else nothing define [create-glyph name actions] : piecewise (name && actions) : begin if (pickHash && [not pickHash.(name)]) : return nothing set dependencyProfile.(name) {} define glyphObject [new Glyph name] glyphObject.set-width WIDTH glyphList.push glyphObject glyphs.(name) = glyphObject actions.call glyphObject foreach d [items-of glyphObject.dependencies] : begin local allAliases : Object.keys glyphs :.filter ([k] -> (glyphs.(k) === glyphs.(d))) dependencyProfile.(name) = [dependencyProfile.(name).concat dependencyProfile.(d) allAliases] # process.stderr.write "\[if recursive 'Recursive ' '']Built Glyph /\(name).\n" return glyphObject true : begin local actions arguments.0 local glyphObject [new Glyph ('.temp-' + [set nTemp (nTemp + 1)])] glyphObject.set-width WIDTH actions.call glyphObject return glyphObject define [select-variant name unicode default] : begin if (pickHash && [not pickHash.(name)]) : return nothing local variant : variantSelector.(name) || default local chosenGlyph glyphs.((name + '.' + variant)) create-glyph name : glyph-construction include chosenGlyph AS_BASE if unicode : assign-unicode unicode local allAliases : Object.keys glyphs :.filter ([k] -> (glyphs.(k) === glyphs.(chosenGlyph.name))) set dependencyProfile.(name) : allAliases.concat dependencyProfile.(chosenGlyph.name) define [italic-variant name unicode] : create-glyph name : glyph-construction if (para.italicangle > 0) then : include glyphs.(name + '.italic') AS_BASE else : include glyphs.(name + '.upright') AS_BASE if unicode : assign-unicode unicode define [alias newid unicode oldid] : create-glyph newid : glyph-construction if unicode : assign-unicode unicode include glyphs.(oldid) AS_BASE set-width glyphs.(oldid).advanceWidth ### Spiro constructions # Basic knots define [g4 x y f] {.x x .y y .type 'g4' .af f} define [g2 x y f] {.x x .y y .type 'g2' .af f} define [corner x y f] {.x x .y y .type 'corner' .af f} define [flat x y f] {.x x .y y .type 'left' .af f} define [curl x y f] {.x x .y y .type 'right' .af f} define [close f] {.type 'close' .af f} define [end f] {.type 'end' .af f} define straight {.l flat .r curl} #derived knots #"ai" knots, used for left and right edges of letters `o`, and similar letters define flat.ai : if para.isItalic g4 flat define curl.ai : if para.isItalic g4 curl #directional bi-knots let directions {{.name 'up' .x 0 .y 1}, {.name 'down' .x 0 .y (-1)}, {.name 'left' .x (-1) .y 0}, {.name 'right' .x 1 .y 0}} adhensions {{.name 'start' .l 0 .r 0.01}, {.name 'mid', .l (-0.005) .r 0.005}, {.name 'end', .l (-0.01) .r 0}} knottypes {g4, g2, corner, straight} foreach [direction : items-of directions] : let [d direction] : begin foreach [knottype : items-of knottypes] : let [kt knottype] : begin set kt.(d.name) {.} foreach [adh : items-of adhensions] : let [a adh] : begin set kt.(d.name).(a.name) : lambda [x y f] : list [fallback kt.l kt] (x + d.x * a.l) (y + d.y * a.l) f [fallback kt.r kt] (x + d.x * a.r) (y + d.y * a.r) f # Aux functions define [widths l r] : lambda [] : this.set-width l r define [widths.lhs w] : widths [fallback w STROKE] 0 define [widths.rhs w] : widths 0 [fallback w STROKE] define [widths.center w] : widths ([fallback w STROKE] / 2) ([fallback w STROKE] / 2) define [heading d] : lambda [] : this.heads-to d define [widths.heading l r d] : lambda [] : begin this.set-width l r; this.heads-to d define [unimportant] : begin if (this.points && this.points.length && this.points.(this.points.length - 1)) : this.points.(this.points.length - 1).subdivided = true if (this.controlKnots && this.controlKnots.length && this.controlKnots.(this.controlKnots.length - 1)) : this.controlKnots.(this.controlKnots.length - 1).unimportant = true define [important] nothing # Interpolation pesudoknots define [afInterpolate before after args] : g4 mix before.x after.x args.rx mix before.y after.y args.ry fallback args.raf unimportant define [afInterpolateThem before after args] : begin local knots {} foreach {rx ry preserve} [items-of args.rs] : knots.push : [fallback args.ty g2] [mix before.x after.x rx] [mix before.y after.y ry] : fallback args.raf : match preserve 1 before.af 2 after.af otherwise unimportant return knots define [alsothru rx ry raf] {.type 'interpolate' .rx rx .ry ry .raf raf .af afInterpolate} define [alsothruthem rs raf ty] {.type 'interpolate' .rs rs .raf raf .ty ty .af afInterpolateThem} define [bez3 a b c d t] : (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b +3 * t * t * (1 - t) * c + t * t * t * d define [bezcontrols x1 y1 x2 y2 _samples raf ty] : begin local samples : fallback _samples 3 local tiny 0.005 local rs {} foreach j [range 1 samples] : rs.push : list bez3 0 x1 x2 1 [mix tiny (1 - tiny) (j / samples)] bez3 0 y1 y2 1 [mix tiny (1 - tiny) (j / samples)] alsothruthem rs raf ty define [bezcontrols.absolute x1 y1 x2 y2 _samples raf ty] : object [type 'interpolate'] : af : lambda [before after] : begin local samples : fallback _samples 3 local tiny 0.005 local rs {} foreach j [range 1 samples] : rs.push : g4 bez3 before.x x1 x2 after.x [mix tiny (1 - tiny) (j / samples)] bez3 before.y y1 y2 after.y [mix tiny (1 - tiny) (j / samples)] fallback raf unimportant return rs define [quadcontrols x1 y1 samples raf ty] : bezcontrols (x1 * 2 / 3) (y1 * 2 / 3) [mix 1 x1 (2 / 3)] [mix 1 y1 (2 / 3)] samples raf ty define {jhv, jvh} : let [cache {}] : begin local [build samples] : begin local hv {} local vh {} foreach [j : range 1 samples] : begin local theta : j / samples * Math.PI / 2 local c : Math.pow [Math.cos theta] (2 / SUPERNESS) local s : Math.pow [Math.sin theta] (2 / SUPERNESS) hv.push {s (1 - c)} vh.push {(1 - c) s} cache.(samples) = {.hv hv .vh vh} local [hv samples] : begin if [not cache.(samples)] : build samples return cache.(samples).hv local [vh samples] : begin if [not cache.(samples)] : build samples return cache.(samples).vh list hv vh define [archv samples notiny k raf] : alsothruthem [jhv [fallback samples 4]] raf define [arcvh samples notiny k raf] : alsothruthem [jvh [fallback samples 4]] raf define [complexThru] : begin local a : {}.slice.call arguments return {.type 'interpolate' .af [lambda [before after args] : begin \\ local ks {} foreach knot [items-of a] : ks.push [knot.af.call this before after knot] return ks ]} # Spiro construction define [flatten knots] : begin local a {} foreach p [items-of knots] : piecewise (p <@ Array) : set a : a.concat [flatten p] true : a.push p return a define [prepareSpiroKnots knots s] : begin local closed false local lastafs {} while (knots.0 && knots.0 <@ Function) : begin knots.0.call s set knots : knots.slice 1 while (knots.(knots.length - 1) && (knots.(knots.length - 1).type === 'close' || knots.(knots.length - 1).type === 'end')) : begin set closed : knots.(knots.length - 1).type === 'close' lastafs.push knots.(knots.length - 1).af set knots : knots.slice 0 (-1) set knots : flatten knots if closed : knots.push knots.0 foreach j [range 0 knots.length] : if (knots.(j) && knots.(j).type === 'interpolate') : begin set knots.(j) : knots.(j).af.call s knots.(j - 1) knots.(j + 1) knots.(j) if closed : knots.pop return {.knots [flatten knots] .closed closed .lastafs lastafs} define [dispiro] : begin local s : new SpiroExpansionContext set s.gizmo globalTransform local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots [{}.slice.call arguments 0] s foreach knot [items-of knots] : let [ty knot.type] [af knot.af] : begin set knot.af : lambda [] : begin this.set-type ty if af : af.apply this arguments libspiro.spiroToBezierOnContext knots closed s foreach af [items-of lastafs] : if af : af.call s local {.lhs lhs .rhs rhs} : s.expand CONTRAST if closed then local g : new Glyph libspiro.spiroToBezierOnContext [lhs.slice 0 (-1)] true g true local lhsContour g.contours.0 set g.contours {} libspiro.spiroToBezierOnContext [rhs.reverse :.slice 0 (-1)] true g true local rhsContour g.contours.0 set g.contours {[lhsContour.concat rhsContour]} else local g : new Glyph lhs.0.type = rhs.0.type = lhs.(lhs.length - 1).type = rhs.(rhs.length - 1).type = 'corner' libspiro.spiroToBezierOnContext [lhs.concat : rhs.reverse] true g true local r g.contours r.knots = knots return r define [spiro-outline] : let [k : {}.slice.call arguments 0] : glyph-construction local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots k this libspiro.spiroToBezierOnContext knots closed this foreach af [items-of lastafs] : if af : af.call this # contour tagging define [tagged tag fn] : lambda [_args] : begin local args : if _args [begin [local a : Object.create _args] [set a.tag tag] a] {.tag tag} return : fn.call this args ###### HERE WE GO! ### Metadata # Font names set font.name.fontFamily para.family set font.name.fontSubFamily para.style set font.name.preferredFamily para.family set font.name.preferredSubFamily para.style set font.name.uniqueSubFamily "\(para.family) \(para.style) \(para.version) (\(para.codename))" set font.name.version para.version set font.name.fullName : if (para.style != 'Regular') (para.family + ' ' + para.style) para.family set font.name.postScriptName : font.name.fullName.replace [regex ' ' 'g'] '-' set font.name.copyright para.copyright set font.name.licence para.licence # Weight, width and slantness set font.'OS/2'.usWeightClass para.weight set font.'OS/2'.bProportion 9 # Monospaced set font.'OS/2'.bWeight : 1 + para.weight / 100 set font.'OS/2'.fsSelection : [if para.isBold 32 0] + [if para.isItalic 1 0] + [if ([not para.isBold] && [not para.isItalic]) 64 0] + 128 set font.'OS/2'.sFamilyClass : 8 * 0x100 + 9 set font.post.isFixedPitch 1 set font.head.macStyle : [if para.isBold 1 0] + [if para.isItalic 2 0] # Metric metadata # Note: we use 1000upm in design, and (1000 * upmsacle)upm in production, to avoid rounding error. let [asc : 1250 * CAP / (CAP - DESCENDER)] [desc : 1250 * DESCENDER / (CAP - DESCENDER)] : begin set font.head.unitsPerEm 1000 set font.hhea.ascent asc set font.'OS/2'.usWinAscent asc set font.'OS/2'.sTypoAscender asc set font.hhea.descent desc set font.'OS/2'.usWinDescent [Math.abs desc] set font.'OS/2'.sTypoDescender desc set font.hhea.lineGap (CAP * 0.2) set font.'OS/2'.sTypoLineGap (CAP * 0.2) set font.'OS/2'.sxHeight XH set font.'OS/2'.sCapHeight CAP set font.post.italicAngle (0 - para.italicangle) # Necessary notdef glyph create-glyph '.notdef' : glyph-construction start-from SB 0 line-to SB CAP line-to RIGHTSB CAP line-to RIGHTSB 0 start-from (SB + STROKE) STROKE line-to (RIGHTSB - STROKE) STROKE line-to (RIGHTSB - STROKE) (CAP - STROKE) line-to (SB + STROKE) (CAP - STROKE) create-glyph 'space' : glyph-construction set-width WIDTH assign-unicode ' ' include eMarks # ASCII $$include 'glyphs/common-shapes.patel' $$include 'glyphs/overmarks.patel' $$include 'glyphs/latin-basic-capital.patel' $$include 'glyphs/latin-basic-lower.patel' $$include 'glyphs/numbers.patel' $$include 'glyphs/symbol-ascii.patel' # Extended $$include 'glyphs/greek.patel' $$include 'glyphs/cyrillic-basic.patel' $$include 'glyphs/latin-extend-basis.patel' $$include 'glyphs/latin-extend-decorated.patel' $$include 'glyphs/cyrillic-extended.patel' $$include 'glyphs/symbol-punctuation.patel' $$include 'glyphs/symbol-math.patel' $$include 'glyphs/symbol-letter.patel' $$include 'glyphs/symbol-geometric.patel' $$include 'glyphs/symbol-other.patel' $$include 'glyphs/autobuilds.patel' set font.glyfMap glyphs return font exports.build = buildFont