diff --git a/generator.js b/generator.js index cbb22def0..e3a8ab7f9 100644 --- a/generator.js +++ b/generator.js @@ -1,22 +1,22 @@ -var fs = require("fs"); -var path = require("path"); +let fs = require("fs"); +let path = require("path"); -// var TTFWriter = require('node-sfnt').TTFWriter; -var argv = require("yargs").argv; -var buildGlyphs = require("./buildglyphs.js"); -var parameters = require("./support/parameters"); -var toml = require("toml"); +// let TTFWriter = require('node-sfnt').TTFWriter; +let argv = require("yargs").argv; +let buildGlyphs = require("./buildglyphs.js"); +let parameters = require("./support/parameters"); +let toml = require("toml"); -var Glyph = require("./support/glyph"); -var autoref = require("./support/autoref"); +let Glyph = require("./support/glyph"); +let autoref = require("./support/autoref"); const objectAssign = require("object-assign"); -var caryllShapeOps = require("caryll-shapeops"); -var c2q = require("megaminx").geometry.c2q; +let caryllShapeOps = require("caryll-shapeops"); +let c2q = require("megaminx").geometry.c2q; function hasv(obj) { if (!obj) return false; - for (var k in obj) if (obj[k]) return true; + for (let k in obj) if (obj[k]) return true; return false; } @@ -70,8 +70,25 @@ function formVariantData(data, para) { return vs; } -// Font building -const font = (function() { +function byGlyphPriority(a, b) { + const pri1 = a.cmpPriority || 0; + const pri2 = b.cmpPriority || 0; + if (pri1 > pri2) return -1; + if (pri1 < pri2) return 1; + if (a.contours && b.contours && a.contours.length < b.contours.length) return 1; + if (a.contours && b.contours && a.contours.length > b.contours.length) return -1; + if (a.advanceWidth < b.advanceWidth) return -1; + if (a.advanceWidth > b.advanceWidth) return 1; + if ((a.unicode && a.unicode[0] && !b.unicode) || !b.unicode[0]) return -1; + if ((b.unicode && b.unicode[0] && !a.unicode) || !a.unicode[0]) return +1; + if (a.unicode && a.unicode[0] && b.unicode && b.unicode[0] && a.unicode[0] < b.unicode[0]) + return -1; + if (a.unicode && a.unicode[0] && b.unicode && b.unicode[0] && a.unicode[0] > b.unicode[0]) + return +1; + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; +} + +function getParameters(argv) { const parametersData = Object.assign( {}, toml.parse(fs.readFileSync(path.join(__dirname, "parameters.toml"), "utf-8")), @@ -80,7 +97,6 @@ const font = (function() { : [] ); const variantData = toml.parse(fs.readFileSync(path.join(__dirname, "variants.toml"), "utf-8")); - const emptyFont = toml.parse(fs.readFileSync(path.join(__dirname, "emptyfont.toml"), "utf-8")); const para = parameters.build(parametersData, argv._); const vsdata = formVariantData(variantData, para); @@ -88,9 +104,13 @@ const font = (function() { para.variantSelector = parameters.build(vsdata, argv._); para.defaultVariant = vsdata.default; if (argv.family) para.family = argv.family; - const fontUniqueName = - para.family + " " + para.style + " " + para.version + " (" + para.codename + ")"; + return para; +} +// Font building +const font = (function() { + const emptyFont = toml.parse(fs.readFileSync(path.join(__dirname, "emptyfont.toml"), "utf-8")); + const para = getParameters(argv); const font = buildGlyphs.build.call(emptyFont, para); font.parameters = para; @@ -99,83 +119,46 @@ const font = (function() { g.gord = j; return g; }) - .sort(function(a, b) { - const pri1 = a.cmpPriority || 0; - const pri2 = b.cmpPriority || 0; - if (pri1 > pri2) return -1; - if (pri1 < pri2) return 1; - if (a.contours && b.contours && a.contours.length < b.contours.length) return 1; - if (a.contours && b.contours && a.contours.length > b.contours.length) return -1; - if (a.advanceWidth < b.advanceWidth) return -1; - if (a.advanceWidth > b.advanceWidth) return 1; - if ((a.unicode && a.unicode[0] && !b.unicode) || !b.unicode[0]) return -1; - if ((b.unicode && b.unicode[0] && !a.unicode) || !a.unicode[0]) return +1; - if ( - a.unicode && - a.unicode[0] && - b.unicode && - b.unicode[0] && - a.unicode[0] < b.unicode[0] - ) - return -1; - if ( - a.unicode && - a.unicode[0] && - b.unicode && - b.unicode[0] && - a.unicode[0] > b.unicode[0] - ) - return +1; - return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; - }); + .sort(byGlyphPriority); return font; })(); if (argv.charmap) { - fs.writeFileSync( - argv.charmap, - JSON.stringify( - font.glyf.map(function(glyph) { - return [ - glyph.name, - glyph.unicode, - glyph.advanceWidth === 0 - ? hasv(glyph.anchors) ? 1 : glyph.contours && glyph.contours.length ? 2 : 0 - : 0 - ]; - }) - ), - "utf8" - ); + const charmap = font.glyf.map(function(glyph) { + return [ + glyph.name, + glyph.unicode, + glyph.advanceWidth === 0 + ? hasv(glyph.anchors) ? 1 : glyph.contours && glyph.contours.length ? 2 : 0 + : 0 + ]; + }); + fs.writeFileSync(argv.charmap, JSON.stringify(charmap), "utf8"); } if (argv.o) { - var o_glyf = {}; - var cmap = {}; - var skew = (argv.uprightify ? 1 : 0) * Math.tan((font.post.italicAngle || 0) / 180 * Math.PI); - // autoref - autoref(font.glyf); - // regulate - font.glyf.forEach(g => { + function regulateGlyph(g, skew) { if (!g.contours) return; - for (var k = 0; k < g.contours.length; k++) { - var contour = g.contours[k]; - for (var p = 0; p < contour.length; p++) { + + // Regulate + for (let k = 0; k < g.contours.length; k++) { + const contour = g.contours[k]; + for (let p = 0; p < contour.length; p++) { contour[p].x += contour[p].y * skew; if (!contour[p].on) continue; contour[p].x = Math.round(contour[p].x); } - var offJ = null, + let offJ = null, mx = null; - for (var p = 0; p < contour.length; p++) { + for (let p = 0; p < contour.length; p++) { if (!contour[p].on) continue; if (offJ) { - var origx = contour[p].x; - var rx = Math.round(contour[p].x * 4) / 4; - var origx0 = mx; - var rx0 = contour[offJ - 1].x; + const origx = contour[p].x; + const rx = Math.round(contour[p].x * 4) / 4; + const origx0 = mx; + const rx0 = contour[offJ - 1].x; if (origx === origx0) continue; - for (var poff = offJ; poff < p; poff++) { + for (let poff = offJ; poff < p; poff++) { contour[poff].x = (contour[poff].x - origx0) / (origx - origx0) * (rx - rx0) + rx0; } @@ -185,44 +168,51 @@ if (argv.o) { offJ = p + 1; } } - var c1 = []; - for (var k = 0; k < g.contours.length; k++) { + const c1 = []; + for (let k = 0; k < g.contours.length; k++) { c1.push(Glyph.contourToStandardCubic(g.contours[k])); } - g.contours = c1; - }); - // overlap removal - font.glyf.forEach(g => { - if (g.contours) { - g.contours = caryllShapeOps.removeOverlap(g.contours, 1, 256, true); - } - }); - // reorder - font.glyf = font.glyf.sort((a, b) => a.gord - b.gord); - // finalize - font.glyf.forEach(g => { - if (g.contours) { - Glyph.prototype.cleanup.call(g, 0.1); - g.contours = c2q.contours(g.contours); - for (var k = 0; k < g.contours.length; k++) { - var contour = g.contours[k]; - for (var p = 0; p < contour.length; p++) { - contour[p].x -= contour[p].y * skew; - } + + // De-overlap + g.contours = caryllShapeOps.removeOverlap(c1, 1, 256, true); + + // Finalize + Glyph.prototype.cleanup.call(g, 0.1); + g.contours = c2q.contours(g.contours); + for (let k = 0; k < g.contours.length; k++) { + const contour = g.contours[k]; + for (let p = 0; p < contour.length; p++) { + contour[p].x -= contour[p].y * skew; } } - o_glyf[g.name] = g; - if (g.unicode && g.unicode.length) { - cmap[g.unicode[0]] = g.name; - } - }); + } - font.glyf = o_glyf; - font.cmap = cmap; - font.glyfMap = null; + const skew = (argv.uprightify ? 1 : 0) * Math.tan((font.post.italicAngle || 0) / 180 * Math.PI); + // autoref + autoref(font.glyf); + // regulate + for (let g of font.glyf) regulateGlyph(g, skew); + + // reorder + font.glyf = font.glyf.sort((a, b) => a.gord - b.gord); + + // finalize + const o_glyf = {}; + const o_cmap = {}; + for (let g of font.glyf) { + o_glyf[g.name] = g; + if (!g.unicode) continue; + for (let u of g.unicode) o_cmap[u] = g.name; + } + + // Prepare OTD + const otd = Object.assign({}, font); + otd.glyf = o_glyf; + otd.cmap = o_cmap; + otd.glyfMap = null; if (argv.o === "|") { - process.stdout.write(JSON.stringify(font)); + process.stdout.write(JSON.stringify(otd)); } else { - fs.writeFileSync(argv.o, JSON.stringify(font)); + fs.writeFileSync(argv.o, JSON.stringify(otd)); } } diff --git a/glyphs/numbers.ptl b/glyphs/numbers.ptl index 677f5e7ec..7508614ee 100644 --- a/glyphs/numbers.ptl +++ b/glyphs/numbers.ptl @@ -30,16 +30,20 @@ export : define [apply] : begin select-variant 'zero' '0' - sketch # one + sketch # one.hooky include markset.capital include : VBar (MIDDLE + ONEBALANCE) 0 CAP include : dispiro flat (MIDDLE - HALFSTROKE * HVCONTRAST + ONEBALANCE) CAP [widths STROKE 0] curl (MIDDLE - HOOKX * 1.25 + ONEBALANCE) (CAP - HOOK * 0.75) + save 'one.hooky' - if SLAB : begin - include : CenterBottomSerif (MIDDLE + ONEBALANCE) 0 LONGJUT - save 'one' '1' + sketch # one.serifed + include glyphs.'one.hooky' AS_BASE + include : CenterBottomSerif (MIDDLE + ONEBALANCE) 0 LONGJUT + save 'one.serifed' + + select-variant 'one' '1' sketch # two include markset.capital diff --git a/meta/features.ptl b/meta/features.ptl index 1fecca644..2db2a0bbb 100644 --- a/meta/features.ptl +++ b/meta/features.ptl @@ -118,11 +118,12 @@ define [buildGSUB para glyphList markGlyphs] : begin commonList.push feature set lookups.(feature).subtables.0.(glyph.name) fs.(feature) # ssxx - foreach [{name composition} : pairs-of para.variants] : if (name.length === 4 && composition.__isComposite) : begin - commonList.push name - local tags {.} - foreach [{ch tag} : pairs-of composition.__cvmap] : set tags.(tag) true - set features.(name) : [Object.keys tags].filter (tag => tags.(tag)) + foreach [{name composition} : pairs-of para.variants] : begin + if (name.length === 4 && composition.__isComposite && [name.slice 0 2] === 'ss') : begin + commonList.push name + local tags {.} + foreach [{ch tag} : pairs-of composition.__cvmap] : set tags.(tag) true + set features.(name) : [Object.keys tags].filter (tag => tags.(tag)) set languages.'cyrl_SRB ' {.features [{'locl_srb'}.concat commonList]} set languages.'cyrl_MKD ' {.features [{'locl_srb'}.concat commonList]} diff --git a/variants.toml b/variants.toml index b321bd07b..f3deb6d86 100644 --- a/variants.toml +++ b/variants.toml @@ -199,6 +199,14 @@ tag = "cv48" y = "curly" tag = "cv49" +[simple.v-one-hooky] +one = "hooky" +tag = "cv50" + +[simple.v-one-serifed] +one = "serifed" +tag = "cv51" + [simple.others] I = 'serifed' J = 'serifed' @@ -221,6 +229,7 @@ design = [ 'v-dollar-through', 'v-numbersign-upright', 'v-three-twoarcs', + 'v-one-hooky', 'others' ] upright = [ @@ -238,6 +247,9 @@ italic = [ 'v-y-curly' ] +[composite.slab] +design = ['v-one-serifed'] + # Composite character options, overrides default settings above. # Andale Mono Style [composite.ss01]