* \[Experimental\] Add a font feature for texture control (#2081).

- Currently only available through custom builds with `build-texture-feature = true`.
This commit is contained in:
be5invis 2023-11-10 03:27:51 -08:00
parent d91cbeca6c
commit cfb3826680
9 changed files with 179 additions and 4 deletions

View file

@ -3,3 +3,5 @@
* Fix serifs of GREEK LETTER DIGAMMA (`U+03DC`) under `ss12`.
* Improve crossbar position of GREEK SMALL LETTER DIGAMMA (`U+03DD`) and add a middle serif under slab.
* Refine Greek Capital Sho (U+03F7) glyph (#2079).
* \[Experimental\] Add a font feature for texture control (#2081).
- Currently only available through custom builds with `build-texture-feature = true`.

View file

@ -3,7 +3,7 @@ $$include '../../meta/macros.ptl'
import [linreg clamp mix fallback] from"../../support/utils.mjs"
import [getGrTree IsSuperscript IsSubscript] from"../../support/gr.mjs"
import [AnyCv DotlessOrNot CvDecompose MathSansSerif] from"../../support/gr.mjs"
import [AnyCv DotlessOrNot CvDecompose MathSansSerif Texture] from"../../support/gr.mjs"
import [NumeratorForm DenominatorForm] from"../../support/gr.mjs"
import [Transform] from"../../support/geometry/transform.mjs"
extern Map
@ -693,6 +693,68 @@ glyph-block Autobuild-Transformed : begin
link-relations relSets
glyph-block Autobuild-Transformed-Texture : begin
if (!(para.buildTexture && !para.isQuasiProportional)) : return nothing
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives
glyph-block-import Recursive-Build : Fork
glyph-block-import Autobuild-Transformed-Shared : extendRelatedGlyphs link-relations wrapName
define [createTextureDerivatives gr extL extR _records] : begin
local { records relSets targetNameMap } : extendRelatedGlyphs gr.key _records
local pendingGlyphs : records.map : [record] => record.1
local forkedPara : Object.assign {.} para
if (extL + extR > 0)
: then : forkedPara.diversityM = 1 + extL + extR
: else : begin
forkedPara.diversityF = 1 + extL + extR
forkedPara.diversityI = 1 + extL + extR
forkedPara.diversityII = 1 + extL + extR
local forked : Fork pendingGlyphs forkedPara
foreach {unicode glyphid} [items-of records] : begin
if [not : query-glyph targetNameMap.(glyphid)] : begin
define glyphT : forked.queryByName glyphid
define glyphO : glyphStore.queryByName glyphid
if (glyphT && glyphO) : begin
if (glyphT.advanceWidth != glyphO.advanceWidth) : begin
gr.set glyphO targetNameMap.(glyphid)
create-glyph targetNameMap.(glyphid) unicode : glyph-proc
include glyphT AS_BASE ALSO_METRICS
set-width Width
if extL : currentGlyph.applyTransform [Translate (-extL * Width) 0] true
link-relations relSets
define ranges : list
list 0x41 0x5A
list 0x61 0x7A
list 0xC0 0xFF
list 0x100 0x2AF
list 0x370 0x3FF
list 0x400 0x4FF
list 0x500 0x52F
define [jobs base] : list
local results {}
foreach {low high} [items-of ranges] : begin
foreach lch [range low till high] : begin
local source : glyphStore.queryNameByUnicode lch
if source : results.push { null source }
return results
define EXTENSION : 1 / 12
define SHRINK : -1 / 12
createTextureDerivatives Texture.ExtL EXTENSION 0 [jobs 0xF000]
createTextureDerivatives Texture.ExtR 0 EXTENSION [jobs 0xF100]
createTextureDerivatives Texture.ExtLR EXTENSION EXTENSION [jobs 0xF200]
createTextureDerivatives Texture.ShrL SHRINK 0 [jobs 0xF300]
createTextureDerivatives Texture.ShrR 0 SHRINK [jobs 0xF400]
createTextureDerivatives Texture.ShrLR SHRINK SHRINK [jobs 0xF500]
glyph-block Autobuild-Transformed-Mathematical : begin
glyph-block-import CommonShapes
glyph-block-import Common-Derivatives

View file

@ -137,4 +137,6 @@ export : define [buildCVSS gsub para glyphStore] : begin
gsub.endBlock rec
return cvs
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length

View file

@ -0,0 +1,88 @@
$$include '../meta/macros.ptl'
extern Set
import [Texture CvDecompose] from"../support/gr.mjs"
# Name-driven feature pairs
export : define [buildGsubTexture gsub glyphStore markGlyphs cvs] : begin
local anyMark : Array.from markGlyphs.all
local rec : gsub.beginBlock
define txtr : gsub.addCommonFeature : gsub.createFeature 'TXTR'
define { chain-rule reverse-rule } : gsub.ChainRuleBuilder
local extRFrom { }
local extRTo { }
local extLFrom { }
local extLTo { }
local shrLFrom { }
local shrLTo { }
local shrRFrom { }
local shrRTo { }
local anyInfluence : new Set
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== ".") : begin
local extL : Texture.ExtL.get g
local extR : Texture.ExtR.get g
local extLR : Texture.ExtLR.get g
local shrL : Texture.ShrL.get g
local shrR : Texture.ShrR.get g
local shrLR : Texture.ShrLR.get g
if extR : begin [extRFrom.push gid] [extRTo.push extR]
if extL : begin [extLFrom.push gid] [extLTo.push extL]
if (extR && extLR) : begin [extLFrom.push extR] [extLTo.push extLR]
if shrL : begin [shrLFrom.push gid] [shrLTo.push shrL]
if shrR : begin [shrRFrom.push gid] [shrRTo.push shrR]
if (shrL && shrLR) : begin [shrRFrom.push shrL] [shrRTo.push shrLR]
if (extL || extR || shrL || shrR) : anyInfluence.add gid
define subExtR : gsub.createLookup
.type 'gsub_chaining'
.ignoreGlyphs anyMark
.rules : list
chain-rule
extRFrom ~> extRTo
shrLFrom ~> shrLTo
define subExtL : gsub.createLookup
.type 'gsub_chaining'
.ignoreGlyphs anyMark
.rules : list
chain-rule
shrRFrom ~> shrRTo
extLFrom ~> extLTo
txtr.addLookup subExtR
txtr.addLookup subExtL
gsub.setDependency subExtR subExtL
# Decompose everything if we enable TXTR
if cvs
: then : begin
# Reuse existing Cvdecompose data
foreach cv [cvs.values] : begin
if cv.decompositionLookup : begin
txtr.addLookup cv.decompositionLookup
gsub.setDependency cv.decompositionLookup subExtR
: else : begin
# Built it from scratch
local decompose : gsub.createLookup
.type 'gsub_multiple'
.substitutions {.}
foreach { gn glyph } [glyphStore.namedEntries] : begin
local parts : CvDecompose.get glyph
if parts : begin
local influenced : anyInfluence.has gn
foreach part [items-of parts] : if [anyInfluence.has part] : set influenced true
if influenced : set decompose.substitutions.(gn) parts
txtr.addLookup decompose
gsub.setDependency decompose subExtR
gsub.endBlock rec

View file

@ -10,6 +10,7 @@ import [buildFrac] from"./gsub-frac.mjs"
import [buildCVSS] from"./gsub-cv-ss.mjs"
import [buildLOCL] from"./gsub-locl.mjs"
import [buildGsubThousands] from"./gsub-thousands.mjs"
import [buildGsubTexture] from"./gsub-texture.mjs"
import [buildMarkMkmk] from"./gpos-mark-mkmk.mjs"
define GDEF_SIMPLE 1
@ -60,8 +61,9 @@ define [buildGSUB para glyphStore markGlyphs] : begin
buildGsubThousands gsub para glyphStore
# cv##, ss##
local cvs nothing
if para.enableCvSs : begin
buildCVSS gsub para glyphStore
set cvs : buildCVSS gsub para glyphStore
# ccmp post cv/ss (for Ogonek shape transform)
buildCCMPPostCvSs gsub ccmp glyphStore markGlyphs
@ -70,6 +72,10 @@ define [buildGSUB para glyphStore markGlyphs] : begin
# Builds last, but the lookups are added into the beginning of the lookup list
buildLOCL gsub para glyphStore
# TXTR, "texture" feature
if (para.buildTexture && !para.isQuasiProportional) : begin
buildGsubTexture gsub glyphStore markGlyphs cvs
gsub.finalize
return gsub

View file

@ -23,8 +23,19 @@ export const VS01 = LinkedGlyphProp("VS01");
export const TieMark = LinkedGlyphProp("TieMark");
export const LeaningMark = LinkedGlyphProp("LeaningMark");
export const LeaningMarkSpacer = LinkedGlyphProp("LeaningMarkSpacer");
export const Texture = {
ExtL: LinkedGlyphProp("TextureExtL"),
ExtR: LinkedGlyphProp("TextureExtR"),
ExtLR: LinkedGlyphProp("TextureExtLR"),
ShrL: LinkedGlyphProp("TextureShrL"),
ShrR: LinkedGlyphProp("TextureShrR"),
ShrLR: LinkedGlyphProp("TextureShrLR")
};
function LinkedGlyphProp(key) {
return {
key,
get(glyph) {
if (glyph && glyph.related) return glyph.related[key];
else return null;

View file

@ -11,6 +11,7 @@ export function init(data, argv) {
applyAlternatesParam(argv, para, data, "slope", "slope");
if (argv.featureControl.noCvSs) para.enableCvSs = false;
if (argv.featureControl.noLigation) para.enableLigation = false;
if (argv.featureControl.buildTexture) para.buildTexture = true;
return para;
}
function applyBlendingParam(argv, para, data, key, keyArgv) {

View file

@ -3,7 +3,8 @@ import UnicodeDataIndex from "@unicode/unicode-15.0.0";
export async function collectBlockData() {
const BlockData = [
[[0xe0a0, 0xe0df], "Private Use Area — Powerline"],
[[0xee00, 0xee3f], "Private Use Area — Progress Bar"]
[[0xee00, 0xee3f], "Private Use Area — Progress Bar"],
[[0xf000, 0xf8ff], "Private Use Area — Texture"]
];
for (const id of UnicodeDataIndex.Block) {

View file

@ -230,6 +230,7 @@ const CompositesFromBuildPlan = computed(`metadata:composites-from-build-plan`,
return data;
});
// eslint-disable-next-line complexity
const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileName) => {
const [{ fileNameToBpMap, buildPlans }] = await target.need(BuildPlans);
const [version] = await target.need(Version);
@ -261,7 +262,8 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
featureControl: {
noCvSs: bp["no-cv-ss"] || false,
noLigation: bp["no-ligation"] || false,
exportGlyphNames: bp["export-glyph-names"] || false
exportGlyphNames: bp["export-glyph-names"] || false,
buildTexture: bp["build-texture-feature"] || false
},
// Ligations
ligations: bp.ligations || null,