define Glyph [require './support/glyph'].Glyph define Stroke [require './support/stroke'].Stroke ### 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 [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j define [exports.build para] : begin { define variantSelector para.variantSelector define font [require './empty.json'] define glyphList font.glyf define glyphs (.'.notdef' glyphList.0) define unicodeGlyphs () define globalTransform ( .xx 1 .yx [Math.tan [para.italicangle / 180 * Math.PI]] .xy 0 .yy 1 .x 0 .y 0 ) define ITALICCOR : 1 / [Math.sqrt [1 - globalTransform.yx * globalTransform.yx]] define UPWARD (.x [-ITALICCOR] .y 0) define DOWNWARD (.x ITALICCOR .y 0) define RIGHTWARD (.x globalTransform.yx .y 1) define LEFTWARD (.x [- globalTransform.yx] .y [-1]) # metrics define DESCENDER para.descender define WIDTH para.width define CAP para.cap define XH para.xheight define O para.o define OXHOOK para.oxhook define SB para.sb define HOOK para.hook define AHOOK para.ahook define SHOOK para.shook define RHOOK para.rhook define SMOOTH para.smooth define SMALLSMOOTH para.smallsmooth define STROKE para.stroke define DOTSIZE para.dotsize define PERIODSIZE para.periodsize define BARPOS para.barpos define GBARPOS para.gbarpos define FIVEBARPOS para.fivebarpos define LONGJUT para.longjut define ACCENT para.accent define ACCENTX para.accentx # derived metrics define XO : XH - O define CAPO : CAP - O define HALFSTROKE : STROKE / 2 define RIGHTSB : WIDTH - SB define MIDDLE : WIDTH / 2 define CAPMIDDLE : CAP / 2 define CAP_SMOOTH : CAP - SMOOTH define DOTRADIUS : DOTSIZE / 2 define PERIODRADIUS : PERIODSIZE / 2 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 ITALICCORS : STROKE * globalTransform.yx # style parameters define EBARPOS : para.ebarpos || BARPOS define KAPPA para.kappa define COKAPPA : 1 - KAPPA define BKAPPA : para.bkappa || KAPPA + 0.1 define CKAPPA : para.ckappa || BKAPPA define COBKAPPA : 1 - BKAPPA define KAPPA_HOOK : para.kappa_hook || BKAPPA + 0.1 define KAPPA_AHOOK : para.kappa_ahook || KAPPA_HOOK define TAILADJX : WIDTH * 0.2 define TAILADJY : XH * 0.25 define TAILADJKAPPA 0.75 define TAILADJSX : WIDTH * 0.2 define TAILADJSY 0 define TAILADJSKAPPA 0.75 define ILBALANCE : LONGJUT * 0.04 define JBALANCE : para.jbalance || HALFSTROKE + ILBALANCE define TBALANCE : para.tbalance || JBALANCE define TBALANCE2 : para.tbalance2 || TBALANCE define RBALANCE : para.rbalance || JBALANCE * 0.3 # Anchor parameters define BASE 'base' define MARK 'mark' define MARKBASE 'markbase' 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 * 0.97] .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 capitalMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below)) define bMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below)) define eMarks (.anchors (.above markAboveLower.anchors.above .below markBelowZero.anchors.below)) define pMarks (.anchors (.above markAboveLower.anchors.above .below markBelowLower.anchors.below)) define ifMarks (.anchors (.above markAboveCap.anchors.above .below markBelowLower.anchors.below)) Stroke.bindParameters para ### 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 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.'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.head.macStyle : [if para.isBold 1 0] + [if para.isItalic 2 0] ### Metric metadata # Note: we use 1000upm in design, and 4096upm in production define upmscale : fallback para.upmscale 1 set font.head.unitsPerEm : upmscale * 1000 set font.hhea.ascent : upmscale * CAP set font.'OS/2'.usWinAscent : upmscale * [CAP + CAP * 0.1] set font.'OS/2'.sTypoAscender : upmscale * CAP set font.hhea.descent : upmscale * DESCENDER set font.'OS/2'.usWinDescent : upmscale * [[Math.abs DESCENDER] + CAP * 0.1] set font.'OS/2'.sTypoDescender : upmscale * DESCENDER set font.hhea.lineGap : upmscale * CAP * 0.2 set font.'OS/2'.sTypoLineGap : upmscale * CAP * 0.2 set font.'OS/2'.sxHeight : upmscale * XH set font.post.italicAnvle : 0 - para.italicangle ### Necessary macros define-macro glyph-construction : syntax-rules { @`[glyph-construction @::steps] ('.syntactic-closure' @`[lambda [] [begin { local currentGlyph this local set-width : this.set-width.bind this local assign-unicode : lambda [code] : begin { currentGlyph.assign-unicode code set unicodeGlyphs.(currentGlyph.unicode`[currentGlyph.unicode.length - 1]) currentGlyph } local start-from : this.start-from.bind this local line-to : this.line-to.bind this local curve-to : this.curve-to.bind this local cubic-to : this.cubic-to.bind this local put-shapes : this.put-shapes.bind this local reverse-last : this.reverse-last.bind this local include : this.include.bind this local create-stroke : this.create-stroke.bind this local set-anchor : this.set-anchor.bind this this.gizmo = globalTransform this.set-width WIDTH begin @::[steps.map formOf] return nothing }]] env) } define [create-glyph name actions] : begin { console.log : "Building /" + name define glyphObject [new Glyph name] glyphList.push glyphObject glyphs`name = glyphObject actions.call glyphObject return glyphObject } define [select-variant glyphid unicode default] : begin { local variant : variantSelector`glyphid || default local chosenGlyph glyphs`[glyphid + '.' + variant] set glyphs`glyphid chosenGlyph if unicode : begin { chosenGlyph.assign-unicode unicode set unicodeGlyphs.(chosenGlyph.unicode`[chosenGlyph.unicode.length - 1]) chosenGlyph } } ###### HERE WE GO! define [xgrid p] : mix SB RIGHTSB p create-glyph 'space' : glyph-construction { set-width WIDTH assign-unicode ' ' include eMarks }