Add Fraktur e/o/ø (#2445)

* Add
  - LATIN SMALL LETTER BLACKLETTER E (`U+AB32`).
  - LATIN SMALL LETTER BLACKLETTER O (`U+AB3D`).
  - LATIN SMALL LETTER BLACKLETTER O WITH STROKE (`U+AB3E`).
  - MATHEMATICAL FRAKTUR SMALL E (`U+1D522`).
  - MATHEMATICAL FRAKTUR SMALL O (`U+1D52C`).

* Notes (#2443, #444)

* Refine
This commit is contained in:
Belleve 2024-07-30 02:28:53 -10:00 committed by GitHub
parent edfd04dae6
commit 67f12d42af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 382 additions and 119 deletions

View file

@ -5,4 +5,9 @@
- BLACK-LETTER CAPITAL R (`U+211C`) (#714). - BLACK-LETTER CAPITAL R (`U+211C`) (#714).
- BLACK-LETTER CAPITAL Z (`U+2128`) (#714). - BLACK-LETTER CAPITAL Z (`U+2128`) (#714).
- BLACK-LETTER CAPITAL C (`U+212D`) (#714). - BLACK-LETTER CAPITAL C (`U+212D`) (#714).
- LATIN SMALL LETTER BLACKLETTER E (`U+AB32`) (#2443).
- LATIN SMALL LETTER BLACKLETTER O (`U+AB3D`) (#2443).
- LATIN SMALL LETTER BLACKLETTER O WITH STROKE (`U+AB3E`) (#2443).
- MATHEMATICAL FRAKTUR CAPITAL J (`U+1D50D`) (#444). - MATHEMATICAL FRAKTUR CAPITAL J (`U+1D50D`) (#444).
- MATHEMATICAL FRAKTUR SMALL E (`U+1D522`) (#444).
- MATHEMATICAL FRAKTUR SMALL O (`U+1D52C`) (#444).

View file

@ -2,8 +2,9 @@ $$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] from "@iosevka/geometry/spiro-control" import [Interpolator WithKnotProxy] from "@iosevka/geometry/spiro-control"
import [RadicalGeometry StrokeGeometry RemoveHolesGeometry] from "@iosevka/geometry" import [RadicalGeometry StrokeGeometry RemoveHolesGeometry] from "@iosevka/geometry"
import [CMixCoord] from "@iosevka/font-kits/derived-coordinates"
glyph-module glyph-module
@ -510,6 +511,9 @@ glyph-block CommonShapes : begin
define [hookEndBlender before after args] : begin define [hookEndBlender before after args] : begin
return : HookShape before after false args return : HookShape before after false args
define [hookProxy args] : begin
return : g4 [new CMixCoord 0.5] args.y
glyph-block-export hookstart glyph-block-export hookstart
define flex-params [hookstart] : begin define flex-params [hookstart] : begin
local-parameter : y local-parameter : y
@ -517,8 +521,8 @@ glyph-block CommonShapes : begin
local-parameter : swTerminal -- sw local-parameter : swTerminal -- sw
local-parameter : isTail -- false local-parameter : isTail -- false
local-parameter : noSwash -- false local-parameter : noSwash -- false
return : Interpolator hookStartBlender local args : object y sw swTerminal isTail noSwash
object y sw swTerminal isTail noSwash return : WithKnotProxy [hookProxy args] : Interpolator hookStartBlender args
glyph-block-export hookend glyph-block-export hookend
define flex-params [hookend] : begin define flex-params [hookend] : begin
@ -527,8 +531,8 @@ glyph-block CommonShapes : begin
local-parameter : swTerminal -- sw local-parameter : swTerminal -- sw
local-parameter : isTail -- false local-parameter : isTail -- false
local-parameter : noSwash -- false local-parameter : noSwash -- false
return : Interpolator hookEndBlender local args : object y sw swTerminal isTail noSwash
object y sw swTerminal isTail noSwash return : WithKnotProxy [hookProxy args] : Interpolator hookEndBlender args
glyph-block-export arch glyph-block-export arch
define arch : namespace define arch : namespace
@ -569,6 +573,11 @@ glyph-block CommonShapes : begin
set r : 0.5 + (r - 0.5) * (v + w) / (u * 2) set r : 0.5 + (r - 0.5) * (v + w) / (u * 2)
return r return r
define [archBlenderProxy args] : begin
return : [if args.compact g2 g4]
new CMixCoord [fallback args.p 0.5] 0 args.mockPre args.mockPost
begin args.y
define [archBlender _before _after args] : begin define [archBlender _before _after args] : begin
local before : fallback args.mockPre _before local before : fallback args.mockPre _before
local after : fallback args.mockPost _after local after : fallback args.mockPost _after
@ -600,8 +609,8 @@ glyph-block CommonShapes : begin
local-parameter : mockPost -- nothing local-parameter : mockPost -- nothing
local-parameter : blendPre -- [arcvh] local-parameter : blendPre -- [arcvh]
local-parameter : blendPost -- [archv] local-parameter : blendPost -- [archv]
return : Interpolator archBlender local args : object [lhs true] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost
object [lhs true] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost return : WithKnotProxy [archBlenderProxy args] : Interpolator archBlender args
export : define flex-params [rhs] : begin export : define flex-params [rhs] : begin
local-parameter : y local-parameter : y
@ -615,8 +624,8 @@ glyph-block CommonShapes : begin
local-parameter : mockPost -- nothing local-parameter : mockPost -- nothing
local-parameter : blendPre -- [arcvh] local-parameter : blendPre -- [arcvh]
local-parameter : blendPost -- [archv] local-parameter : blendPost -- [archv]
return : Interpolator archBlender local args : object [lhs false] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost
object [lhs false] y p sw compact o swBefore swAfter mockPre mockPost blendPre blendPost return : WithKnotProxy [archBlenderProxy args] : Interpolator archBlender args
foreach side {lhs rhs} : begin foreach side {lhs rhs} : begin
set side.centerAt : object set side.centerAt : object

View file

@ -4,6 +4,7 @@ import [GlyphBlock GlyphBuildExecutor] from "@iosevka/glyph/block"
import as Gr from "@iosevka/glyph/relation" import as Gr from "@iosevka/glyph/relation"
import as SpiroKit from "@iosevka/font-kits/spiro-kit" import as SpiroKit from "@iosevka/font-kits/spiro-kit"
import as BooleKit from "@iosevka/font-kits/boole-kit" import as BooleKit from "@iosevka/font-kits/boole-kit"
import as DerivedCoordinates from "@iosevka/font-kits/derived-coordinates"
import [DesignParameters calculateMetrics setFontMetrics GenDivFrame] from "./meta/aesthetics.mjs" import [DesignParameters calculateMetrics setFontMetrics GenDivFrame] from "./meta/aesthetics.mjs"
import [$NamedParameterPair$] from "@iosevka/util" import [$NamedParameterPair$] from "@iosevka/util"
@ -81,6 +82,7 @@ export : define [buildGlyphs para recursive] : begin
Superness DesignParameters.superness Superness DesignParameters.superness
define BooleFns : BooleKit.SetupBuilders : object define BooleFns : BooleKit.SetupBuilders : object
globalTransform Metrics.GlobalTransform globalTransform Metrics.GlobalTransform
define DerivedCoordinateFns : DerivedCoordinates.SetupBuilders : object
# Setup the capture # Setup the capture
define $$Capture$$ : object define $$Capture$$ : object
@ -93,6 +95,7 @@ export : define [buildGlyphs para recursive] : begin
glyphStore glyphStore
SpiroFns SpiroFns
BooleFns BooleFns
DerivedCoordinateFns
DivFrame DivFrame
MarkSet MarkSet
AS_BASE AS_BASE

View file

@ -9,6 +9,7 @@ $$include '../meta/macros.ptl'
import [mix fallback] from "@iosevka/util" 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 [Interpolator] from "@iosevka/geometry/spiro-control" import [Interpolator] from "@iosevka/geometry/spiro-control"
glyph-module glyph-module
@ -57,6 +58,8 @@ glyph-block LetterLike-Fraktur-Shared : begin
new Vec2 (-thickTf.x - this.thin) (-thickTf.y - this.thin) new Vec2 (-thickTf.x - this.thin) (-thickTf.y - this.thin)
new Vec2 (-thickTf.x - this.thin) (-thickTf.y + this.thin) new Vec2 (-thickTf.x - this.thin) (-thickTf.y + this.thin)
public [box u d l r] : new Box [this.yt u] [this.yb d] [this.xl l] [this.xr r]
public [xl x] : x + this.thick public [xl x] : x + this.thick
public [xr x] : x - this.thick public [xr x] : x - this.thick
public [xp l r p] : mix [this.xl l] [this.xr r] p public [xp l r p] : mix [this.xl l] [this.xr r] p
@ -93,8 +96,8 @@ glyph-block LetterLike-Fraktur-Shared : begin
define LbFootRise : 0.375 * SHook + 0.375 * S.thick define LbFootRise : 0.375 * SHook + 0.375 * S.thick
glyph-block-export SlopeA SlopeB glyph-block-export SlopeA SlopeB
define SlopeA : DecoSizeY / DecoSizeX define SlopeA : 0.875 * DecoSizeY / DecoSizeX
define SlopeB 1.0 define SlopeB : 0.875 * -[mix SlopeA 1.0 0.5]
# Wave blenders # Wave blenders
glyph-block-export Wave glyph-block-export Wave
@ -115,11 +118,23 @@ glyph-block LetterLike-Fraktur-Shared : begin
g2 [mix before.x after.x 0.375] after.y g2 [mix before.x after.x 0.375] after.y
g2 [mix before.x after.x 0.625] before.y g2 [mix before.x after.x 0.625] before.y
glyph-block-export PHexTop
define PHexTop : 0.5 + 0.5 * ([Math.max DecoSizeX frakThin] / (RightSB - SB))
glyph-block-export PHexBot
define PHexBot : 1 - PHexTop
glyph-block LetterLike-Fraktur : begin glyph-block LetterLike-Fraktur : begin
glyph-block-import Common-Derivatives
glyph-block-import CommonShapes glyph-block-import CommonShapes
glyph-block-import LetterLike-Fraktur-Shared : S F T fraktur-stroke glyph-block-import LetterLike-Fraktur-Shared : S F T fraktur-stroke
glyph-block-import LetterLike-Fraktur-Shared : DecoSizeX DecoSizeY SlopeA SlopeB glyph-block-import LetterLike-Fraktur-Shared : DecoSizeX DecoSizeY SlopeA SlopeB
glyph-block-import LetterLike-Fraktur-Shared : Wave LbFootRise FHook glyph-block-import LetterLike-Fraktur-Shared : Wave LbFootRise FHook PHexTop PHexBot
define [LtDecorativeWave sx sy ey] : fraktur-stroke F
g2.ld.start [F.connL S : S.xl sx] [F.connB S : S.yt sy]
~~~ [Wave.vc (-Wave.DepthX)]
g2.ld.end pre@ (ey - 2 * S.thick)
create-glyph "frak/C" 0x212D : glyph-proc create-glyph "frak/C" 0x212D : glyph-proc
include : MarkSet.capital include : MarkSet.capital
@ -137,7 +152,7 @@ glyph-block LetterLike-Fraktur : begin
include : fraktur-stroke S include : fraktur-stroke S
g4.ld.start [S.xp SB RightSB 0.1] ([S.yt CAP] - 0.1 * ArchDepthA) g4.ld.start [S.xp SB RightSB 0.1] ([S.yt CAP] - 0.1 * ArchDepthA)
flat [S.xl SB] ([S.yt CAP] - 0.6 * ArchDepthA) flat [S.xl SB] ([S.yt CAP] - 0.6 * ArchDepthA)
curl same-x ([S.yb 0] + ArchDepthB) curl pre@ ([S.yb 0] + ArchDepthB)
~~~ [hookend [S.yb 0] (sw -- S.thick)] ~~~ [hookend [S.yb 0] (sw -- S.thick)]
g2 [S.xr RightSB] ([S.yb 0] + SHook) g2 [S.xr RightSB] ([S.yb 0] + SHook)
@ -151,7 +166,7 @@ glyph-block LetterLike-Fraktur : begin
include : fraktur-stroke F include : fraktur-stroke F
g2.ld.start [F.connL S xCenter] [F.connB S : [S.yt CAP] - DecoSizeX] g2.ld.start [F.connL S xCenter] [F.connB S : [S.yt CAP] - DecoSizeX]
~~~ [Wave.vc (-Wave.DepthX)] ~~~ [Wave.vc (-Wave.DepthX)]
g2.ld.end same-x (CAP * 0.375) g2.ld.end pre@ (CAP * 0.375)
create-glyph "frak/H" 0x210C : glyph-proc create-glyph "frak/H" 0x210C : glyph-proc
include : MarkSet.capDesc include : MarkSet.capDesc
@ -190,36 +205,32 @@ glyph-block LetterLike-Fraktur : begin
g2.ld.start [S.xr RightSB] [S.yt CAP] g2.ld.start [S.xr RightSB] [S.yt CAP]
~~~ [Wave.h] ~~~ [Wave.h]
g2.ld.mid [S.xl SB] [S.yt (CAP - Wave.DepthY)] g2.ld.mid [S.xl SB] [S.yt (CAP - Wave.DepthY)]
include : fraktur-stroke F include : LtDecorativeWave [S.xl SB] (CAP - Wave.DepthY) (CAP * 0.625)
g2.ld.start [F.connL S : S.xl SB] [F.connB S : S.yt (CAP - Wave.DepthY)]
~~~ [Wave.vc (-Wave.DepthX)]
g2.ld.end [F.connL S : S.xl SB] (CAP * 0.625 - 2 * S.thick)
create-glyph "frak/I" 0x2111 : glyph-proc create-glyph "frak/I" 0x2111 : glyph-proc
include : MarkSet.capital include : MarkSet.capital
include : IJTopStroke include : IJTopStroke
# Main stroke
local iBox : S.box CAP 0 SB RightSB
include : fraktur-stroke S include : fraktur-stroke S
g2.ld.start [S.xr RightSB] [S.yt CAP] g2.ld.start iBox.right iBox.top
g4 [S.xp SB RightSB 0.75] [S.yp ArchDepthA CAP 0.625] g4 [iBox.xp 0.7] [mix@ 0.375]
g4 [S.xr RightSB] [S.yb ArchDepthA] g4 iBox.right (post@ <+> ArchDepthA)
~~~ [hookend [S.yb 0] (sw -- S.thick)] hookend (sw -- S.thick) iBox.bot
g2 [S.xl SB] [S.yb SHook] g2 iBox.left (pre@ <+> SHook)
create-glyph "frak/J" 0x1D50D : glyph-proc create-glyph "frak/J" 0x1D50D : glyph-proc
include : MarkSet.capDesc include : MarkSet.capDesc
include : IJTopStroke include : IJTopStroke
# Main stroke local jBox : S.box [S.yt (CAP - 1.5 * Wave.DepthY - 2 * S.thick)] Descender SB RightSB
local mainStrokeTop : S.yt (CAP - 1.5 * Wave.DepthY - 2 * S.thick)
include : fraktur-stroke S include : fraktur-stroke S
g4 [S.xr RightSB] (mainStrokeTop - FHook) g4 jBox.right (post@ <-> FHook)
~~~ [hookstart mainStrokeTop (sw -- S.thick)] hookstart (sw -- S.thick) jBox.top
g4 [S.xr : mix SB RightSB 0.6] (mainStrokeTop - 0.6 * ArchDepthA) g4 ([jBox.xp 0.6] - S.thick) (pre@ <-> 0.6 * ArchDepthA)
g4 [S.xr RightSB] [S.yb (Descender + ArchDepthA)] g4 jBox.right (post@ <+> ArchDepthA)
~~~ [hookend [S.yb Descender] (sw -- S.thick)] hookend (sw -- S.thick) jBox.bot
g2 [S.xl SB] [S.yb (Descender + SHook)] g2 jBox.left (pre@ <+> SHook)
create-glyph "frak/R" 0x211C : glyph-proc create-glyph "frak/R" 0x211C : glyph-proc
include : MarkSet.capital include : MarkSet.capital
@ -231,10 +242,7 @@ glyph-block LetterLike-Fraktur : begin
local adb : 0.6 * ArchDepthB local adb : 0.6 * ArchDepthB
# Deocration at top-left # Deocration at top-left
include : fraktur-stroke F include : LtDecorativeWave xExt (CAP - ltHook) (CAP * 0.625)
g2.ld.start [F.connL S : S.xl xExt] [F.connB S : S.yt (CAP - ltHook)]
~~~ [Wave.vc (-Wave.DepthX)]
g2.ld.end [F.connL S : S.xl xExt] (CAP * 0.625 - 2 * S.thick)
local xMidStrokeL : S.xl xLeftStem local xMidStrokeL : S.xl xLeftStem
local xMidStrokeR : S.xp xLeftStem RightSB 0.625 local xMidStrokeR : S.xp xLeftStem RightSB 0.625
@ -251,16 +259,16 @@ glyph-block LetterLike-Fraktur : begin
g2.ru.start [S.xl xExt] [S.yt (CAP - ltHook)] g2.ru.start [S.xl xExt] [S.yt (CAP - ltHook)]
~~~ [arch.rhs [S.yt CAP] 0.6 (blendPre -- null)] ~~~ [arch.rhs [S.yt CAP] 0.6 (blendPre -- null)]
flat [S.xl xLeftStem] [Math.max ([S.yb CAP] - ada) yArchStart] flat [S.xl xLeftStem] [Math.max ([S.yb CAP] - ada) yArchStart]
curl [S.xl xLeftStem] yMidStrokeL curl (pre@ <+> 0) yMidStrokeL
corner [S.xl xExt] ([S.yb 0] + LbFootRise) corner [S.xl xExt] (post@ <+> LbFootRise)
g2c.right.end (Middle - DecoSizeX) [S.yb 0] g2c.right.end (post@ <-> DecoSizeX) [S.yb 0]
corner Middle ([S.yb 0] + DecoSizeY) corner Middle (pre@ <+> DecoSizeY)
# Top-right arch # Top-right arch
include : fraktur-stroke S include : fraktur-stroke S
flat xArchStart yArchStart flat xArchStart yArchStart
corner xArchTop yArchTop corner xArchTop yArchTop
g2.down.mid [S.xr RightSB] [mix yMidStrokeR yArchTop 0.5] g2.down.mid [S.xr RightSB] [mix@ 0.5]
flat xMidStrokeR yMidStrokeR flat xMidStrokeR yMidStrokeR
curl xMidStrokeL yMidStrokeL curl xMidStrokeL yMidStrokeL
@ -271,32 +279,62 @@ glyph-block LetterLike-Fraktur : begin
# Leg # Leg
include : fraktur-stroke S include : fraktur-stroke S
g2 xLegStart yLegStart [g2.sr SlopeA].start xLegStart yLegStart
g2 (xLegStart + TINY) (yLegStart + SlopeA * TINY) flat [mix@ 0.75] (pre@ <-> adb)
flat [mix xLegStart xLegEnd 0.75] (yLegStart - adb) decor@ : curl pre@ (post@ <+> ada)
curl [mix xLegStart xLegEnd 0.75] (yLegEnd + ada)
corner xLegEnd yLegEnd corner xLegEnd yLegEnd
corner (xLegEnd + DecoSizeX) (yLegEnd + DecoSizeY) corner (pre@ <+> DecoSizeX) (pre@ <+> DecoSizeY)
create-glyph "frak/Z" 0x2128 : glyph-proc create-glyph "frak/Z" 0x2128 : glyph-proc
include : MarkSet.capital include : MarkSet.capital
local zBox : S.box CAP 0 SB RightSB
# Top Stroke # Top Stroke
include : fraktur-stroke S include : fraktur-stroke S
g2.ld.start [S.xr RightSB] [S.yt CAP] g2.ld.start zBox.right zBox.top
~~~ [Wave.h] ~~~ [Wave.h]
g2.ld.mid [S.xl SB] [S.yt (CAP - Wave.DepthY)] g2.ld.mid zBox.left (pre@ <-> Wave.DepthY)
# Bottom Stroke # Bottom Stroke
local diag : list local diag : list
corner [S.xr RightSB] [S.yt CAP] corner zBox.right zBox.top
corner [S.xp SB RightSB 0.166] [S.yp 0 CAP 0.5] corner [zBox.xp 0.166] [zBox.yp 0.5]
include : fraktur-stroke S diag include : fraktur-stroke S diag
include : difference include : difference
fraktur-stroke S fraktur-stroke S
g2.ru.start [S.xp SB RightSB 0.166] [S.yp 0 CAP 0.5] g2.ru.start diag.1.x diag.1.y
~~~ [arch.rhs [S.yp 0 CAP 0.55] 0.375 (sw -- S.thick)] ~~~ [arch.rhs [zBox.yp 0.55] 0.375 (sw -- S.thick)]
g2.down.mid [S.xr RightSB] [S.yb ArchDepthA] g2.down.mid zBox.right (post@ <+> ArchDepthA)
~~~ [hookend [S.yb 0] (sw -- S.thick)] hookend zBox.bot (sw -- S.thick)
g2 [S.xl SB] [S.yb SHook] g2 zBox.left (pre@ <+> SHook)
MaskAboveLine diag.0.x diag.0.y diag.1.x diag.1.y 4 MaskAboveLine diag.0.x diag.0.y diag.1.x diag.1.y 4
create-glyph "frak/e" 0xAB32 : glyph-proc
include : MarkSet.e
local eBox : S.box XH 0 SB RightSB
include : fraktur-stroke S
corner (eBox.left + S.thick) [post@slope SlopeA]
g2 eBox.xMid [eBox.yp DesignParameters.eBarPos]
corner eBox.right [pre@slope SlopeA]
corner [eBox.xp PHexTop] eBox.top
corner eBox.left [pre@slope SlopeA]
curl pre@ (post@ <+> ArchDepthB)
[g2c.sr (-SlopeA)].end [eBox.xp PHexTop] eBox.bot
corner eBox.right [pre@slope SlopeA]
alias 'mathFrak/e' 0x1D522 'frak/e'
create-glyph "frak/o" 0xAB3D : glyph-proc
include : MarkSet.e
local oBox : S.box XH 0 SB RightSB
include : fraktur-stroke S
[cg2.sr SlopeB].start [oBox.xp PHexTop] oBox.top
g2.down.mid oBox.right [mix@ 0.5]
[g2c.sl SlopeA].start [oBox.xp PHexBot] oBox.bot
corner oBox.left [pre@slope SlopeB]
corner pre@ [post@slope SlopeA]
close
alias 'mathFrak/o' 0x1D52C 'frak/o'

View file

@ -7,9 +7,18 @@ define-operator "--" 890 'right' : syntax-rules
define-operator "~>" 880 'right' : syntax-rules define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r} `(@l ~> @r) `{.left @l .right @r}
### The operator indicating a "mix" ### The operator indicating a "delay"
define-operator prefix "~~~" : syntax-rules define-operator prefix "~~~" : syntax-rules
`(~~~ @x) : dirty [formOf x] `(~~~ @x) : dirty `[decor@ @x]
### This operator is a method variant of (+)
define-operator infix "<+>" 350 'left' : syntax-rules
`(@l <+> @r) : dirty `[@l.op_add @r]
### This operator is a method variant of (-)
define-operator infix "<->" 350 'left' : syntax-rules
`(@l <-> @r) : dirty `[@l.op_sub @r]
### Macro for identity match ### Macro for identity match
define-macro Just : begin define-macro Just : begin
@ -281,10 +290,13 @@ define-macro glyph-block : syntax-rules
NarrowUnicodeT WideUnicodeT VERY-FAR TINY] NarrowUnicodeT WideUnicodeT VERY-FAR TINY]
define spiroFnImports `[g4 g2 corner flat curl close end straight g2c cg2 flatc ccurl widths define spiroFnImports `[g4 g2 corner flat curl close end straight g2c cg2 flatc ccurl widths
disable-contrast heading unimportant important alsoThru alsoThruThem bezControls disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
quadControls archv arcvh dispiro spiro-outline spiro-collect same-x same-y same-x-post quadControls archv arcvh dispiro spiro-outline spiro-collect]
same-y-post]
define booleFnImports `[union intersection difference] define booleFnImports `[union intersection difference]
define drvCoordImports `[pre@ post@ mix@ pre@slope post@slope
decor@ decor@@ decor@@@ pre@tang-in post@tang-in pre@tang-out post@tang-out]
dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\ dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\
$Capture_Ext$.$Exec$.defineGlyphBlock $Capture_Ext$ @blockName $Capture_Ext$.$Exec$.defineGlyphBlock $Capture_Ext$ @blockName
function [$Capture$ $ExportCapture$] : begin function [$Capture$ $ExportCapture$] : begin
@ -292,6 +304,7 @@ define-macro glyph-block : syntax-rules
define [object @::[metricImports.filter : lambda [x] variableSet.(x)]] $Capture$.Metrics define [object @::[metricImports.filter : lambda [x] variableSet.(x)]] $Capture$.Metrics
define [object @::[spiroFnImports.filter : lambda [x] variableSet.(x)]] $Capture$.SpiroFns define [object @::[spiroFnImports.filter : lambda [x] variableSet.(x)]] $Capture$.SpiroFns
define [object @::[booleFnImports.filter : lambda [x] variableSet.(x)]] $Capture$.BooleFns define [object @::[booleFnImports.filter : lambda [x] variableSet.(x)]] $Capture$.BooleFns
define [object @::drvCoordImports] $Capture$.DerivedCoordinateFns
* @body * @body

View file

@ -212,6 +212,7 @@ export : define decompOverrides : object
0xA7A9 { 's' 'oblStrike' } 0xA7A9 { 's' 'oblStrike' }
0xAB30 { 'scripta' 'hStrike' } 0xAB30 { 'scripta' 'hStrike' }
0xAB3E { 'frak/o' 'shortSlash' }
0xAB3F { 'turnc' 'shortSlash' } 0xAB3F { 'turnc' 'shortSlash' }
0xAB4F { 'uShortLeg' 'hStrike' } 0xAB4F { 'uShortLeg' 'hStrike' }

View file

@ -3,6 +3,7 @@
"version": "31.1.0", "version": "31.1.0",
"private": true, "private": true,
"exports": { "exports": {
"./derived-coordinates": "./src/derived-coordinates.mjs",
"./boole-kit": "./src/boole-kit.mjs", "./boole-kit": "./src/boole-kit.mjs",
"./spiro-kit": "./src/spiro-kit.mjs" "./spiro-kit": "./src/spiro-kit.mjs"
}, },

View file

@ -0,0 +1,171 @@
import {
DecorInterpolator,
DEP_POST_X,
DEP_POST_Y,
DEP_PRE_X,
DEP_PRE_Y,
DEP_SAME_X,
DEP_SAME_Y,
DerivedCoordinateBase,
InterpolatorBase,
} from "@iosevka/geometry/spiro-control";
const TINY = 1 / 128;
export function SetupBuilders(_bindings) {
return {
// Derived coordinates
// pre@, post@: copy or ade delta to the pre or post point's X or Y coordinate
// use with pre@ or like (pre@ <+> delta)
"pre@": new CDeltaPre(0),
"post@": new CDeltaPost(0),
// "Tangent" derived cooredinates, which is simply a tiny delta.
"pre@tang-out": s => new CDeltaPre(TINY * s),
"post@tang-out": s => new CDeltaPost(TINY * s),
"pre@tang-in": s => new CDeltaPre(-TINY * s),
"post@tang-in": s => new CDeltaPost(-TINY * s),
// mix@: mix between pre and post point's X or Y coordinates
// usage [mix@ proportion] or [mix@ proportion delta]
"mix@": (p, delta) => new CMixCoord(p, delta),
// pre@slope, post@slope: Get the coordiante using the pre/post point's coordinate and a
// slope. An optional delta can be added to the result. See the definitions for more
// details.
"pre@slope": (s, delta) => new CAtSlopePre(s, delta),
"post@slope": (s, delta) => new CAtSlopePost(s, delta),
// Interpolators
// decor@, decor@@, decor@@@: Add a "delay" to the thing inside when resolving the spiro
// controls. This is a very useful utility for coordinate propagation, which allow us to
// "skip" the current point and go to the next or previous point. The number of @'s
// determines the number of times the delay is applied.
"decor@": x => new DecorInterpolator(x),
"decor@@": x => new DecorInterpolator(new DecorInterpolator(x)),
"decor@@@": x => new DecorInterpolator(new DecorInterpolator(new DecorInterpolator(x))),
};
}
class CDeltaPre extends DerivedCoordinateBase {
constructor(delta) {
super();
this.delta = delta;
}
op_add(delta) {
return new CDeltaPre(this.delta + delta);
}
op_sub(delta) {
return new CDeltaPre(this.delta - delta);
}
getDependencyForX() {
return DEP_PRE_X;
}
getDependencyForY() {
return DEP_PRE_Y;
}
resolveX(pre, curr, post) {
return pre.x + this.delta;
}
resolveY(pre, curr, post) {
return pre.y + this.delta;
}
}
class CDeltaPost extends DerivedCoordinateBase {
constructor(delta) {
super();
this.delta = delta;
}
op_add(delta) {
return new CDeltaPost(this.delta + delta);
}
op_sub(delta) {
return new CDeltaPost(this.delta - delta);
}
getDependencyForX() {
return DEP_POST_X;
}
getDependencyForY() {
return DEP_POST_Y;
}
resolveX(pre, curr, post) {
return post.x + this.delta;
}
resolveY(pre, curr, post) {
return post.y + this.delta;
}
}
export class CMixCoord extends DerivedCoordinateBase {
constructor(proportion, delta, mockPre, mockPost) {
super();
this.proportion = proportion;
this.delta = delta || 0;
this.mockPre = mockPre || null;
this.mockPost = mockPost || null;
}
getDependencyForX() {
let f = 0;
if (!this.mockPre) f |= DEP_PRE_X;
if (!this.mockPost) f |= DEP_POST_X;
return f;
}
getDependencyForY() {
let f = 0;
if (!this.mockPre) f |= DEP_PRE_Y;
if (!this.mockPost) f |= DEP_POST_Y;
return f;
}
resolveX(_pre, curr, _post) {
const pre = this.mockPre || _pre;
const post = this.mockPost || _post;
return pre.x + this.proportion * (post.x - pre.x) + this.delta;
}
resolveY(_pre, curr, _post) {
const pre = this.mockPre || _pre;
const post = this.mockPost || _post;
return pre.y + this.proportion * (post.y - pre.y) + this.delta;
}
}
class CAtSlopePre extends DerivedCoordinateBase {
constructor(slope, delta) {
super();
this.slope = slope;
this.delta = delta || 0;
}
getDependencyForX() {
return DEP_PRE_X | DEP_PRE_Y | DEP_SAME_Y;
}
getDependencyForY() {
return DEP_PRE_X | DEP_PRE_Y | DEP_SAME_X;
}
resolveY(pre, curr, post) {
return pre.y + this.slope * (curr.x - pre.x) + this.delta;
}
resolveX(pre, curr, post) {
return pre.x + (curr.y - pre.y) / this.slope + this.delta;
}
}
class CAtSlopePost extends DerivedCoordinateBase {
constructor(slope, delta) {
super();
this.slope = slope;
this.delta = delta || 0;
}
getDependencyForX() {
return DEP_POST_X | DEP_POST_Y | DEP_SAME_Y;
}
getDependencyForY() {
return DEP_POST_X | DEP_POST_Y | DEP_SAME_X;
}
resolveY(pre, curr, post) {
return post.y + this.slope * (curr.x - post.x) + this.delta;
}
resolveX(pre, curr, post) {
return post.x + (curr.y - post.y) / this.slope + this.delta;
}
}

View file

@ -1,11 +1,6 @@
import { DiSpiroGeometry, SpiroGeometry } from "@iosevka/geometry"; import { DiSpiroGeometry, SpiroGeometry } from "@iosevka/geometry";
import { import {
BiKnotCollector, BiKnotCollector,
DEP_POST_X,
DEP_POST_Y,
DEP_PRE_X,
DEP_PRE_Y,
DerivedCoordinateBase,
Interpolator, Interpolator,
SpiroFlattener, SpiroFlattener,
TerminateInstruction, TerminateInstruction,
@ -109,40 +104,6 @@ function DirPairImpl(kPre, kCenter, kPost, dirX, dirY, dPre, dPost) {
new UserCloseKnotPair(kCenter(x, y, af), tyPre, tyPost, dirX, dirY, dPre, dPost); new UserCloseKnotPair(kCenter(x, y, af), tyPre, tyPost, dirX, dirY, dPre, dPost);
} }
/// Derivative coordinates
class CSameX extends DerivedCoordinateBase {
getDependency() {
return DEP_PRE_X;
}
resolve(pre) {
return pre.x;
}
}
class CSameY extends DerivedCoordinateBase {
getDependency() {
return DEP_PRE_Y;
}
resolve(pre) {
return pre.y;
}
}
class CSameXPost extends DerivedCoordinateBase {
getDependency() {
return DEP_POST_X;
}
resolve(pre, curr, post) {
return post.x;
}
}
class CSameYPost extends DerivedCoordinateBase {
getDependency() {
return DEP_POST_Y;
}
resolve(pre, curr, post) {
return post.y;
}
}
export function SetupBuilders(bindings) { export function SetupBuilders(bindings) {
const { Stroke, Superness } = bindings; const { Stroke, Superness } = bindings;
@ -193,7 +154,7 @@ export function SetupBuilders(bindings) {
{ name: "ld", x: -1, y: -1 }, { name: "ld", x: -1, y: -1 },
]; ];
for (const [sink, kl, kc, kr] of knotTypes) { for (const [sink, kl, kc, kr] of knotTypes) {
sink.sl = s => new DirectedKnotPairBuilder(bindings, kl, kc, kr, -1, s); sink.sl = s => new DirectedKnotPairBuilder(bindings, kl, kc, kr, -1, -s);
sink.sr = s => new DirectedKnotPairBuilder(bindings, kl, kc, kr, 1, s); sink.sr = s => new DirectedKnotPairBuilder(bindings, kl, kc, kr, 1, s);
sink.dir = (dx, dy) => new DirectedKnotPairBuilder(bindings, kl, kc, kr, dx, dy); sink.dir = (dx, dy) => new DirectedKnotPairBuilder(bindings, kl, kc, kr, dx, dy);
for (const d of directions) { for (const d of directions) {
@ -479,10 +440,5 @@ export function SetupBuilders(bindings) {
dispiro, dispiro,
"spiro-outline": spiroOutline, "spiro-outline": spiroOutline,
"spiro-collect": spiroCollect, "spiro-collect": spiroCollect,
"same-x": new CSameX(),
"same-y": new CSameY(),
"same-x-post": new CSameXPost(),
"same-y-post": new CSameYPost(),
}; };
} }

View file

@ -3,7 +3,7 @@ import { mix } from "@iosevka/util";
export class Box { export class Box {
constructor(t, b, l, r) { constructor(t, b, l, r) {
this.top = t; this.top = t;
this.bottom = this.bot = b; this.bot = this.bottom = b;
this.left = l; this.left = l;
this.right = r; this.right = r;
this.xMid = this.xMiddle = mix(l, r, 0.5); this.xMid = this.xMiddle = mix(l, r, 0.5);
@ -43,6 +43,10 @@ export class Box {
this.right, this.right,
); );
} }
xp(t) {
return this.mixX(t);
}
mixX(t) { mixX(t) {
return mix(this.left, this.right, t); return mix(this.left, this.right, t);
} }
@ -52,6 +56,10 @@ export class Box {
mixXMidRight(t) { mixXMidRight(t) {
return mix(this.xMid, this.right, t); return mix(this.xMid, this.right, t);
} }
yp(t) {
return this.mixY(t);
}
mixY(t) { mixY(t) {
return mix(this.bottom, this.top, t); return mix(this.bottom, this.top, t);
} }

View file

@ -182,12 +182,17 @@ class CoordinatePropagator {
const stateC = ic ? this.stateY : this.stateX; const stateC = ic ? this.stateY : this.stateX;
if (stateC[i] === CR_RESOLVED) return; if (stateC[i] === CR_RESOLVED) return;
if (stateC[i] === CR_RESOLVING) throw new Error("Circular dependency detected"); if (stateC[i] === CR_RESOLVING) {
console.log(this);
throw new Error("Circular dependency detected");
}
stateC[i] = CR_RESOLVING; stateC[i] = CR_RESOLVING;
if (depC[i] & DEP_PRE_X) this.solve(this.cycI(i - 1), 0); if (depC[i] & DEP_PRE_X) this.solve(this.cycI(i - 1), 0);
if (depC[i] & DEP_PRE_Y) this.solve(this.cycI(i - 1), 1); if (depC[i] & DEP_PRE_Y) this.solve(this.cycI(i - 1), 1);
if (depC[i] & DEP_SAME_X) this.solve(this.cycI(i), 0);
if (depC[i] & DEP_SAME_Y) this.solve(this.cycI(i), 1);
if (depC[i] & DEP_POST_X) this.solve(this.cycI(i + 1), 0); if (depC[i] & DEP_POST_X) this.solve(this.cycI(i + 1), 0);
if (depC[i] & DEP_POST_Y) this.solve(this.cycI(i + 1), 1); if (depC[i] & DEP_POST_Y) this.solve(this.cycI(i + 1), 1);
@ -215,8 +220,10 @@ const RES_DEP_STAGE_INTERPOLATION = 2;
export const DEP_SKIP = 0x1; export const DEP_SKIP = 0x1;
export const DEP_PRE_X = 0x2; export const DEP_PRE_X = 0x2;
export const DEP_PRE_Y = 0x4; export const DEP_PRE_Y = 0x4;
export const DEP_POST_X = 0x8; export const DEP_SAME_X = 0x8;
export const DEP_POST_Y = 0x10; export const DEP_SAME_Y = 0x10;
export const DEP_POST_X = 0x20;
export const DEP_POST_Y = 0x40;
const DEP_PRE = DEP_PRE_X | DEP_PRE_Y; const DEP_PRE = DEP_PRE_X | DEP_PRE_Y;
const DEP_POST = DEP_POST_X | DEP_POST_Y; const DEP_POST = DEP_POST_X | DEP_POST_Y;
@ -239,9 +246,9 @@ export class UserControlKnot {
getDependency(stage) { getDependency(stage) {
switch (stage) { switch (stage) {
case RES_DEP_STAGE_COORDINATE_PROPOGATION_X: case RES_DEP_STAGE_COORDINATE_PROPOGATION_X:
return typeof this.x === "number" ? 0 : this.x.getDependency(stage); return typeof this.x === "number" ? 0 : this.x.getDependencyForX();
case RES_DEP_STAGE_COORDINATE_PROPOGATION_Y: case RES_DEP_STAGE_COORDINATE_PROPOGATION_Y:
return typeof this.y === "number" ? 0 : this.y.getDependency(stage); return typeof this.y === "number" ? 0 : this.y.getDependencyForY();
case RES_DEP_STAGE_INTERPOLATION: case RES_DEP_STAGE_INTERPOLATION:
return 0; return 0;
default: default:
@ -256,10 +263,10 @@ export class UserControlKnot {
// console.log(this, ic, pre, post); // console.log(this, ic, pre, post);
switch (ic) { switch (ic) {
case 0: case 0:
this.x = this.x.resolve(pre, this, post); this.x = this.x.resolveX(pre, this, post);
break; break;
case 1: case 1:
this.y = this.y.resolve(pre, this, post); this.y = this.y.resolveY(pre, this, post);
break; break;
} }
} }
@ -292,7 +299,7 @@ export class UserCloseKnotPair {
} }
getKernelKnot() { getKernelKnot() {
return this.center; return this.center.getKernelKnot();
} }
resolveCoordiantePropogation(ic, pre, post) { resolveCoordiantePropogation(ic, pre, post) {
this.center.resolveCoordiantePropogation(ic, pre, post); this.center.resolveCoordiantePropogation(ic, pre, post);
@ -333,11 +340,10 @@ export class InterpolatorBase {
return 0; return 0;
} }
} }
getKernelKnot() { getKernelKnot() {
throw new Error("Unreachable"); throw new Error("Unreachable");
} }
resolveCoordiantePropogation(pre, post) { resolveCoordiantePropogation() {
throw new Error("Unreachable"); throw new Error("Unreachable");
} }
@ -349,6 +355,16 @@ export class InterpolatorBase {
} }
} }
export class DecorInterpolator extends InterpolatorBase {
constructor(items) {
super();
this.items = items;
}
resolveInterpolation(pre, post) {
return this.items;
}
}
class FunctionInterpolator extends InterpolatorBase { class FunctionInterpolator extends InterpolatorBase {
constructor(blendFn, extraArgs) { constructor(blendFn, extraArgs) {
super(); super();
@ -359,9 +375,45 @@ class FunctionInterpolator extends InterpolatorBase {
return this.blendFn(pre, post, this.extraArgs); return this.blendFn(pre, post, this.extraArgs);
} }
} }
/**
* This class denotes an interpolator that has a proxy knot. The proxy could be used in the
* coordinate propagation stage to resolve dependencies.
*/
export class KnotProxyInterpolator extends InterpolatorBase {
constructor(proxy, actual) {
super();
this.knotProxy = proxy;
this.actual = actual;
}
getDependency(stage) {
switch (stage) {
case RES_DEP_STAGE_COORDINATE_PROPOGATION_X:
case RES_DEP_STAGE_COORDINATE_PROPOGATION_Y:
return this.knotProxy.getDependency(stage);
default:
return this.actual.getDependency(stage);
}
}
getKernelKnot() {
return this.knotProxy.getKernelKnot();
}
resolveCoordiantePropogation(ic, pre, post) {
this.knotProxy.resolveCoordiantePropogation(ic, pre, post);
}
resolveInterpolation(pre, post) {
return this.actual.resolveInterpolation(pre, post);
}
}
export function Interpolator(blender, restParameters) { export function Interpolator(blender, restParameters) {
return new FunctionInterpolator(blender, restParameters); return new FunctionInterpolator(blender, restParameters);
} }
export function WithKnotProxy(proxy, actual) {
return new KnotProxyInterpolator(proxy, actual);
}
export class TerminateInstruction { export class TerminateInstruction {
constructor(type, af) { constructor(type, af) {
@ -378,10 +430,16 @@ export class TerminateInstruction {
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
export class DerivedCoordinateBase { export class DerivedCoordinateBase {
getDependency() { getDependencyForX() {
throw new Error("Unimplemented"); throw new Error("Unimplemented");
} }
resolve(pre, curr, post) { getDependencyForY() {
throw new Error("Unimplemented");
}
resolveX(pre, curr, post) {
throw new Error("Unimplemented");
}
resolveY(pre, curr, post) {
throw new Error("Unimplemented"); throw new Error("Unimplemented");
} }
} }