Skip to content

Commit

Permalink
Simplify and small refactor of the ligation builder (#2447)
Browse files Browse the repository at this point in the history
* Refactor the ligation builder

* Simplify & small refactor of the ligation set builder
  • Loading branch information
be5invis authored Jul 31, 2024
1 parent 491d9fe commit d08e7db
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 86 deletions.
30 changes: 15 additions & 15 deletions packages/font-otl/src/gsub-ligation.ptl
Original file line number Diff line number Diff line change
Expand Up @@ -471,21 +471,21 @@ define [buildLigationsImpl gsub para $LigGroup$] : begin
define [CAntiHeadForce] : if dbl [lsx 'hole'] [lsx 'shift0.anti']
define [CAntiHeadForceShiftN1] : if dbl [lsx 'hole.shiftN1'] [lsx 'shiftN1.anti']

define [LJoinHeadForce] : if [hasLG 'arrow-l'] [CJoinHeadForce] advance
define [LJoinHeadForceLR] : if ([hasLG 'arrow-l'] || [hasLG 'arrow-lr']) [CJoinHeadForce] advance
define [LJoinHeadForceShift1] : if [hasLG 'arrow-l'] [CJoinHeadForceShift1] advance
define [LJoinHeadForceShift1LR] : if ([hasLG 'arrow-l'] || [hasLG 'arrow-lr']) [CJoinHeadForce] advance
define [LMiddleHead] : if [hasLG 'counter-arrow-l'] [CJoinHeadMid] : if [hasLG 'arrow-l'] [LJoinHeadForce] advance
define [LAntiHeadForce] : if [hasLG 'counter-arrow-l'] [CAntiHeadForce] advance
define [LAntiHeadForceShiftN1] : if [hasLG 'counter-arrow-l'] [CAntiHeadForceShiftN1] advance

define [RJoinHeadForce] : if [hasLG 'arrow-r'] [CJoinHeadForce] advance
define [RJoinHeadForceLR] : if ([hasLG 'arrow-r'] || [hasLG 'arrow-lr']) [CJoinHeadForce] advance
define [RJoinHeadForceShift1] : if [hasLG 'arrow-r'] [CJoinHeadForceShift1] advance
define [RJoinHeadForceShift1LR] : if ([hasLG 'arrow-r'] || [hasLG 'arrow-lr']) [CJoinHeadForce] advance
define [RMiddleHead] : if [hasLG 'counter-arrow-r'] [CJoinHeadMid] : if [hasLG 'arrow-r'] [RJoinHeadForce] advance
define [RAntiHeadForce] : if [hasLG 'counter-arrow-r'] [CAntiHeadForce] advance
define [RAntiHeadForceShiftN1] : if [hasLG 'counter-arrow-r'] [CAntiHeadForceShiftN1] advance
define [LJoinHeadForce] : if [hasLG 'arrow-l'] [CJoinHeadForce] advance
define [LJoinHeadForceLR] : if [hasLG 'arrow-lr'] [CJoinHeadForce] advance
define [LJoinHeadForceShift1] : if [hasLG 'arrow-l'] [CJoinHeadForceShift1] advance
define [LJoinHeadForceShift1LR] : if [hasLG 'arrow-lr'] [CJoinHeadForce] advance
define [LMiddleHead] : if [hasLG 'counter-arrow-l'] [CJoinHeadMid] : if [hasLG 'arrow-l'] [LJoinHeadForce] advance
define [LAntiHeadForce] : if [hasLG 'counter-arrow-l'] [CAntiHeadForce] advance
define [LAntiHeadForceShiftN1] : if [hasLG 'counter-arrow-l'] [CAntiHeadForceShiftN1] advance

define [RJoinHeadForce] : if [hasLG 'arrow-r'] [CJoinHeadForce] advance
define [RJoinHeadForceLR] : if [hasLG 'arrow-lr'] [CJoinHeadForce] advance
define [RJoinHeadForceShift1] : if [hasLG 'arrow-r'] [CJoinHeadForceShift1] advance
define [RJoinHeadForceShift1LR] : if [hasLG 'arrow-lr'] [CJoinHeadForce] advance
define [RMiddleHead] : if [hasLG 'counter-arrow-r'] [CJoinHeadMid] : if [hasLG 'arrow-r'] [RJoinHeadForce] advance
define [RAntiHeadForce] : if [hasLG 'counter-arrow-r'] [CAntiHeadForce] advance
define [RAntiHeadForceShiftN1] : if [hasLG 'counter-arrow-r'] [CAntiHeadForceShiftN1] advance

# Ambiguous
define [LAntiHeadAmbig] : if doLTAlt [LAntiHeadForce] advance
Expand Down
6 changes: 1 addition & 5 deletions packages/font-otl/src/index.ptl
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,7 @@ define [buildGSUB para glyphStore markGlyphs] : begin
local ccmp : buildCCMP gsub glyphStore markGlyphs

# Ligation
if para.enableLigation : do
define plm : Object.assign {.} para.ligation.defaultBuildup
if (para.ligation.caltBuildup && para.ligation.caltBuildup.length) : begin
set plm.calt para.ligation.caltBuildup
buildLigations gsub para plm
if para.enableLigation : buildLigations gsub para para.ligationBuildups

# frac
buildFrac gsub glyphStore
Expand Down
102 changes: 54 additions & 48 deletions packages/param/src/ligation.mjs
Original file line number Diff line number Diff line change
@@ -1,59 +1,65 @@
import * as Parameters from "./index.mjs";

export function applyLigationData(data, para, argv) {
const defaultBuildup = {};
const hives = {};
hives["default"] = { caltBuildup: [] };
for (const gr in data.simple) {
const lg = data.simple[gr];
hives[`ligset-enable-${gr}`] = { appends: { caltBuildup: [gr] } };
hives[`ligset-disable-${gr}`] = { removes: { caltBuildup: [gr] } };
}
for (const gr in data.composite) {
const comp = data.composite[gr];
if (!comp.tag) continue;
const ligSets = createBuildup(data.simple, data.composite, comp.buildup);
defaultBuildup[comp.tag] = ligSets;
hives[`ligset-inherit-${gr}`] = { caltBuildup: ligSets };
}
para.ligation = {
defaultBuildup,
caltBuildup: [],
};
const simples = data.simple;
const composites = { ...data.composite, ...argv.ligtionCompositesFromBuildPlan };

const taggedBuildups = {};
for (const [key, config] of Object.entries(data.composite)) {
if (!config.tag) continue;
taggedBuildups[config.tag] = createBuildupForComposite(simples, composites, config);
}

if (argv.ligations) {
if (argv.ligations.inherits)
Parameters.apply(para.ligation, hives, [`ligset-inherit-${argv.ligations.inherits}`]);
if (argv.ligations.disables)
Parameters.apply(
para.ligation,
hives,
argv.ligations.disables.map(x => `ligset-disable-${x}`),
);
if (argv.ligations.enables)
Parameters.apply(
para.ligation,
hives,
argv.ligations.enables.map(x => `ligset-enable-${x}`),
);
taggedBuildups["calt"] = createBuildupForComposite(simples, composites, argv.ligations);
}
if (argv.customLigationTags) {
for (const [tag, config] of Object.entries(argv.customLigationTags)) {
taggedBuildups[tag] = createBuildupForComposite(simples, composites, config);
}
}

para.ligationBuildups = taggedBuildups;
}

export function createBuildup(simple, composite, buildup) {
export function createBuildupForComposite(simples, composites, config) {
let sink = new Set();
createBuildupImpl(false, sink, simple, composite, buildup);
addComposite(sink, simples, composites, config);
return Array.from(sink);
}

function createBuildupImpl(fSimpleOnly, sink, simple, composite, buildup) {
for (const s of buildup) {
if (simple[s]) {
sink.add(s);
const gr = simple[s];
if (gr.implies) createBuildupImpl(true, sink, simple, composite, gr.implies);
} else if (!fSimpleOnly && composite[s]) {
createBuildupImpl(fSimpleOnly, sink, simple, composite, composite[s].buildup);
} else {
throw new Error("Cannot find simple ligation group " + s);
function addByKey(sink, simples, composites, key) {
if (simples[key]) {
addSimple(sink, simples, key);
} else if (composites[key]) {
addComposite(sink, simples, composites, composites[key]);
} else {
throw new Error("Cannot find ligation group " + key);
}
}
function addComposite(sink, simples, composites, config) {
if (config.inherits) {
// "Inherits" will override the current sink data
const newSink = new Set();
addByKey(newSink, simples, composites, config.inherits);
sink.clear();
for (const item of newSink) sink.add(item);
}
if (config.enables) {
for (const item of config.enables) addByKey(sink, simples, composites, item);
}
if (config.buildup) {
for (const item of config.buildup) addByKey(sink, simples, composites, item);
}
if (config.disables) {
const newSink = new Set();
for (const item of config.disables) addByKey(newSink, simples, composites, item);
for (const item of newSink) sink.delete(item);
}
}
function addSimple(sink, simples, key) {
const gr = simples[key];
sink.add(key);
if (gr.implies) {
for (const imply of gr.implies) {
addSimple(sink, simples, imply);
}
}
}
6 changes: 3 additions & 3 deletions packages/param/src/variant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ export function parse(data, argv) {
const comp = new Composite(k, data.composite[k]);
composites.set(k, comp);
}
if (argv && argv.compositesFromBuildPlan) {
for (const k in argv.compositesFromBuildPlan) {
if (argv && argv.variantCompositesFromBuildPlan) {
for (const k in argv.variantCompositesFromBuildPlan) {
const key = `buildPlans.${k}`;
const comp = new Composite(key, argv.compositesFromBuildPlan[k]);
const comp = new Composite(key, argv.variantCompositesFromBuildPlan[k]);
composites.set(key, comp);
}
}
Expand Down
6 changes: 3 additions & 3 deletions tools/data-export/src/ligation-data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from "fs";
import path from "path";

import * as toml from "@iarna/toml";
import { createBuildup } from "@iosevka/param/ligation";
import { createBuildupForComposite } from "@iosevka/param/ligation";

const ligationSamplesNarrow = [
[
Expand Down Expand Up @@ -100,11 +100,11 @@ function buildLigationSet(ligData, getKey) {
]);
for (const sel in ligData.composite) {
const comp = ligData.composite[sel];
if (!comp.tag) continue;
if (!comp.tag || !comp.desc) continue;
const key = getKey(comp);
let item = ligationSets.get(key);
if (!item) {
let ligSets = createBuildup(ligData.simple, ligData.composite, comp.buildup);
let ligSets = createBuildupForComposite(ligData.simple, ligData.composite, comp);
item = {
selector: sel,
tag: comp.tag,
Expand Down
50 changes: 38 additions & 12 deletions verdafile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,40 @@ const GroupFontsOf = computed.group("metadata:group-fonts-of", async (target, gi
return plan.targets;
});

const CompositesFromBuildPlan = computed(`metadata:composites-from-build-plan`, async target => {
const [{ buildPlans }] = await target.need(BuildPlans);
let data = {};
for (const bpn in buildPlans) {
let bp = buildPlans[bpn];
if (bp.variants) {
data[bpn] = bp.variants;
const VariantCompositesFromBuildPlan = computed(
`metadata:variant-composites-from-build-plan`,
async target => {
const [{ buildPlans }] = await target.need(BuildPlans);
let data = {};
for (const bpn in buildPlans) {
let bp = buildPlans[bpn];
if (bp.variants) {
data[bpn] = bp.variants;
}
}
}
return data;
});
return data;
},
);

const LigtionCompositesFromBuildPlan = computed(
`metadata:ligation-composites-from-build-plan`,
async target => {
const [{ buildPlans }] = await target.need(BuildPlans);
let data = {};
for (const bpn in buildPlans) {
let bp = buildPlans[bpn];
if (bp.ligations) {
data[`buildPlans.${bpn}`] = bp.ligations;
}
if (bp.customLigationTags) {
for (const [tag, config] of Object.entries(bp.customLigationTags)) {
data[`buildPlans.${bpn}.${tag}`] = config;
}
}
}
return data;
},
);

// eslint-disable-next-line complexity
const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileName) => {
Expand All @@ -279,7 +302,8 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
};
}

const [compositesFromBuildPlan] = await target.need(CompositesFromBuildPlan);
const [variantCompositesFromBuildPlan] = await target.need(VariantCompositesFromBuildPlan);
const [ligtionCompositesFromBuildPlan] = await target.need(LigtionCompositesFromBuildPlan);

return {
name: fileName,
Expand All @@ -294,6 +318,7 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
},
// Ligations
ligations: bp.ligations || null,
customLigationTags: bp.customLigationTags || null,
// Shape
shape: {
serifs: bp.serifs || null,
Expand Down Expand Up @@ -335,7 +360,8 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
spacingDerive,

// Composite variants from build plan -- used for variant resolution when building fonts
compositesFromBuildPlan,
variantCompositesFromBuildPlan,
ligtionCompositesFromBuildPlan,
};
});

Expand Down

0 comments on commit d08e7db

Please sign in to comment.