Iosevka/support/glyph.patel
2015-07-27 00:49:00 +08:00

167 lines
No EOL
6 KiB
Text

define bezierCubic2Q2 [require 'node-sfnt/lib/math/bezierCubic2Q2']
define tp [require './transform'].transformPoint
define utp [require './transform'].untransform
define Stroke [require './stroke'].Stroke
define id (
.xx 1
.yx 0
.xy 0
.yy 1
.x 0
.y 0
)
define [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j
define aFunction (.unapply [function [obj arity] [if [obj <@ Function] (obj) null]])
define [Glyph name] : begin {
set this.name name
set this.unicode ()
set this.contours ()
set this.advanceWidth 500
set this.anchors (.)
set this.gizmo (
.xx 1
.yx 0
.xy 0
.yy 1
.x 0
.y 0
)
set this.dependencies ()
return nothing
}
define Glyph.is (.unapply [function [obj arity] [if [obj <@ Glyph] (obj) null]])
define [Glyph.prototype.set-width w] : begin {
this.advanceWidth = w
return this
}
define [Glyph.prototype.assign-unicode u] : begin {
this.unicode.push : piecewise {
[[typeof u] === 'string'] : u.charCodeAt 0
true u
}
return this
}
define [Glyph.prototype.start-from x y] : begin {
this.contours.push ([tp this.gizmo (.x x .y y .onCurve true)])
return this
}
define [Glyph.prototype.line-to x y] : begin {
this.contours`[this.contours.length - 1].push [tp this.gizmo (.x x .y y .onCurve true)]
return this
}
define [Glyph.prototype.curve-control x y] : begin {
this.contours`[this.contours.length - 1].push [tp this.gizmo (.x x .y y .onCurve false)]
return this
}
define [Glyph.prototype.curve-to xc yc x y] : begin {
this.contours`[this.contours.length - 1].push [tp this.gizmo (.x xc .y yc .onCurve false)] [tp this.gizmo (.x x .y y .onCurve true)]
return this
}
define [Glyph.prototype.arc-vh-to x y kappa] : begin {
local lastContour this.contours`[this.contours.length - 1]
local lastPoint lastContour`[lastContour.length - 1]
local last : utp this.gizmo lastPoint
this.cubic-to last.x [last.y + [fallback kappa 0.618] * [y - last.y]] [x + [fallback kappa 0.618] * [last.x - x]] y x y
return this
}
define [Glyph.prototype.arc-hv-to x y kappa] : begin {
local lastContour this.contours`[this.contours.length - 1]
local lastPoint lastContour`[lastContour.length - 1]
local last : utp this.gizmo lastPoint
this.cubic-to [last.x + [fallback kappa 0.618] * [x - last.x]] last.y x [y + [fallback kappa 0.618] * [last.y - y]] x y
return this
}
define [Glyph.prototype.cubic-to x1 y1 x2 y2 x y] : begin {
local lastContour this.contours`[this.contours.length - 1]
local lastPoint lastContour`[lastContour.length - 1]
local last : utp this.gizmo lastPoint
local segments [bezierCubic2Q2 last (.x x1 .y y1) (.x x2 .y y2) (.x x .y y)]
foreach (p0 (.x xc .y yc) (.x xf .y yf)) [items-of segments] : this.curve-to xc yc xf yf
return this
}
define [Glyph.prototype.reverse-last] : begin {
this.contours.[this.contours.length - 1] = [this.contours.[this.contours.length - 1].reverse]
}
define [Glyph.prototype.put-shapes contours] : begin {
# do not double-transform
local t this.gizmo
set this.gizmo id
foreach contour [items-of contours] : begin {
this.start-from contour.0.x contour.0.y
for [local j 1] [j < contour.length] [inc j] : begin {
local point contour`j
if point.cubic [begin {
local p2 contour`[j + 1]
local p3 contour`[j + 2]
this.cubic-to point.x point.y p2.x p2.y p3.x p3.y
j = j + 2
}] [if point.onCurve [this.line-to point.x point.y] [this.curve-control point.x point.y]]
}
}
set this.gizmo t
return this
}
define [Glyph.prototype.include component copyAnchors] : begin {
local glyph : match component {
[aFunction it] : return : component.call this
[Stroke.is it] (.contours [component.to-outline 0 0])
(:: contours) (.contours contours)
otherwise component
}
local contours glyph.contours
local transform (.x 0 .y 0 .xx 1 .yy 1 .xy 0 .yx 0)
local shiftx 0
local shifty 0
if [this.anchors && glyph.anchors] : foreach markid [items-of [Object.keys this.anchors]] : begin {
local anchorThis this.anchors`markid
local anchorThat glyph.anchors`markid
if [anchorThis && [anchorThis.type === 'base' || anchorThis.mbx !== nothing && anchorThis.mby !== nothing] && anchorThat && anchorThat.type === 'mark'] : begin {
set (shiftx shifty) (
[[fallback anchorThis.mbx anchorThis.x] - anchorThat.x]
[[fallback anchorThis.mby anchorThis.y] - anchorThat.y]
)
if [anchorThat.mbx !== nothing && anchorThat.mby !== nothing] : begin {
set this.anchors`markid (
.x [anchorThis.x + anchorThat.mbx - anchorThat.x]
.y [anchorThis.y + anchorThat.mby - anchorThat.y]
.type anchorThis.type
.mbx anchorThis.mbx
.mby anchorThis.mby
)
}
}
}
set transform.x : transform.x + shiftx
set transform.y : transform.y + shifty
if contours : begin {
this.put-shapes : contours.map : function [contour] {
contour.map : function [point] : tp transform point
}
}
if [[[not contours] || copyAnchors] && glyph.anchors] : set this.anchors : let [a (.)] [anchors glyph.anchors] [keys : Object.keys glyph.anchors] : begin {
foreach k [items-of keys] [set a`k anchors`k]
* a
}
piecewise {
glyph.name : this.dependencies.push glyph.name
glyph.dependencies : this.dependencies = [this.dependencies.concat glyph.dependencies]
}
}
define [Glyph.prototype.apply-transform transform] : set this.contours : this.contours.map : function [contour] : begin {
return : contour.map : function [point] [tp transform point]
}
define [Glyph.prototype.create-stroke] : begin {
local s : new Stroke
s.gizmo = [Object.create this.gizmo]
return s
}
define [Glyph.prototype.set-anchor id type x y mbx mby] : begin {
local anchorpoint [tp this.gizmo (.x x .y y)]
local markbasepoint : if [mbx !== nothing && mby !== nothing] [tp this.gizmo (.x mbx .y mby)] (.x nothing .y nothing)
this.anchors`id = (.x anchorpoint.x .y anchorpoint.y .type type .mbx markbasepoint.x .mby markbasepoint.y)
}
exports.Glyph = Glyph