From d6ad6d21e30f72448392a153cd7c0cf6dce9a7fc Mon Sep 17 00:00:00 2001 From: be5invis Date: Wed, 21 Aug 2024 23:13:35 -0700 Subject: [PATCH] Move the glyph saving logic to MJS side --- packages/font-glyphs/src/index.ptl | 51 ++-------------- .../font-glyphs/src/letter/latin/lower-g.ptl | 4 +- packages/font-glyphs/src/meta/macros.ptl | 33 +++++------ packages/font-otl/src/index.ptl | 5 ++ packages/glyph/src/block.mjs | 59 +++++++++++++++++++ 5 files changed, 84 insertions(+), 68 deletions(-) diff --git a/packages/font-glyphs/src/index.ptl b/packages/font-glyphs/src/index.ptl index 2582cee16c..4cb9d4b835 100644 --- a/packages/font-glyphs/src/index.ptl +++ b/packages/font-glyphs/src/index.ptl @@ -1,6 +1,6 @@ import [Glyph GlyphProc ForkGlyphProc] from "@iosevka/glyph" import [GlyphStore] from "@iosevka/glyph/store" -import [GlyphBlock GlyphBuildExecutor] from "@iosevka/glyph/block" +import [GlyphBlock GlyphBuildExecutor GlyphSaveSink] from "@iosevka/glyph/block" import as Gr from "@iosevka/glyph/relation" import as SpiroKit from "@iosevka/font-kits/spiro-kit" import as BooleKit from "@iosevka/font-kits/boole-kit" @@ -15,7 +15,6 @@ $$include './meta/macros.ptl' export : define [buildGlyphs para recursive] : begin # Execution and dependency management local $Exec$ : new GlyphBuildExecutor recursive - define [glyph-is-needed name] : [not recursive] || [recursive.glyphIsNeeded name] # Initialize glyph store local glyphStore : new GlyphStore @@ -32,45 +31,8 @@ export : define [buildGlyphs para recursive] : begin # Anchor parameters define {AS_BASE ALSO_METRICS} {'AS-BASE' 'ALSO-METRICS'} - # The callback used to create and save glyphs - define [$createAndSaveGlyphImpl$ _1 _2 actions] : begin - local saveGlyphName null - local unicode null - - piecewise - ([typeof _1] === 'number' && _1) : begin - set saveGlyphName : 'uni' + [_1.toString 16 :.padStart 4 '0' :.toUpperCase] - set unicode _1 - ([typeof _1] === 'string' && _1) : begin - set saveGlyphName _1 - set unicode _2 - true : begin - set saveGlyphName null - set unicode null - - if (saveGlyphName && [not : glyph-is-needed saveGlyphName]) : return nothing - if para.verbose : console.log saveGlyphName - - local glyphObject [new Glyph saveGlyphName] - glyphObject.setWidth Metrics.Width - glyphObject.gizmo = Metrics.GlobalTransform - glyphObject._m_dependencyManager = $Exec$.dependencyManager - - glyphObject.include actions true true - - $Exec$.setGlyphToBlockDependency glyphObject - - if saveGlyphName : begin - if (saveGlyphName.0 != '.' && [glyphStore.queryByName saveGlyphName]) - throw : new Error "Glyph \(saveGlyphName) already exists" - glyphStore.addGlyph saveGlyphName glyphObject - if unicode : begin - local u unicode - if ([typeof unicode] === "string") : begin - set u [unicode.codePointAt 0] - glyphStore.encodeGlyph u glyphObject - - return glyphObject + # Glyph saving sink + define $GlyphSaveSink$ : new GlyphSaveSink $Exec$ Metrics glyphStore # Spiro kit and boole kit define SpiroFns : SpiroKit.SetupBuilders : object @@ -86,9 +48,9 @@ export : define [buildGlyphs para recursive] : begin # Setup the capture define $$Capture$$ : object - $createAndSaveGlyphImpl$ $NamedParameterPair$ $Exec$ + $GlyphSaveSink$ Metrics : Object.assign {.} Metrics para recursive @@ -100,7 +62,6 @@ export : define [buildGlyphs para recursive] : begin MarkSet AS_BASE ALSO_METRICS - glyph-is-needed buildGlyphs fontMetrics GlyphProc @@ -148,8 +109,4 @@ export : define [buildGlyphs para recursive] : begin $Exec$.executePendingBlocks - Gr.linkSuffixPairGr glyphStore 'NWID' 'WWID' Gr.Nwid Gr.Wwid - Gr.linkSuffixPairGr glyphStore 'lnum' 'onum' Gr.Lnum Gr.Onum - Gr.linkSuffixGr glyphStore 'aplForm' Gr.AplForm - return : object glyphStore fontMetrics diff --git a/packages/font-glyphs/src/letter/latin/lower-g.ptl b/packages/font-glyphs/src/letter/latin/lower-g.ptl index 28bc542380..8b5c1a90a6 100644 --- a/packages/font-glyphs/src/letter/latin/lower-g.ptl +++ b/packages/font-glyphs/src/letter/latin/lower-g.ptl @@ -51,7 +51,7 @@ glyph-block Letter-Latin-Lower-G : begin set-base-anchor 'overlay' Middle [mix (Descender + O) groundy 0.5] set-base-anchor 'strike' Middle (XH / 2) - create-forked-glyph 'gBar.doubleStorey' : OverlayW obwDoubleStorey + derive-composites "gBar.doubleStorey" null "g.doubleStorey" [OverlayW obwDoubleStorey] create-glyph 'g.openDoubleStorey' : glyph-proc include : MarkSet.p @@ -81,7 +81,7 @@ glyph-block Letter-Latin-Lower-G : begin set-base-anchor 'overlay' Middle [mix (Descender + O) groundy 0.5] set-base-anchor 'strike' Middle (XH / 2) - create-forked-glyph 'gBar.openDoubleStorey' : OverlayW obwDoubleStorey + derive-composites "gBar.openDoubleStorey" null "g.openDoubleStorey" [OverlayW obwDoubleStorey] define SingleStorey : namespace export : define [RoundHookT sink df yTop offset sw] : sink diff --git a/packages/font-glyphs/src/meta/macros.ptl b/packages/font-glyphs/src/meta/macros.ptl index ad850367dd..7a6dbca013 100644 --- a/packages/font-glyphs/src/meta/macros.ptl +++ b/packages/font-glyphs/src/meta/macros.ptl @@ -149,40 +149,35 @@ define-macro eject-contour : syntax-rules ###### Canvas-based mechanism define-macro new-glyph : syntax-rules `[new-glyph @body] : begin - dirty `[$createAndSaveGlyphImpl$ null null @[formOf body]] + dirty `[$GlyphSaveSink$.save null null @[formOf body]] define-macro create-glyph : syntax-rules `[create-glyph @body] : begin - if [not externEnv.$nWFGlyphs$] : set externEnv.$nWFGlyphs$ 0 - inc externEnv.$nWFGlyphs$ - local f0 : '.' + [[env.macros.get 'input-path']].1 + '.' - local tcn {".quote" (".WF" + f0 + externEnv.$nWFGlyphs$)} - dirty `[$createAndSaveGlyphImpl$ @tcn null @[formOf body]] + dirty `[$GlyphSaveSink$.save null null @[formOf body]] `[create-glyph @name @body] : begin - dirty `[$createAndSaveGlyphImpl$ @[formOf name] null @[formOf body]] + dirty `[$GlyphSaveSink$.save @[formOf name] null @[formOf body]] `[create-glyph @name @code @body] : begin - dirty `[$createAndSaveGlyphImpl$ @[formOf name] @[formOf code] @[formOf body]] + dirty `[$GlyphSaveSink$.save @[formOf name] @[formOf code] @[formOf body]] define-macro create-aliased-glyph : syntax-rules `[create-aliased-glyph @name] : begin dirty `[create-aliased-glyph @[formOf name] null] `[create-aliased-glyph @name @code] : begin - dirty `[$createAndSaveGlyphImpl$ @[formOf name] @[formOf code] + dirty `[$GlyphSaveSink$.save @[formOf name] @[formOf code] [new $Capture$.ForkGlyphProc currentGlyph null] ] define-macro create-forked-glyph : syntax-rules `[create-forked-glyph @body] : begin - if [not externEnv.$nWFGlyphs$] : set externEnv.$nWFGlyphs$ 0 - inc externEnv.$nWFGlyphs$ - local f0 : '.' + [[env.macros.get 'input-path']].1 + '.' - local tcn {".quote" (".WF" + f0 + externEnv.$nWFGlyphs$)} - dirty `[create-forked-glyph @tcn null @[formOf body]] + dirty `[create-forked-glyph null null @[formOf body]] `[create-forked-glyph @name @body] : begin dirty `[create-forked-glyph @[formOf name] null @[formOf body]] `[create-forked-glyph @name @code @body] : begin - dirty `[$createAndSaveGlyphImpl$ @[formOf name] @[formOf code] + dirty `[$GlyphSaveSink$.save @[formOf name] @[formOf code] [new $Capture$.ForkGlyphProc currentGlyph @[formOf body]] ] +define-macro glyph-is-needed : syntax-rules + `[glyph-is-needed @name] : dirty `[$GlyphSaveSink$.glyphIsNeeded @[formOf name]] + ###### Glyph modules and Glyph blocks define-macro glyph-module : syntax-rules @@ -265,13 +260,13 @@ define-macro glyph-block : syntax-rules ([typeof form] === "string") : set variableSet.(form) true traceBody body - traceBody `[$NamedParameterPair$ $createAndSaveGlyphImpl$ $Exec$] + traceBody `[$NamedParameterPair$ $GlyphSaveSink$ $Exec$] set externEnv.$glyphBlockVariableUsage$ variableSet - define captureImports `[$createAndSaveGlyphImpl$ $NamedParameterPair$ $Exec$ Metrics para - recursive glyphStore glyph-is-needed SpiroFns BooleFns MarkSet AS_BASE ALSO_METRICS - buildGlyphs DivFrame fontMetrics] + define captureImports `[$GlyphSaveSink$ $NamedParameterPair$ $Exec$ Metrics para recursive + glyphStore SpiroFns BooleFns MarkSet AS_BASE ALSO_METRICS buildGlyphs DivFrame + fontMetrics] define metricImports `[DesignParameters UPM HalfUPM Width SB CAP XH Ascender Descender Contrast SymbolMid ParenTop ParenBot OperTop OperBot TackTop TackBot PlusTop PlusBot diff --git a/packages/font-otl/src/index.ptl b/packages/font-otl/src/index.ptl index 4b2233bef5..2462069ab1 100644 --- a/packages/font-otl/src/index.ptl +++ b/packages/font-otl/src/index.ptl @@ -108,6 +108,11 @@ define [buildGDEF para glyphStore markGlyphs] : begin return GDEF export : define [buildOtl para glyphStore] : begin + # Link glyph pairs by suffix + Gr.linkSuffixPairGr glyphStore 'NWID' 'WWID' Gr.Nwid Gr.Wwid + Gr.linkSuffixPairGr glyphStore 'lnum' 'onum' Gr.Lnum Gr.Onum + Gr.linkSuffixGr glyphStore 'aplForm' Gr.AplForm + local markGlyphs { .all [new Set] .markAttachClassDef [new Map] .markGlyphSets {} } local GPOS : buildGPOS para glyphStore markGlyphs local GDEF : buildGDEF para glyphStore markGlyphs diff --git a/packages/glyph/src/block.mjs b/packages/glyph/src/block.mjs index 53212c6c44..686119f83d 100644 --- a/packages/glyph/src/block.mjs +++ b/packages/glyph/src/block.mjs @@ -1,3 +1,5 @@ +import { Glyph } from "./glyph.mjs"; + export class GlyphBuildExecutor { constructor(recursiveBuildFilter) { this.recursiveBuildFilter = recursiveBuildFilter; @@ -174,3 +176,60 @@ export class GlyphBlock { return this.exports; } } + +/// The class used to handle glyph saving. +export class GlyphSaveSink { + constructor(exec, metrics, store) { + this.exec = exec; + this.metrics = metrics; + this.glyphStore = store; + } + + glyphIsNeeded(name) { + return ( + !this.exec.recursiveBuildFilter || this.exec.recursiveBuildFilter.glyphIsNeeded(name) + ); + } + + save($1, $2, contents) { + // Figure out the glyph name and unicode to save + let saveGlyphName = null; + let unicode = null; + if ($1 && typeof $1 === "string") { + saveGlyphName = $1; + unicode = $2 || 0; + } else if ($1 && typeof $1 === "number") { + saveGlyphName = "uni" + $1.toString(16).padStart(4, "0").toUpperCase(); + unicode = $1; + } + + // If we are in a recursive build run, and the glyph is not needed, skip it + if (saveGlyphName && !this.glyphIsNeeded(saveGlyphName)) return; + + // Create the glyph object & include the contents + const glyphObject = new Glyph(saveGlyphName); + glyphObject.setWidth(this.metrics.Width); + glyphObject.gizmo = this.metrics.GlobalTransform; + glyphObject._m_dependencyManager = this.exec.dependencyManager; + + glyphObject.include(contents, true, true); + + // Set the glyph-to-block dependency + this.exec.setGlyphToBlockDependency(glyphObject); + + // Save the glyph if requested + if (saveGlyphName) { + if (this.glyphStore.queryByName(saveGlyphName)) { + throw new Error(`Duplicate glyph: ${saveGlyphName}`); + } + + this.glyphStore.addGlyph(saveGlyphName, glyphObject); + if (unicode) { + let u = typeof unicode === "string" ? unicode.codePointAt(0) : unicode; + this.glyphStore.encodeGlyph(u, glyphObject); + } + } + + return glyphObject; + } +}