Make basic operations to produce less closures (#2477)
This commit is contained in:
parent
78b0df7e7d
commit
1c9c2e09a8
12 changed files with 307 additions and 227 deletions
|
@ -2,7 +2,7 @@ $$include '../meta/macros.ptl'
|
||||||
|
|
||||||
import [mix linreg clamp fallback boole boolePn] from "@iosevka/util"
|
import [mix linreg clamp fallback boole boolePn] from "@iosevka/util"
|
||||||
import [Transform] from "@iosevka/geometry/transform"
|
import [Transform] from "@iosevka/geometry/transform"
|
||||||
import [Interpolator WithKnotProxy] from "@iosevka/geometry/spiro-control"
|
import [FunctionInterpolator WithKnotProxy AfCombine] from "@iosevka/geometry/spiro-control"
|
||||||
import [RadicalGeometry StrokeGeometry RemoveHolesGeometry] from "@iosevka/geometry"
|
import [RadicalGeometry StrokeGeometry RemoveHolesGeometry] from "@iosevka/geometry"
|
||||||
import [CMixCoord CopyBackKnotProxy] from "@iosevka/font-kits/derived-coordinates"
|
import [CMixCoord CopyBackKnotProxy] from "@iosevka/font-kits/derived-coordinates"
|
||||||
|
|
||||||
|
@ -133,7 +133,6 @@ glyph-block CommonShapes : begin
|
||||||
local mx ((l + r) / 2)
|
local mx ((l + r) / 2)
|
||||||
currentGlyph.gizmo = [if transformShiftOnly [Transform.Id] giz]
|
currentGlyph.gizmo = [if transformShiftOnly [Transform.Id] giz]
|
||||||
include : dispiro
|
include : dispiro
|
||||||
begin [lambda : set this.gizmo currentGlyph.gizmo]
|
|
||||||
widths.rhs [fallback s Stroke]
|
widths.rhs [fallback s Stroke]
|
||||||
g4 mx d [heading Leftward]
|
g4 mx d [heading Leftward]
|
||||||
archv
|
archv
|
||||||
|
@ -168,7 +167,6 @@ glyph-block CommonShapes : begin
|
||||||
local mx ((l + r) / 2)
|
local mx ((l + r) / 2)
|
||||||
currentGlyph.gizmo = [if transformShiftOnly [Transform.Id] giz]
|
currentGlyph.gizmo = [if transformShiftOnly [Transform.Id] giz]
|
||||||
include : spiro-outline
|
include : spiro-outline
|
||||||
begin [lambda : set this.gizmo currentGlyph.gizmo]
|
|
||||||
g4 mx d
|
g4 mx d
|
||||||
archv 32 2.0
|
archv 32 2.0
|
||||||
g4 l my
|
g4 l my
|
||||||
|
@ -463,22 +461,16 @@ glyph-block CommonShapes : begin
|
||||||
local depth : v + skew0 * sw - sw
|
local depth : v + skew0 * sw - sw
|
||||||
local shallowLimit : sw / 2
|
local shallowLimit : sw / 2
|
||||||
local skew : clamp 0 (1 / 2) : skew0 + [clamp 0 shallowLimit (shallowLimit - depth)] / rad
|
local skew : clamp 0 (1 / 2) : skew0 + [clamp 0 shallowLimit (shallowLimit - depth)] / rad
|
||||||
local faf toFinish.af
|
|
||||||
if doSwash
|
local headDirection : if doSwash
|
||||||
: then : begin
|
object
|
||||||
set toFinish.af : lambda [] : begin
|
x (Contrast / [Math.hypot 1 skew] * [if dtu (-1) 1])
|
||||||
if faf : faf.apply this arguments
|
y (skew / [Math.hypot 1 skew] * [if ltr 1 (-1)])
|
||||||
if this.headsTo : this.headsTo {
|
object
|
||||||
.x (Contrast / [Math.hypot 1 skew] * [if dtu (-1) 1])
|
x (Contrast * [if dtu (-1) 1])
|
||||||
.y (skew / [Math.hypot 1 skew] * [if ltr 1 (-1)])
|
y 0
|
||||||
}
|
|
||||||
: else : begin
|
set toFinish.af : new AfCombine toFinish.af [heading headDirection]
|
||||||
set toFinish.af : lambda [] : begin
|
|
||||||
if faf : faf.apply this arguments
|
|
||||||
if this.headsTo : this.headsTo{
|
|
||||||
.x (Contrast * [if dtu (-1) 1])
|
|
||||||
.y 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create the arc knots
|
# Create the arc knots
|
||||||
local segBefore {}
|
local segBefore {}
|
||||||
|
@ -487,14 +479,14 @@ glyph-block CommonShapes : begin
|
||||||
local fraction : j / nHookSegments
|
local fraction : j / nHookSegments
|
||||||
local mixRatioAdjust : Math.max (1 / 2) : (1 / 2) + [if doSwash 1 (1 / 8)] * (mixRatio - (1 / 2))
|
local mixRatioAdjust : Math.max (1 / 2) : (1 / 2) + [if doSwash 1 (1 / 8)] * (mixRatio - (1 / 2))
|
||||||
local fractionAfter : fraction * (1 - mixRatioAdjust) / mixRatioAdjust
|
local fractionAfter : fraction * (1 - mixRatioAdjust) / mixRatioAdjust
|
||||||
local myfinal : _SuperXY ((1 - mixRatioAdjust) / mixRatioAdjust) superness
|
local myfinal : 1 - [archv.yFromX ((1 - mixRatioAdjust) / mixRatioAdjust) superness]
|
||||||
segBefore.push : g4
|
segBefore.push : g4
|
||||||
mix mx toStraight.x fraction
|
mix mx toStraight.x fraction
|
||||||
mix y toStraight.y (1 - [_SuperXY fraction superness])
|
mix y toStraight.y [archv.yFromX fraction superness]
|
||||||
begin unimportant
|
begin unimportant
|
||||||
segAfter.push : g4
|
segAfter.push : g4
|
||||||
mix mx toFinish.x fraction
|
mix mx toFinish.x fraction
|
||||||
mix y toFinish.y ((1 - [_SuperXY fractionAfter superness]) / (1 - myfinal))
|
mix y toFinish.y ([archv.yFromX fractionAfter superness] / (1 - myfinal))
|
||||||
begin unimportant
|
begin unimportant
|
||||||
|
|
||||||
if isStart
|
if isStart
|
||||||
|
@ -525,7 +517,7 @@ glyph-block CommonShapes : begin
|
||||||
local-parameter : noSwash -- false
|
local-parameter : noSwash -- false
|
||||||
local-parameter : o -- O
|
local-parameter : o -- O
|
||||||
local args : object [yRef y] sw swTerminal isTail noSwash [overshoot o]
|
local args : object [yRef y] sw swTerminal isTail noSwash [overshoot o]
|
||||||
return : WithKnotProxy [hookProxy args] : Interpolator hookStartBlender args
|
return : WithKnotProxy [hookProxy args] : new FunctionInterpolator hookStartBlender args
|
||||||
|
|
||||||
glyph-block-export hookend
|
glyph-block-export hookend
|
||||||
define flex-params [hookend] : begin
|
define flex-params [hookend] : begin
|
||||||
|
@ -536,7 +528,7 @@ glyph-block CommonShapes : begin
|
||||||
local-parameter : noSwash -- false
|
local-parameter : noSwash -- false
|
||||||
local-parameter : o -- O
|
local-parameter : o -- O
|
||||||
local args : object [yRef y] sw swTerminal isTail noSwash [overshoot o]
|
local args : object [yRef y] sw swTerminal isTail noSwash [overshoot o]
|
||||||
return : WithKnotProxy [hookProxy args] : Interpolator hookEndBlender args
|
return : WithKnotProxy [hookProxy args] : new FunctionInterpolator hookEndBlender args
|
||||||
|
|
||||||
glyph-block-export arch
|
glyph-block-export arch
|
||||||
define arch : namespace
|
define arch : namespace
|
||||||
|
@ -638,7 +630,8 @@ glyph-block CommonShapes : begin
|
||||||
local-parameter : blendPre -- [if anglePre nothing [arcvh]]
|
local-parameter : blendPre -- [if anglePre nothing [arcvh]]
|
||||||
local-parameter : blendPost -- [if anglePost nothing [archv]]
|
local-parameter : blendPost -- [if anglePost nothing [archv]]
|
||||||
local args : object [lhs true] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost anglePre anglePost
|
local args : object [lhs true] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost anglePre anglePost
|
||||||
return : WithKnotProxy [archBlenderProxy args] : Interpolator archBlender args
|
return : WithKnotProxy [archBlenderProxy args]
|
||||||
|
new FunctionInterpolator archBlender args
|
||||||
|
|
||||||
export : define flex-params [rhs] : begin
|
export : define flex-params [rhs] : begin
|
||||||
local-parameter : y
|
local-parameter : y
|
||||||
|
@ -655,7 +648,8 @@ glyph-block CommonShapes : begin
|
||||||
local-parameter : blendPre -- [if anglePre nothing [arcvh]]
|
local-parameter : blendPre -- [if anglePre nothing [arcvh]]
|
||||||
local-parameter : blendPost -- [if anglePost nothing [archv]]
|
local-parameter : blendPost -- [if anglePost nothing [archv]]
|
||||||
local args : object [lhs false] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost anglePre anglePost
|
local args : object [lhs false] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost anglePre anglePost
|
||||||
return : WithKnotProxy [archBlenderProxy args] : Interpolator archBlender args
|
return : WithKnotProxy [archBlenderProxy args]
|
||||||
|
new FunctionInterpolator archBlender args
|
||||||
|
|
||||||
foreach side {lhs rhs} : begin
|
foreach side {lhs rhs} : begin
|
||||||
set side.centerAt : object
|
set side.centerAt : object
|
||||||
|
|
|
@ -4,7 +4,7 @@ import [mix fallback] from "@iosevka/util"
|
||||||
import [SpiroPenGeometry] from "@iosevka/geometry"
|
import [SpiroPenGeometry] from "@iosevka/geometry"
|
||||||
import [Vec2] from "@iosevka/geometry/point"
|
import [Vec2] from "@iosevka/geometry/point"
|
||||||
import [Box] from "@iosevka/geometry/box"
|
import [Box] from "@iosevka/geometry/box"
|
||||||
import [Interpolator] from "@iosevka/geometry/spiro-control"
|
import [AfBase FunctionInterpolator] from "@iosevka/geometry/spiro-control"
|
||||||
import [PenKnotCollector] from "@iosevka/geometry/spiro-pen-expand"
|
import [PenKnotCollector] from "@iosevka/geometry/spiro-pen-expand"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
@ -61,8 +61,13 @@ glyph-block LetterLike-Fraktur-Common : begin
|
||||||
|
|
||||||
# Directive to change the profile
|
# Directive to change the profile
|
||||||
glyph-block-export change-pen
|
glyph-block-export change-pen
|
||||||
define [change-pen newPen] : function : begin
|
define [change-pen newPen] : new AfChangePen newPen
|
||||||
this.setProfile : newPen.getPenShape this.gizmo
|
|
||||||
|
class AfChangePen : inherits AfBase
|
||||||
|
public [new newPen] : begin
|
||||||
|
this.newPen = newPen
|
||||||
|
public [applyTo target] : begin
|
||||||
|
target.setProfile : this.newPen.getPenShape target.gizmo
|
||||||
|
|
||||||
# A pen profile describes a virtual flat-tip pen. We use a 45-degree arrangement to
|
# A pen profile describes a virtual flat-tip pen. We use a 45-degree arrangement to
|
||||||
# simplify the math.
|
# simplify the math.
|
||||||
|
@ -152,26 +157,26 @@ glyph-block LetterLike-Fraktur-Common : begin
|
||||||
export : define DepthX : 1 * DecoSizeX
|
export : define DepthX : 1 * DecoSizeX
|
||||||
export : define LTDecoSize : 0.75 * DecoSizeX
|
export : define LTDecoSize : 0.75 * DecoSizeX
|
||||||
|
|
||||||
export : define [h o] : Interpolator hBlender [object o]
|
export : define [h o] : new FunctionInterpolator hBlender [object o]
|
||||||
define [hBlender before after args] : begin
|
define [hBlender before after args] : begin
|
||||||
return : list
|
return : list
|
||||||
g2 [mix before.x after.x 0.375] (after.y + [fallback args.o 0])
|
g2 [mix before.x after.x 0.375] (after.y + [fallback args.o 0])
|
||||||
g2 [mix before.x after.x 0.625] (before.y - [fallback args.o 0])
|
g2 [mix before.x after.x 0.625] (before.y - [fallback args.o 0])
|
||||||
|
|
||||||
export : define [vc waveDepth] : Interpolator vcBlender [object waveDepth]
|
export : define [vc waveDepth] : new FunctionInterpolator vcBlender [object waveDepth]
|
||||||
define [vcBlender before after args] : begin
|
define [vcBlender before after args] : begin
|
||||||
local [object waveDepth] args
|
local [object waveDepth] args
|
||||||
return : list
|
return : list
|
||||||
g2 (before.x + 0.5 * waveDepth) [mix before.y after.y 0.375]
|
g2 (before.x + 0.5 * waveDepth) [mix before.y after.y 0.375]
|
||||||
g2 (after.x - 0.5 * waveDepth) [mix before.y after.y 0.625]
|
g2 (after.x - 0.5 * waveDepth) [mix before.y after.y 0.625]
|
||||||
|
|
||||||
export : define [v] : Interpolator vBlender
|
export : define [v] : new FunctionInterpolator vBlender
|
||||||
define [vBlender before after] : begin
|
define [vBlender before after] : begin
|
||||||
return : list
|
return : list
|
||||||
g2 after.x [mix before.y after.y 0.375]
|
g2 after.x [mix before.y after.y 0.375]
|
||||||
g2 before.x [mix before.y after.y 0.625]
|
g2 before.x [mix before.y after.y 0.625]
|
||||||
|
|
||||||
export : define [vDistAfter d] : Interpolator vDistAfterBlender [object d]
|
export : define [vDistAfter d] : new FunctionInterpolator vDistAfterBlender [object d]
|
||||||
define [vDistAfterBlender before after args] : begin
|
define [vDistAfterBlender before after args] : begin
|
||||||
return : list
|
return : list
|
||||||
g2 after.x [mix before.y after.y 0.375]
|
g2 after.x [mix before.y after.y 0.375]
|
||||||
|
|
|
@ -166,7 +166,7 @@ glyph-block Letter-Latin-Lower-E : begin
|
||||||
dispiro
|
dispiro
|
||||||
g4 lastKnot.x lastKnot.y [widths.rhs fine]
|
g4 lastKnot.x lastKnot.y [widths.rhs fine]
|
||||||
g4 (lastKnot.x - beginCoSlope * TINY) (lastKnot.y - TINY)
|
g4 (lastKnot.x - beginCoSlope * TINY) (lastKnot.y - TINY)
|
||||||
alsoThruThem.fromTWithOffset {(1/3) (2/3)} : object
|
alsoThruThem.computed { (1/3) (2/3) } : object
|
||||||
rx : function [rt] rt
|
rx : function [rt] rt
|
||||||
deltaX : function [rt] 0
|
deltaX : function [rt] 0
|
||||||
ry : function [rt] : 1/24 + rt + (1/2 - rt) * (3/8)
|
ry : function [rt] : 1/24 + rt + (1/2 - rt) * (3/8)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
$$include '../meta/macros.ptl'
|
$$include '../meta/macros.ptl'
|
||||||
|
|
||||||
import [mix clamp fallback] from "@iosevka/util"
|
import [mix clamp fallback] from "@iosevka/util"
|
||||||
import [Interpolator] from "@iosevka/geometry/spiro-control"
|
import [FunctionInterpolator] from "@iosevka/geometry/spiro-control"
|
||||||
import [Dotless CvDecompose] from "@iosevka/glyph/relation"
|
import [Dotless CvDecompose] from "@iosevka/glyph/relation"
|
||||||
import [RightDependentTrigger RightDependentLink DependentSelector] from "@iosevka/glyph/relation"
|
import [RightDependentTrigger RightDependentLink DependentSelector] from "@iosevka/glyph/relation"
|
||||||
import [DesignParameters] from "../meta/aesthetics.mjs"
|
import [DesignParameters] from "../meta/aesthetics.mjs"
|
||||||
|
@ -211,7 +211,7 @@ glyph-block Letter-Shared-Shapes : begin
|
||||||
local-parameter : swBefore -- Stroke
|
local-parameter : swBefore -- Stroke
|
||||||
local-parameter : terminalSlopeAdj -- 0.5
|
local-parameter : terminalSlopeAdj -- 0.5
|
||||||
|
|
||||||
return : Interpolator normalBlender
|
return : new FunctionInterpolator normalBlender
|
||||||
object [flat false] fine bottom xOuter x2 y2 yLoopTop swBefore terminalSlopeAdj
|
object [flat false] fine bottom xOuter x2 y2 yLoopTop swBefore terminalSlopeAdj
|
||||||
|
|
||||||
export : define flex-params [f] : begin
|
export : define flex-params [f] : begin
|
||||||
|
@ -223,7 +223,7 @@ glyph-block Letter-Shared-Shapes : begin
|
||||||
local-parameter : swBefore -- Stroke
|
local-parameter : swBefore -- Stroke
|
||||||
local-parameter : terminalSlopeAdj -- 0.5
|
local-parameter : terminalSlopeAdj -- 0.5
|
||||||
|
|
||||||
return : Interpolator normalBlender
|
return : new FunctionInterpolator normalBlender
|
||||||
object [flat true] fine bottom xOuter x2 yLoopTop swBefore terminalSlopeAdj
|
object [flat true] fine bottom xOuter x2 yLoopTop swBefore terminalSlopeAdj
|
||||||
|
|
||||||
glyph-block-export HCurlyTail
|
glyph-block-export HCurlyTail
|
||||||
|
|
|
@ -177,10 +177,6 @@ export : define [calculateMetrics para] : begin
|
||||||
define GeometryStroke : AdviceStroke 4
|
define GeometryStroke : AdviceStroke 4
|
||||||
define ShoulderFine : Math.min (Stroke * para.shoulderFineMin) [AdviceStroke 16]
|
define ShoulderFine : Math.min (Stroke * para.shoulderFineMin) [AdviceStroke 16]
|
||||||
|
|
||||||
define [_SuperXY x superness] : Math.pow
|
|
||||||
1 - [Math.pow x [fallback superness DesignParameters.superness]]
|
|
||||||
1 / [fallback superness DesignParameters.superness]
|
|
||||||
|
|
||||||
define [AdviceGlottalStopArchDepth y sign] : begin
|
define [AdviceGlottalStopArchDepth y sign] : begin
|
||||||
return : ((y - Stroke) * 0.24 + Stroke * 0.625) + sign * TanSlope * SmoothAdjust
|
return : ((y - Stroke) * 0.24 + Stroke * 0.625) + sign * TanSlope * SmoothAdjust
|
||||||
|
|
||||||
|
@ -199,7 +195,7 @@ export : define [calculateMetrics para] : begin
|
||||||
EssUpper EssLower EssQuestion HalfStroke RightSB Middle DotRadius PeriodRadius SideJut
|
EssUpper EssLower EssQuestion HalfStroke RightSB Middle DotRadius PeriodRadius SideJut
|
||||||
ArchDepthA ArchDepthB SmallArchDepthA SmallArchDepthB CorrectionOMidX CorrectionOMidS
|
ArchDepthA ArchDepthB SmallArchDepthA SmallArchDepthB CorrectionOMidX CorrectionOMidS
|
||||||
compositeBaseAnchors AdviceStroke AdviceStroke2 OverlayStroke OperatorStroke GeometryStroke
|
compositeBaseAnchors AdviceStroke AdviceStroke2 OverlayStroke OperatorStroke GeometryStroke
|
||||||
ShoulderFine _SuperXY AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf
|
ShoulderFine AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf
|
||||||
SmoothAdjust MidJutSide MidJutCenter YSmoothMidR YSmoothMidL HSwToV NarrowUnicodeT
|
SmoothAdjust MidJutSide MidJutCenter YSmoothMidR YSmoothMidL HSwToV NarrowUnicodeT
|
||||||
WideUnicodeT VERY-FAR TINY]
|
WideUnicodeT VERY-FAR TINY]
|
||||||
|
|
||||||
|
|
|
@ -284,10 +284,10 @@ define-macro glyph-block : syntax-rules
|
||||||
WideWidth2 WideWidth3 WideWidth4 EssUpper EssLower EssQuestion HalfStroke RightSB
|
WideWidth2 WideWidth3 WideWidth4 EssUpper EssLower EssQuestion HalfStroke RightSB
|
||||||
Middle DotRadius PeriodRadius SideJut ArchDepthA ArchDepthB SmallArchDepthA
|
Middle DotRadius PeriodRadius SideJut ArchDepthA ArchDepthB SmallArchDepthA
|
||||||
SmallArchDepthB CorrectionOMidX CorrectionOMidS AdviceStroke AdviceStroke2
|
SmallArchDepthB CorrectionOMidX CorrectionOMidS AdviceStroke AdviceStroke2
|
||||||
OverlayStroke OperatorStroke GeometryStroke ShoulderFine _SuperXY
|
OverlayStroke OperatorStroke GeometryStroke ShoulderFine AdviceGlottalStopArchDepth
|
||||||
AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust
|
StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust MidJutSide MidJutCenter
|
||||||
MidJutSide MidJutCenter compositeBaseAnchors YSmoothMidR YSmoothMidL HSwToV
|
compositeBaseAnchors YSmoothMidR YSmoothMidL HSwToV NarrowUnicodeT WideUnicodeT
|
||||||
NarrowUnicodeT WideUnicodeT VERY-FAR TINY]
|
VERY-FAR TINY]
|
||||||
define spiroFnImports `[g4 g2 corner flat curl virt close end straight g2c cg2 flatc ccurl
|
define spiroFnImports `[g4 g2 corner flat curl virt close end straight g2c cg2 flatc ccurl
|
||||||
widths disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
|
widths disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
|
||||||
quadControls archv arcvh dispiro spiro-outline spiro-collect]
|
quadControls archv arcvh dispiro spiro-outline spiro-collect]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { DiSpiroGeometry, SpiroGeometry } from "@iosevka/geometry";
|
import { DiSpiroGeometry, SpiroGeometry } from "@iosevka/geometry";
|
||||||
import {
|
import {
|
||||||
Interpolator,
|
AfBase,
|
||||||
|
InterpolatorBase,
|
||||||
SpiroFlattener,
|
SpiroFlattener,
|
||||||
TerminateInstruction,
|
TerminateInstruction,
|
||||||
UserCloseKnotPair,
|
UserCloseKnotPair,
|
||||||
|
@ -167,12 +168,21 @@ export function SetupBuilders(bindings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AfSetWidths extends AfBase {
|
||||||
|
constructor(l, r) {
|
||||||
|
super();
|
||||||
|
this.l = l;
|
||||||
|
this.r = r;
|
||||||
|
}
|
||||||
|
applyTo(target) {
|
||||||
|
target.setWidth(this.l, this.r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function widths(l, r) {
|
function widths(l, r) {
|
||||||
if (!isFinite(l)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(l)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(r)) throw new TypeError("NaN detected for right width");
|
if (!isFinite(r)) throw new TypeError("NaN detected for right width");
|
||||||
return function () {
|
return new AfSetWidths(l, r);
|
||||||
if (this.setWidth) this.setWidth(l, r);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
widths.lhs = function (w) {
|
widths.lhs = function (w) {
|
||||||
w = fallback(w, Stroke);
|
w = fallback(w, Stroke);
|
||||||
|
@ -190,154 +200,172 @@ export function SetupBuilders(bindings) {
|
||||||
return widths(w / 2, w / 2);
|
return widths(w / 2, w / 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AfHeading extends AfBase {
|
||||||
|
constructor(d) {
|
||||||
|
super();
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
applyTo(target) {
|
||||||
|
target.headsTo(this.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
function heading(d) {
|
function heading(d) {
|
||||||
if (!isFinite(d.x) || !isFinite(d.y))
|
if (!isFinite(d.x) || !isFinite(d.y))
|
||||||
throw new TypeError("NaN detected for heading directions");
|
throw new TypeError("NaN detected for heading directions");
|
||||||
return function () {
|
return new AfHeading(d);
|
||||||
if (this.headsTo) this.headsTo(d);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AfWidthsHeading extends AfBase {
|
||||||
|
constructor(l, r, d) {
|
||||||
|
super();
|
||||||
|
this.l = l;
|
||||||
|
this.r = r;
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
applyTo(target) {
|
||||||
|
target.setWidth(this.l, this.r);
|
||||||
|
target.headsTo(this.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
widths.heading = function (l, r, d) {
|
widths.heading = function (l, r, d) {
|
||||||
if (!isFinite(l)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(l)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(r)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(r)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(d.x) || !isFinite(d.y))
|
if (!isFinite(d.x) || !isFinite(d.y))
|
||||||
throw new TypeError("NaN detected for heading directions");
|
throw new TypeError("NaN detected for heading directions");
|
||||||
return function () {
|
return new AfWidthsHeading(l, r, d);
|
||||||
if (this.setWidth) this.setWidth(l, r);
|
|
||||||
if (this.headsTo) this.headsTo(d);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
widths.lhs.heading = function (w, d) {
|
widths.lhs.heading = function (w, d) {
|
||||||
w = fallback(w, Stroke);
|
w = fallback(w, Stroke);
|
||||||
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(d.x) || !isFinite(d.y))
|
if (!isFinite(d.x) || !isFinite(d.y))
|
||||||
throw new TypeError("NaN detected for heading directions");
|
throw new TypeError("NaN detected for heading directions");
|
||||||
return function () {
|
return new AfWidthsHeading(w, 0, d);
|
||||||
if (this.setWidth) this.setWidth(w, 0);
|
|
||||||
if (this.headsTo) this.headsTo(d);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
widths.rhs.heading = function (w, d) {
|
widths.rhs.heading = function (w, d) {
|
||||||
w = fallback(w, Stroke);
|
w = fallback(w, Stroke);
|
||||||
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(d.x) || !isFinite(d.y))
|
if (!isFinite(d.x) || !isFinite(d.y))
|
||||||
throw new TypeError("NaN detected for heading directions");
|
throw new TypeError("NaN detected for heading directions");
|
||||||
return function () {
|
return new AfWidthsHeading(0, w, d);
|
||||||
if (this.setWidth) this.setWidth(0, w);
|
|
||||||
if (this.headsTo) this.headsTo(d);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
widths.center.heading = function (w, d) {
|
widths.center.heading = function (w, d) {
|
||||||
w = fallback(w, Stroke);
|
w = fallback(w, Stroke);
|
||||||
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
if (!isFinite(w)) throw new TypeError("NaN detected for left width");
|
||||||
if (!isFinite(d.x) || !isFinite(d.y))
|
if (!isFinite(d.x) || !isFinite(d.y))
|
||||||
throw new TypeError("NaN detected for heading directions");
|
throw new TypeError("NaN detected for heading directions");
|
||||||
return function () {
|
return new AfWidthsHeading(w / 2, w / 2, d);
|
||||||
if (this.setWidth) this.setWidth(w / 2, w / 2);
|
|
||||||
if (this.headsTo) this.headsTo(d);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AfDisableContrast extends AfBase {
|
||||||
|
applyTo(target) {
|
||||||
|
target.setContrast(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
function disableContrast() {
|
function disableContrast() {
|
||||||
return function () {
|
return new AfDisableContrast();
|
||||||
if (this.setContrast) this.setContrast(1);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function unimportant() {
|
|
||||||
if (this.setUnimportant) this.setUnimportant(1);
|
|
||||||
}
|
|
||||||
function important() {
|
|
||||||
return void 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function afInterpolate(before, after, args) {
|
class AfUnimportant extends AfBase {
|
||||||
return g4(
|
applyTo(target) {
|
||||||
mix(before.x, after.x, args.rx),
|
target.setUnimportant();
|
||||||
mix(before.y, after.y, args.ry),
|
}
|
||||||
fallback(args.raf, unimportant),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
function afInterpolateDelta(before, after, args) {
|
const unimportant = new AfUnimportant();
|
||||||
return g4(
|
|
||||||
mix(before.x, after.x, args.rx) + args.deltaX,
|
class AfImportant extends AfBase {
|
||||||
mix(before.y, after.y, args.ry) + args.deltaY,
|
applyTo(target) {
|
||||||
fallback(args.raf, unimportant),
|
target.setImportant();
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
function afInterpolateG2(before, after, args) {
|
const important = new AfImportant();
|
||||||
return g2(
|
|
||||||
mix(before.x, after.x, args.rx),
|
/// Simple (single mix) interpolator
|
||||||
mix(before.y, after.y, args.ry),
|
class SimpleMixInterpolator extends InterpolatorBase {
|
||||||
fallback(args.raf, unimportant),
|
constructor(ty, rx, ry, deltaX, deltaY, raf) {
|
||||||
);
|
super();
|
||||||
}
|
this.ty = ty;
|
||||||
function afInterpolateThem(before, after, args) {
|
this.rx = rx;
|
||||||
let innerKnots = [];
|
this.ry = ry;
|
||||||
for (const [rx, ry, rt] of args.rs) {
|
this.deltaX = deltaX;
|
||||||
innerKnots.push(
|
this.deltaY = deltaY;
|
||||||
fallback(args.ty, g2)(
|
this.raf = fallback(raf, unimportant);
|
||||||
mix(before.x, after.x, rx),
|
}
|
||||||
mix(before.y, after.y, ry),
|
resolveInterpolation(before, after) {
|
||||||
args.raf && args.raf.blend && rt !== void 0
|
return this.ty(
|
||||||
? args.raf.blend(rt)
|
mix(before.x, after.x, this.rx) + this.deltaX,
|
||||||
: args.raf
|
mix(before.y, after.y, this.ry) + this.deltaY,
|
||||||
? args.raf
|
this.raf,
|
||||||
: unimportant,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return innerKnots;
|
|
||||||
}
|
|
||||||
function afInterpolateThemWithDelta(before, after, args) {
|
|
||||||
let innerKnots = [];
|
|
||||||
for (const [rx, ry, deltaX, deltaY, rt] of args.rs) {
|
|
||||||
innerKnots.push(
|
|
||||||
fallback(args.ty, g2)(
|
|
||||||
mix(before.x, after.x, rx) + deltaX,
|
|
||||||
mix(before.y, after.y, ry) + deltaY,
|
|
||||||
args.raf && args.raf.blend && rt !== void 0
|
|
||||||
? args.raf.blend(rt)
|
|
||||||
: args.raf
|
|
||||||
? args.raf
|
|
||||||
: unimportant,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return innerKnots;
|
|
||||||
}
|
|
||||||
function afInterpolateThemFromTWithDelta(before, after, args) {
|
|
||||||
let innerKnots = [];
|
|
||||||
for (const rt of args.rs) {
|
|
||||||
innerKnots.push(
|
|
||||||
fallback(args.ty, g2)(
|
|
||||||
mix(before.x, after.x, args.raf.rx(rt)) + args.raf.deltaX(rt),
|
|
||||||
mix(before.y, after.y, args.raf.ry(rt)) + args.raf.deltaY(rt),
|
|
||||||
args.raf.modifier(rt),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return innerKnots;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function alsoThru(rx, ry, raf) {
|
function alsoThru(rx, ry, raf) {
|
||||||
return Interpolator(afInterpolate, { rx, ry, raf });
|
return new SimpleMixInterpolator(g4, rx, ry, 0, 0, raf);
|
||||||
}
|
}
|
||||||
alsoThru.withOffset = function (rx, ry, deltaX, deltaY, raf) {
|
alsoThru.withOffset = function (rx, ry, deltaX, deltaY, raf) {
|
||||||
return Interpolator(afInterpolateDelta, { rx, ry, deltaX, deltaY, raf });
|
return new SimpleMixInterpolator(g4, rx, ry, deltaX, deltaY, raf);
|
||||||
};
|
};
|
||||||
alsoThru.g2 = function (rx, ry, raf) {
|
alsoThru.g2 = function (rx, ry, raf) {
|
||||||
return Interpolator(afInterpolateG2, { rx, ry, raf });
|
return new SimpleMixInterpolator(g2, rx, ry, 0, 0, raf);
|
||||||
};
|
};
|
||||||
function alsoThruThem(rs, raf, ty) {
|
|
||||||
return Interpolator(afInterpolateThem, { rs, raf, ty });
|
/// Multi-mix interpolator
|
||||||
|
class MultiMixInterpolator extends InterpolatorBase {
|
||||||
|
constructor(rs, raf, ty) {
|
||||||
|
super();
|
||||||
|
this.rs = rs;
|
||||||
|
this.raf = raf;
|
||||||
|
this.ty = fallback(ty, g2);
|
||||||
|
}
|
||||||
|
resolveInterpolation(before, after) {
|
||||||
|
let innerKnots = [];
|
||||||
|
for (const [rx, ry, rt] of this.rs) {
|
||||||
|
const x = mix(before.x, after.x, rx);
|
||||||
|
const y = mix(before.y, after.y, ry);
|
||||||
|
const af =
|
||||||
|
this.raf && this.raf.blend && rt !== void 0
|
||||||
|
? this.raf.blend(rt)
|
||||||
|
: this.raf
|
||||||
|
? this.raf
|
||||||
|
: unimportant;
|
||||||
|
innerKnots.push(this.ty(x, y, af));
|
||||||
|
}
|
||||||
|
return innerKnots;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
alsoThruThem.withOffset = function (rs, raf, ty) {
|
function alsoThruThem(rs, raf, ty) {
|
||||||
return Interpolator(afInterpolateThemWithDelta, { rs, raf, ty });
|
return new MultiMixInterpolator(rs, raf, ty);
|
||||||
};
|
}
|
||||||
alsoThruThem.fromTWithOffset = function (rs, raf, ty) {
|
|
||||||
return Interpolator(afInterpolateThemFromTWithDelta, { rs, raf, ty });
|
/// Multi-mix interpolator that use function set to compute proportion/deltas
|
||||||
|
class MultiMixComputeInterpolator extends InterpolatorBase {
|
||||||
|
constructor(rs, raf, ty) {
|
||||||
|
super();
|
||||||
|
this.rs = rs;
|
||||||
|
this.raf = raf;
|
||||||
|
this.ty = fallback(ty, g2);
|
||||||
|
}
|
||||||
|
resolveInterpolation(before, after) {
|
||||||
|
let innerKnots = [];
|
||||||
|
for (const rt of this.rs) {
|
||||||
|
innerKnots.push(
|
||||||
|
this.ty(
|
||||||
|
mix(before.x, after.x, this.raf.rx(rt)) + this.raf.deltaX(rt),
|
||||||
|
mix(before.y, after.y, this.raf.ry(rt)) + this.raf.deltaY(rt),
|
||||||
|
this.raf.modifier(rt),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return innerKnots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alsoThruThem.computed = function (rs, raf, ty) {
|
||||||
|
return new MultiMixComputeInterpolator(rs, raf, ty);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Bezier control interpolator
|
||||||
|
|
||||||
function bezControlsImpl(x1, y1, x2, y2, samples, raf, ty) {
|
function bezControlsImpl(x1, y1, x2, y2, samples, raf, ty) {
|
||||||
let rs = [];
|
let rs = [];
|
||||||
for (let j = 1; j < samples; j = j + 1)
|
for (let j = 1; j < samples; j = j + 1)
|
||||||
|
@ -362,44 +390,64 @@ export function SetupBuilders(bindings) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let DEFAULT_STEPS = 6;
|
// ArcHV and ArcVH interpolators
|
||||||
let [buildHV, buildVH] = (function (cache) {
|
class ArcHvInterpolator extends InterpolatorBase {
|
||||||
function build(samples, _superness) {
|
constructor(steps, superness) {
|
||||||
const superness = fallback(_superness, Superness);
|
super();
|
||||||
let hv = [];
|
this.steps = steps;
|
||||||
let vh = [];
|
this.superness = superness;
|
||||||
for (let j = 1; j < samples; j = j + 1) {
|
}
|
||||||
const theta = (((j + 1) / (samples + 2)) * Math.PI) / 2;
|
resolveInterpolation(before, after) {
|
||||||
const c = Math.pow(Math.cos(theta), 2 / superness);
|
let innerKnots = [];
|
||||||
const s = Math.pow(Math.sin(theta), 2 / superness);
|
for (let j = 1; j < this.steps; j++) {
|
||||||
hv.push([s, 1 - c]);
|
const theta = (((j + 1) / (this.steps + 2)) * Math.PI) / 2;
|
||||||
vh.push([1 - c, s]);
|
const c = Math.pow(Math.cos(theta), 2 / this.superness);
|
||||||
|
const s = Math.pow(Math.sin(theta), 2 / this.superness);
|
||||||
|
const x = mix(before.x, after.x, s);
|
||||||
|
const y = mix(before.y, after.y, 1 - c);
|
||||||
|
innerKnots.push(g2(x, y, unimportant));
|
||||||
}
|
}
|
||||||
return { hv, vh: vh };
|
return innerKnots;
|
||||||
}
|
}
|
||||||
function buildHVImpl(samples, _superness) {
|
}
|
||||||
if (_superness) return build(samples, _superness).hv;
|
class ArcVhInterpolator extends InterpolatorBase {
|
||||||
if (!cache[samples]) cache[samples] = build(samples, _superness);
|
constructor(steps, superness) {
|
||||||
return cache[samples].hv;
|
super();
|
||||||
|
this.steps = steps;
|
||||||
|
this.superness = superness;
|
||||||
}
|
}
|
||||||
function buildVHImpl(samples, _superness) {
|
resolveInterpolation(before, after) {
|
||||||
if (_superness) return build(samples, _superness).vh;
|
let innerKnots = [];
|
||||||
if (!cache[samples]) cache[samples] = build(samples, _superness);
|
for (let j = 1; j < this.steps; j++) {
|
||||||
return cache[samples].vh;
|
const theta = (((j + 1) / (this.steps + 2)) * Math.PI) / 2;
|
||||||
|
const c = Math.pow(Math.cos(theta), 2 / this.superness);
|
||||||
|
const s = Math.pow(Math.sin(theta), 2 / this.superness);
|
||||||
|
const x = mix(before.x, after.x, 1 - c);
|
||||||
|
const y = mix(before.y, after.y, s);
|
||||||
|
innerKnots.push(g2(x, y, unimportant));
|
||||||
|
}
|
||||||
|
return innerKnots;
|
||||||
}
|
}
|
||||||
return [buildHVImpl, buildVHImpl];
|
}
|
||||||
})([]);
|
|
||||||
|
let DEFAULT_STEPS = 6;
|
||||||
function archv(samples, superness) {
|
function archv(samples, superness) {
|
||||||
return alsoThruThem(buildHV(fallback(samples, DEFAULT_STEPS), superness));
|
return new ArcHvInterpolator(
|
||||||
|
fallback(samples, DEFAULT_STEPS),
|
||||||
|
fallback(superness, Superness),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
archv.superness = function (s) {
|
archv.superness = function (s) {
|
||||||
return archv(DEFAULT_STEPS, s);
|
return new ArcHvInterpolator(DEFAULT_STEPS, s);
|
||||||
};
|
};
|
||||||
function arcvh(samples, superness) {
|
function arcvh(samples, superness) {
|
||||||
return alsoThruThem(buildVH(fallback(samples, DEFAULT_STEPS), superness));
|
return new ArcVhInterpolator(
|
||||||
|
fallback(samples, DEFAULT_STEPS),
|
||||||
|
fallback(superness, Superness),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
arcvh.superness = function (s) {
|
arcvh.superness = function (s) {
|
||||||
return arcvh(DEFAULT_STEPS, s);
|
return new ArcVhInterpolator(DEFAULT_STEPS, s);
|
||||||
};
|
};
|
||||||
archv.yFromX = function (px, _s) {
|
archv.yFromX = function (px, _s) {
|
||||||
const s = fallback(_s, Superness);
|
const s = fallback(_s, Superness);
|
||||||
|
|
|
@ -58,15 +58,23 @@ class CvLookupManager
|
||||||
return lookup
|
return lookup
|
||||||
|
|
||||||
public [linkDeps] : begin
|
public [linkDeps] : begin
|
||||||
if (this.decompositionLookup && this.altrenatesLookup) : begin
|
if this.decompositionLookup : begin
|
||||||
this.table.setDependency this.decompositionLookup this.altrenatesLookup
|
if this.altrenatesLookup : begin
|
||||||
|
this.table.setDependency this.decompositionLookup this.altrenatesLookup
|
||||||
|
foreach lookupSS [items-of this.singleSubstLookups] : if lookupSS : begin
|
||||||
|
this.table.setDependency this.decompositionLookup lookupSS
|
||||||
|
foreach lookupCP [items-of this.cherryPickingLookups] : if lookupCP : begin
|
||||||
|
this.table.setDependency this.decompositionLookup lookupCP
|
||||||
|
|
||||||
if this.altrenatesLookup : begin
|
if this.altrenatesLookup : begin
|
||||||
foreach lookupSS [items-of this.singleSubstLookups] : if lookupSS : begin
|
foreach lookupSS [items-of this.singleSubstLookups] : if lookupSS : begin
|
||||||
this.table.setDependency this.altrenatesLookup lookupSS
|
this.table.setDependency this.altrenatesLookup lookupSS
|
||||||
foreach lookupCP [items-of this.cherryPickingLookups] : if lookupCP : begin
|
foreach lookupCP [items-of this.cherryPickingLookups] : if lookupCP : begin
|
||||||
this.table.setDependency lookupCP this.altrenatesLookup
|
this.table.setDependency lookupCP this.altrenatesLookup
|
||||||
foreach lookupSS [items-of this.singleSubstLookups] : if lookupSS : begin
|
|
||||||
this.table.setDependency lookupCP lookupSS
|
foreach lookupCP [items-of this.cherryPickingLookups] : if lookupCP : begin
|
||||||
|
foreach lookupSS [items-of this.singleSubstLookups] : if lookupSS : begin
|
||||||
|
this.table.setDependency lookupCP lookupSS
|
||||||
|
|
||||||
public [linkCrossDeps other] : begin
|
public [linkCrossDeps other] : begin
|
||||||
if (this.altrenatesLookup && other.altrenatesLookup) : begin
|
if (this.altrenatesLookup && other.altrenatesLookup) : begin
|
||||||
|
@ -101,41 +109,35 @@ export : define [buildCVSS gsub para glyphStore] : begin
|
||||||
local lookup : [cvs.get gr.tag].createDecompositionSubst
|
local lookup : [cvs.get gr.tag].createDecompositionSubst
|
||||||
if [not lookup.substitutions.(gn)] : set lookup.substitutions.(gn) parts
|
if [not lookup.substitutions.(gn)] : set lookup.substitutions.(gn) parts
|
||||||
|
|
||||||
do "cvxx"
|
do "cvxx / ssxx"
|
||||||
local cvGrs {}
|
local grSetUsedBySs : new Set
|
||||||
foreach {name prime} para.variants.primes : foreach {vn variant} prime.variants : begin
|
foreach {name composition} para.variants.composites : if composition.tag : begin
|
||||||
if (variant.tag && variant.rank) : cvGrs.push variant
|
define feature : gsub.addCommonFeature : gsub.createFeature composition.tag
|
||||||
cvGrs.sort AnyCv.compare
|
|
||||||
|
|
||||||
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
define decomp : composition.decompose para para.variants.selectorTree
|
||||||
foreach gr [items-of cvGrs] : begin
|
local ssGrs {}
|
||||||
local subst : gr.get glyph
|
foreach { prime pv } [items-of decomp] : if (pv.tag && pv.rank) : begin
|
||||||
if (subst && subst != gn) : begin
|
ssGrs.push pv
|
||||||
local cvAlt : [cvs.get gr.tag].createAlternateSubst
|
local dl [cvs.get pv.tag].decompositionLookup
|
||||||
if [not cvAlt.substitutions.(gn)] : set cvAlt.substitutions.(gn) { }
|
if dl : feature.addLookup dl
|
||||||
set cvAlt.substitutions.(gn).(gr.rank - 1) : glyphStore.ensureExists subst
|
ssGrs.sort AnyCv.compare
|
||||||
|
|
||||||
do "ssxx" : foreach {name composition} para.variants.composites : if composition.tag : begin
|
|
||||||
define feature : gsub.addCommonFeature : gsub.createFeature composition.tag
|
|
||||||
|
|
||||||
define decomp : composition.decompose para para.variants.selectorTree
|
|
||||||
local ssGrs {}
|
|
||||||
foreach { prime pv } [items-of decomp] : if (pv.tag && pv.rank) : begin
|
|
||||||
ssGrs.push pv
|
|
||||||
local dl [cvs.get pv.tag].decompositionLookup
|
|
||||||
if dl : feature.addLookup dl
|
|
||||||
ssGrs.sort AnyCv.compare
|
|
||||||
|
|
||||||
foreach gr [items-of ssGrs] : begin
|
|
||||||
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
|
||||||
feature.addLookup cvSingle
|
|
||||||
|
|
||||||
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
|
||||||
foreach gr [items-of ssGrs] : begin
|
foreach gr [items-of ssGrs] : begin
|
||||||
|
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
||||||
|
feature.addLookup cvSingle
|
||||||
|
grSetUsedBySs.add gr
|
||||||
|
|
||||||
|
foreach {gn glyph} [glyphStore.namedEntriesWithFilter nonDecomposable] : begin
|
||||||
|
foreach gr [items-of : AnyCv.query glyph] : begin
|
||||||
local subst : gr.get glyph
|
local subst : gr.get glyph
|
||||||
if (subst && subst != gn) : begin
|
if (subst && subst != gn) : begin
|
||||||
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
if (gr.tag && gr.rank) : begin
|
||||||
set cvSingle.substitutions.(gn) : glyphStore.ensureExists subst
|
local cvAlt : [cvs.get gr.tag].createAlternateSubst
|
||||||
|
if [not cvAlt.substitutions.(gn)] : set cvAlt.substitutions.(gn) { }
|
||||||
|
set cvAlt.substitutions.(gn).(gr.rank - 1) : glyphStore.ensureExists subst
|
||||||
|
if [grSetUsedBySs.has gr] : begin
|
||||||
|
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
||||||
|
set cvSingle.substitutions.(gn) : glyphStore.ensureExists subst
|
||||||
|
|
||||||
do "CV cherry picking"
|
do "CV cherry picking"
|
||||||
foreach {name prime} para.variants.primes : if prime.cherryPicking : begin
|
foreach {name prime} para.variants.primes : if prime.cherryPicking : begin
|
||||||
|
@ -147,7 +149,7 @@ export : define [buildCVSS gsub para glyphStore] : begin
|
||||||
if cv.decompositionLookup : feature.addLookup cv.decompositionLookup
|
if cv.decompositionLookup : feature.addLookup cv.decompositionLookup
|
||||||
feature.addLookup lookup
|
feature.addLookup lookup
|
||||||
|
|
||||||
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
foreach {gn glyph} [glyphStore.namedEntriesWithFilter nonDecomposable] : begin
|
||||||
local subst : gr.get glyph
|
local subst : gr.get glyph
|
||||||
if (subst && subst != gn) : begin
|
if (subst && subst != gn) : begin
|
||||||
set lookup.substitutions.(gn) : glyphStore.ensureExists subst
|
set lookup.substitutions.(gn) : glyphStore.ensureExists subst
|
||||||
|
@ -172,3 +174,4 @@ export : define [buildCVSS gsub para glyphStore] : begin
|
||||||
return cvs
|
return cvs
|
||||||
|
|
||||||
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length
|
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length
|
||||||
|
define [nonDecomposable gn g] : not : CvDecompose.get g
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This class is used to "flatten" the spiro controls into a plain list of UserControlKnot
|
// This class is used to "flatten" the spiro controls into a plain list of UserControlKnot
|
||||||
export class SpiroFlattener {
|
export class SpiroFlattener {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.preControlFunctions = [];
|
this.preControls = [];
|
||||||
this.controls = [];
|
this.controls = [];
|
||||||
this.postControls = [];
|
this.postControls = [];
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,21 @@ export class SpiroFlattener {
|
||||||
add(c) {
|
add(c) {
|
||||||
if (Array.isArray(c)) {
|
if (Array.isArray(c)) {
|
||||||
for (const item of c) this.add(item);
|
for (const item of c) this.add(item);
|
||||||
} else if (c instanceof Function) {
|
} else if (c instanceof AfBase) {
|
||||||
if (!this.controls.length) this.preControlFunctions.push(c);
|
if (this.controls.length) {
|
||||||
else throw new Error("Invalid spiro control sequence");
|
throw new Error(
|
||||||
|
"Invalid spiro control sequence: pre-control functions must be added first",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.preControls.push(c);
|
||||||
} else if (c instanceof TerminateInstruction) {
|
} else if (c instanceof TerminateInstruction) {
|
||||||
this.postControls.push(c);
|
this.postControls.push(c);
|
||||||
} else {
|
} else {
|
||||||
if (this.postControls.length) throw new Error("Invalid spiro control sequence");
|
if (this.postControls.length) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid spiro control sequence: post-control functions must be added last",
|
||||||
|
);
|
||||||
|
}
|
||||||
this.controls.push(c);
|
this.controls.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +42,7 @@ export class SpiroFlattener {
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe(collector) {
|
pipe(collector) {
|
||||||
for (const fn of this.preControlFunctions) fn.call(collector);
|
for (const fn of this.preControls) fn.applyTo(collector);
|
||||||
for (const control of this.controls) collector.pushKnot(control);
|
for (const control of this.controls) collector.pushKnot(control);
|
||||||
for (const postControl of this.postControls) postControl.applyTo(collector);
|
for (const postControl of this.postControls) postControl.applyTo(collector);
|
||||||
collector.finish();
|
collector.finish();
|
||||||
|
@ -214,6 +222,27 @@ class CoordinatePropagator {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/** The "amendmend function" */
|
||||||
|
export class AfBase {
|
||||||
|
applyTo() {
|
||||||
|
throw new Error("Unimplemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AfCombine extends AfBase {
|
||||||
|
constructor(af1, af2) {
|
||||||
|
super();
|
||||||
|
this.af1 = af1;
|
||||||
|
this.af2 = af2;
|
||||||
|
}
|
||||||
|
applyTo(target) {
|
||||||
|
if (this.af1) this.af1.applyTo(target);
|
||||||
|
if (this.af2) this.af2.applyTo(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const RES_DEP_STAGE_COORDINATE_PROPOGATION_X = 0;
|
const RES_DEP_STAGE_COORDINATE_PROPOGATION_X = 0;
|
||||||
const RES_DEP_STAGE_COORDINATE_PROPOGATION_Y = 1;
|
const RES_DEP_STAGE_COORDINATE_PROPOGATION_Y = 1;
|
||||||
const RES_DEP_STAGE_INTERPOLATION = 2;
|
const RES_DEP_STAGE_INTERPOLATION = 2;
|
||||||
|
@ -241,7 +270,7 @@ export class UserControlKnot {
|
||||||
this.af = af;
|
this.af = af;
|
||||||
}
|
}
|
||||||
applyTo(ctx) {
|
applyTo(ctx) {
|
||||||
if (this.af) this.af.call(ctx);
|
if (this.af) this.af.applyTo(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependency(stage) {
|
getDependency(stage) {
|
||||||
|
@ -261,7 +290,6 @@ export class UserControlKnot {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
resolveCoordiantePropogation(ic, pre, post) {
|
resolveCoordiantePropogation(ic, pre, post) {
|
||||||
// console.log(this, ic, pre, post);
|
|
||||||
switch (ic) {
|
switch (ic) {
|
||||||
case 0:
|
case 0:
|
||||||
this.x = this.x.resolveX(pre, this, post);
|
this.x = this.x.resolveX(pre, this, post);
|
||||||
|
@ -388,7 +416,7 @@ export class DecorInterpolator extends InterpolatorBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FunctionInterpolator extends InterpolatorBase {
|
export class FunctionInterpolator extends InterpolatorBase {
|
||||||
constructor(blendFn, extraArgs) {
|
constructor(blendFn, extraArgs) {
|
||||||
super();
|
super();
|
||||||
this.blendFn = blendFn;
|
this.blendFn = blendFn;
|
||||||
|
@ -430,10 +458,6 @@ export class KnotProxyInterpolator extends InterpolatorBase {
|
||||||
return this.actual.resolveInterpolation(pre, post);
|
return this.actual.resolveInterpolation(pre, post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Interpolator(blender, restParameters) {
|
|
||||||
return new FunctionInterpolator(blender, restParameters);
|
|
||||||
}
|
|
||||||
export function WithKnotProxy(proxy, actual) {
|
export function WithKnotProxy(proxy, actual) {
|
||||||
return new KnotProxyInterpolator(proxy, actual);
|
return new KnotProxyInterpolator(proxy, actual);
|
||||||
}
|
}
|
||||||
|
@ -448,7 +472,6 @@ export class TerminateInstruction {
|
||||||
applyTo(ctx) {
|
applyTo(ctx) {
|
||||||
if (this.type === "close") ctx.closed = true;
|
if (this.type === "close") ctx.closed = true;
|
||||||
if (this.af) throw new Error("Unreachable");
|
if (this.af) throw new Error("Unreachable");
|
||||||
// if (this.af) this.af.call(ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,11 @@ export class BiKnotCollector {
|
||||||
this.lastKnot.proposedNormal = direction;
|
this.lastKnot.proposedNormal = direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setImportant() {
|
||||||
|
if (this.lastKnot) {
|
||||||
|
this.lastKnot.unimportant = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
setUnimportant() {
|
setUnimportant() {
|
||||||
if (this.lastKnot) {
|
if (this.lastKnot) {
|
||||||
this.lastKnot.unimportant = 1;
|
this.lastKnot.unimportant = 1;
|
||||||
|
|
|
@ -33,6 +33,7 @@ export class PenKnotCollector {
|
||||||
setUnimportant() {
|
setUnimportant() {
|
||||||
if (this.m_lastKnot) this.m_lastKnot.profile = null;
|
if (this.m_lastKnot) this.m_lastKnot.profile = null;
|
||||||
}
|
}
|
||||||
|
setImportant() {} // Not used
|
||||||
setContrast() {}
|
setContrast() {}
|
||||||
|
|
||||||
setProfile(profile) {
|
setProfile(profile) {
|
||||||
|
|
|
@ -14,6 +14,11 @@ export class GlyphStore {
|
||||||
namedEntries() {
|
namedEntries() {
|
||||||
return this.nameForward.entries();
|
return this.nameForward.entries();
|
||||||
}
|
}
|
||||||
|
*namedEntriesWithFilter(fn) {
|
||||||
|
for (const [name, g] of this.nameForward.entries()) {
|
||||||
|
if (fn(name, g)) yield [name, g];
|
||||||
|
}
|
||||||
|
}
|
||||||
glyphNames() {
|
glyphNames() {
|
||||||
return this.nameForward.keys();
|
return this.nameForward.keys();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue