extern isFinite import './point' as Point import './transform' as : Transform && [object [transformPoint tp] [untransform utp] inverse] import './anchor' as Anchor import "./utils" as [object fallback mix ratio] define-macro xytransform : syntax-rules `[xytransform @tfm @x @y] : begin set [env.declarations.get [formOf x]].isParameter 0 set [env.declarations.get [formOf y]].isParameter 0 let [t : env.newt] `[begin \\ set @t @x set @x : @x * @tfm.xx + @y * @tfm.yx + @tfm.x set @y : @t * @tfm.xy + @y * @tfm.yy + @tfm.y ] export all : class Glyph public [new name] : begin set this.name name set this.unicode {} set this.contours {} set this.advanceWidth 500 set this.autoRefPriority 0 set this.anchors {.} set this.gizmo : Transform.Id set this.dependencies {} set this.defaultTag null return nothing static is {.unapply [function [obj arity] [if (obj <@ Glyph) {obj} null]]} public [set-width w] : begin this.advanceWidth = w return this public [assign-unicode u] : begin this.unicode.push : piecewise ([typeof u] === 'string') : u.charCodeAt 0 true u return this public [retag-contour oldtag newtag] : begin if this.contours : foreach [c : items-of this.contours] : if (c.tag === oldtag) : set c.tag newtag return this public [eject-contour tag] : begin set this.contours : this.contours.filter : lambda [c] (c.tag !== tag) return this public [depends-on glyph] : begin piecewise glyph.name : this.dependencies.push glyph.name glyph.dependencies : this.dependencies = [this.dependencies.concat glyph.dependencies] return this public [includeGeometry geom shiftx shifty] : begin if (!geom || !geom.contours) : return nothing foreach [contour : items-of geom.contours] : begin local c {} set c.tag : contour.tag || geom.tag || this.defaultTag foreach [point : items-of contour] : c.push : Point.translated point shiftx shifty this.contours.push c public [combineAnchor markid shift anchorThis anchorThat] : begin if (!anchorThis || !anchorThat || anchorThat.type !== Anchor.MARK) : return nothing if (anchorThis.type === Anchor.BASE) : begin set shift.x : anchorThis.x - anchorThat.x set shift.y : anchorThis.y - anchorThat.y if (anchorThat.mbx !== nothing && anchorThat.mby !== nothing) set this.anchors.(markid) : new Anchor * (anchorThis.x + anchorThat.mbx - anchorThat.x) * (anchorThis.y + anchorThat.mby - anchorThat.y) * Anchor.BASE : else : if (anchorThis.mbx !== nothing && anchorThis.mby !== nothing) : begin set shift.x : anchorThis.mbx - anchorThat.x set shift.y : anchorThis.mby - anchorThat.y if (anchorThat.mbx !== nothing && anchorThat.mby !== nothing) set this.anchors.(markid) : new Anchor * anchorThis.x * anchorThis.y * anchorThis.type * (anchorThis.mbx + anchorThat.mbx - anchorThat.x) * (anchorThis.mby + anchorThat.mby - anchorThat.y) public [includeGlyph glyph copyAnchors copyWidth] : begin if (glyph <@ Function) : begin throw "\(this.name): Cannot include a function using includeGlyph. Use include instead." local shift {.x 0 .y 0} if glyph.anchors : foreach { markid anchorThis } [pairs-of this.anchors] : begin local anchorThat glyph.anchors.(markid) this.combineAnchor markid shift anchorThis anchorThat this.includeGeometry glyph shift.x shift.y if ((copyAnchors || glyph.isMarkSet) && glyph.anchors) : begin foreach [k : items-of : Object.keys glyph.anchors] : begin set this.anchors.(k) glyph.anchors.(k) if (glyph.advanceWidth >= 0 && copyWidth) : set this.advanceWidth glyph.advanceWidth if glyph.name : this.dependencies.push glyph.name if glyph.dependencies : this.dependencies = [this.dependencies.concat glyph.dependencies] return this public [include component copyAnchors copyWidth] : begin piecewise (component <@ Function) : begin local t this.defaultTag if component.tag : set this.defaultTag component.tag component.call this copyAnchors copyWidth set this.defaultTag t return this (component <@ Transform) : return : this.apply-transform component copyAnchors (component <@ Array) : begin return : this.includeGlyph {.contours component} copyAnchors copyWidth true : begin return : this.includeGlyph component copyAnchors copyWidth public [apply-transform transform alsoAnchors] : begin foreach [c : items-of this.contours] : foreach [j : range 0 c.length] : set c.(j) : tp transform c.(j) if alsoAnchors : foreach key [items-of [Object.keys this.anchors]] : begin set this.anchors.(key) : Anchor.transform transform this.anchors.(key) return this public [set-anchor id type x y mbx mby] : begin xytransform this.gizmo x y if (mbx !== nothing && mby !== nothing) : then : begin xytransform this.gizmo mbx mby set this.anchors.(id) : new Anchor x y type mbx mby : else : set this.anchors.(id) : new Anchor x y type return this