@cantoo/fontkit 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/browser-module.mjs +13660 -0
- package/dist/browser-module.mjs.map +1 -0
- package/dist/browser.cjs +13689 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/main.cjs +13712 -0
- package/dist/main.cjs.map +1 -0
- package/dist/module.mjs +13673 -0
- package/dist/module.mjs.map +1 -0
- package/package.json +99 -0
- package/src/CmapProcessor.js +285 -0
- package/src/DFont.js +113 -0
- package/src/TTFFont.js +621 -0
- package/src/TrueTypeCollection.js +65 -0
- package/src/WOFF2Font.js +222 -0
- package/src/WOFFFont.js +56 -0
- package/src/aat/AATFeatureMap.js +545 -0
- package/src/aat/AATLayoutEngine.js +48 -0
- package/src/aat/AATLookupTable.js +125 -0
- package/src/aat/AATMorxProcessor.js +429 -0
- package/src/aat/AATStateMachine.js +96 -0
- package/src/base.js +29 -0
- package/src/cff/CFFCharsets.js +99 -0
- package/src/cff/CFFDict.js +166 -0
- package/src/cff/CFFEncodings.js +48 -0
- package/src/cff/CFFFont.js +158 -0
- package/src/cff/CFFIndex.js +150 -0
- package/src/cff/CFFOperand.js +135 -0
- package/src/cff/CFFPointer.js +50 -0
- package/src/cff/CFFPrivateDict.js +39 -0
- package/src/cff/CFFStandardStrings.js +71 -0
- package/src/cff/CFFTop.js +236 -0
- package/src/decorators.js +36 -0
- package/src/encodings.js +219 -0
- package/src/fs.js +12 -0
- package/src/glyph/BBox.js +72 -0
- package/src/glyph/CBDTGlyph.js +9 -0
- package/src/glyph/CFFGlyph.js +635 -0
- package/src/glyph/COLRGlyph.js +108 -0
- package/src/glyph/Glyph.js +270 -0
- package/src/glyph/GlyphVariationProcessor.js +487 -0
- package/src/glyph/Path.js +257 -0
- package/src/glyph/SBIXGlyph.js +54 -0
- package/src/glyph/StandardNames.js +27 -0
- package/src/glyph/TTFGlyph.js +408 -0
- package/src/glyph/TTFGlyphEncoder.js +158 -0
- package/src/glyph/WOFF2Glyph.js +70 -0
- package/src/index.js +15 -0
- package/src/layout/GlyphPosition.js +30 -0
- package/src/layout/GlyphRun.js +108 -0
- package/src/layout/KernProcessor.js +97 -0
- package/src/layout/LayoutEngine.js +190 -0
- package/src/layout/Script.js +231 -0
- package/src/layout/UnicodeLayoutEngine.js +250 -0
- package/src/node.js +16 -0
- package/src/opentype/GPOSProcessor.js +311 -0
- package/src/opentype/GSUBProcessor.js +208 -0
- package/src/opentype/GlyphInfo.js +57 -0
- package/src/opentype/GlyphIterator.js +82 -0
- package/src/opentype/OTLayoutEngine.js +117 -0
- package/src/opentype/OTProcessor.js +472 -0
- package/src/opentype/ShapingPlan.js +121 -0
- package/src/opentype/shapers/ArabicShaper.js +124 -0
- package/src/opentype/shapers/DefaultShaper.js +116 -0
- package/src/opentype/shapers/HangulShaper.js +285 -0
- package/src/opentype/shapers/HebrewShaper.js +105 -0
- package/src/opentype/shapers/IndicShaper.js +914 -0
- package/src/opentype/shapers/ThaiShaper.js +238 -0
- package/src/opentype/shapers/UniversalShaper.js +186 -0
- package/src/opentype/shapers/data.trie +0 -0
- package/src/opentype/shapers/gen-indic.js +208 -0
- package/src/opentype/shapers/gen-use.js +287 -0
- package/src/opentype/shapers/generate-data.js +33 -0
- package/src/opentype/shapers/index.js +109 -0
- package/src/opentype/shapers/indic-data.js +175 -0
- package/src/opentype/shapers/indic.json +1 -0
- package/src/opentype/shapers/indic.machine +31 -0
- package/src/opentype/shapers/indic.trie +0 -0
- package/src/opentype/shapers/use.json +1 -0
- package/src/opentype/shapers/use.machine +44 -0
- package/src/opentype/shapers/use.trie +0 -0
- package/src/packages/unicode-properties/LICENSE +8 -0
- package/src/packages/unicode-properties/README.md +12 -0
- package/src/packages/unicode-properties/data-trie.js +1 -0
- package/src/packages/unicode-properties/data.js +1 -0
- package/src/packages/unicode-properties/data.json +1 -0
- package/src/packages/unicode-properties/data.trie +0 -0
- package/src/packages/unicode-properties/dist/index.cjs +257 -0
- package/src/packages/unicode-properties/dist/index.cjs.map +7 -0
- package/src/packages/unicode-properties/dist/index.mjs +234 -0
- package/src/packages/unicode-properties/dist/index.mjs.map +7 -0
- package/src/packages/unicode-properties/generate.js +107 -0
- package/src/packages/unicode-properties/index.js +184 -0
- package/src/packages/unicode-properties/package.json +50 -0
- package/src/packages/unicode-trie/LICENSE +8 -0
- package/src/packages/unicode-trie/README.md +13 -0
- package/src/packages/unicode-trie/builder.js +965 -0
- package/src/packages/unicode-trie/dist/builder.cjs +711 -0
- package/src/packages/unicode-trie/dist/builder.cjs.map +7 -0
- package/src/packages/unicode-trie/dist/builder.mjs +690 -0
- package/src/packages/unicode-trie/dist/builder.mjs.map +7 -0
- package/src/packages/unicode-trie/dist/index.cjs +112 -0
- package/src/packages/unicode-trie/dist/index.cjs.map +7 -0
- package/src/packages/unicode-trie/dist/index.mjs +91 -0
- package/src/packages/unicode-trie/dist/index.mjs.map +7 -0
- package/src/packages/unicode-trie/index.js +135 -0
- package/src/packages/unicode-trie/package.json +49 -0
- package/src/packages/unicode-trie/swap.js +21 -0
- package/src/subset/CFFSubset.js +176 -0
- package/src/subset/Subset.js +63 -0
- package/src/subset/TTFSubset.js +130 -0
- package/src/tables/BASE.js +78 -0
- package/src/tables/COLR.js +25 -0
- package/src/tables/CPAL.js +24 -0
- package/src/tables/DSIG.js +21 -0
- package/src/tables/EBDT.js +91 -0
- package/src/tables/EBLC.js +80 -0
- package/src/tables/GDEF.js +57 -0
- package/src/tables/GPOS.js +209 -0
- package/src/tables/GSUB.js +85 -0
- package/src/tables/HVAR.js +44 -0
- package/src/tables/JSTF.js +43 -0
- package/src/tables/LTSH.js +10 -0
- package/src/tables/OS2.js +84 -0
- package/src/tables/PCLT.js +21 -0
- package/src/tables/STAT.js +99 -0
- package/src/tables/VDMX.js +33 -0
- package/src/tables/VORG.js +14 -0
- package/src/tables/WOFF2Directory.js +73 -0
- package/src/tables/WOFFDirectory.js +37 -0
- package/src/tables/aat.js +157 -0
- package/src/tables/avar.js +19 -0
- package/src/tables/bsln.js +31 -0
- package/src/tables/cmap.js +127 -0
- package/src/tables/cvt.js +6 -0
- package/src/tables/directory.js +58 -0
- package/src/tables/feat.js +28 -0
- package/src/tables/fpgm.js +8 -0
- package/src/tables/fvar.js +31 -0
- package/src/tables/gasp.js +15 -0
- package/src/tables/glyf.js +4 -0
- package/src/tables/gvar.js +27 -0
- package/src/tables/hdmx.js +15 -0
- package/src/tables/head.js +25 -0
- package/src/tables/hhea.js +19 -0
- package/src/tables/hmtx.js +11 -0
- package/src/tables/index.js +119 -0
- package/src/tables/just.js +81 -0
- package/src/tables/kern.js +91 -0
- package/src/tables/loca.js +30 -0
- package/src/tables/maxp.js +20 -0
- package/src/tables/morx.js +79 -0
- package/src/tables/name.js +157 -0
- package/src/tables/opbd.js +15 -0
- package/src/tables/opentype.js +217 -0
- package/src/tables/post.js +34 -0
- package/src/tables/prep.js +6 -0
- package/src/tables/sbix.js +17 -0
- package/src/tables/variations.js +80 -0
- package/src/tables/vhea.js +19 -0
- package/src/tables/vmtx.js +12 -0
- package/src/utils.js +62 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import BBox from '../glyph/BBox';
|
|
2
|
+
import * as Script from '../layout/Script';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a run of Glyph and GlyphPosition objects.
|
|
6
|
+
* Returned by the font layout method.
|
|
7
|
+
*/
|
|
8
|
+
export default class GlyphRun {
|
|
9
|
+
constructor(glyphs, features, script, language, direction) {
|
|
10
|
+
/**
|
|
11
|
+
* An array of Glyph objects in the run
|
|
12
|
+
* @type {Glyph[]}
|
|
13
|
+
*/
|
|
14
|
+
this.glyphs = glyphs;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An array of GlyphPosition objects for each glyph in the run
|
|
18
|
+
* @type {GlyphPosition[]}
|
|
19
|
+
*/
|
|
20
|
+
this.positions = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The script that was requested for shaping. This was either passed in or detected automatically.
|
|
24
|
+
* @type {string}
|
|
25
|
+
*/
|
|
26
|
+
this.script = script;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The language requested for shaping, as passed in. If `null`, the default language for the
|
|
30
|
+
* script was used.
|
|
31
|
+
* @type {string}
|
|
32
|
+
*/
|
|
33
|
+
this.language = language || null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The direction requested for shaping, as passed in (either ltr or rtl).
|
|
37
|
+
* If `null`, the default direction of the script is used.
|
|
38
|
+
* @type {string}
|
|
39
|
+
*/
|
|
40
|
+
this.direction = direction || Script.direction(script);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The features requested during shaping. This is a combination of user
|
|
44
|
+
* specified features and features chosen by the shaper.
|
|
45
|
+
* @type {object}
|
|
46
|
+
*/
|
|
47
|
+
this.features = {};
|
|
48
|
+
|
|
49
|
+
// Convert features to an object
|
|
50
|
+
if (Array.isArray(features)) {
|
|
51
|
+
for (let tag of features) {
|
|
52
|
+
this.features[tag] = true;
|
|
53
|
+
}
|
|
54
|
+
} else if (typeof features === 'object') {
|
|
55
|
+
this.features = features;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The total advance width of the run.
|
|
61
|
+
* @type {number}
|
|
62
|
+
*/
|
|
63
|
+
get advanceWidth() {
|
|
64
|
+
let width = 0;
|
|
65
|
+
for (let position of this.positions) {
|
|
66
|
+
width += position.xAdvance;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return width;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The total advance height of the run.
|
|
74
|
+
* @type {number}
|
|
75
|
+
*/
|
|
76
|
+
get advanceHeight() {
|
|
77
|
+
let height = 0;
|
|
78
|
+
for (let position of this.positions) {
|
|
79
|
+
height += position.yAdvance;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return height;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The bounding box containing all glyphs in the run.
|
|
87
|
+
* @type {BBox}
|
|
88
|
+
*/
|
|
89
|
+
get bbox() {
|
|
90
|
+
let bbox = new BBox;
|
|
91
|
+
|
|
92
|
+
let x = 0;
|
|
93
|
+
let y = 0;
|
|
94
|
+
for (let index = 0; index < this.glyphs.length; index++) {
|
|
95
|
+
let glyph = this.glyphs[index];
|
|
96
|
+
let p = this.positions[index];
|
|
97
|
+
let b = glyph.bbox;
|
|
98
|
+
|
|
99
|
+
bbox.addPoint(b.minX + x + p.xOffset, b.minY + y + p.yOffset);
|
|
100
|
+
bbox.addPoint(b.maxX + x + p.xOffset, b.maxY + y + p.yOffset);
|
|
101
|
+
|
|
102
|
+
x += p.xAdvance;
|
|
103
|
+
y += p.yAdvance;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return bbox;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {binarySearch} from '../utils';
|
|
2
|
+
|
|
3
|
+
export default class KernProcessor {
|
|
4
|
+
constructor(font) {
|
|
5
|
+
this.kern = font.kern;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
process(glyphs, positions) {
|
|
9
|
+
for (let glyphIndex = 0; glyphIndex < glyphs.length - 1; glyphIndex++) {
|
|
10
|
+
let left = glyphs[glyphIndex].id;
|
|
11
|
+
let right = glyphs[glyphIndex + 1].id;
|
|
12
|
+
positions[glyphIndex].xAdvance += this.getKerning(left, right);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getKerning(left, right) {
|
|
17
|
+
let res = 0;
|
|
18
|
+
|
|
19
|
+
for (let table of this.kern.tables) {
|
|
20
|
+
if (table.coverage.crossStream) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
switch (table.version) {
|
|
25
|
+
case 0:
|
|
26
|
+
if (!table.coverage.horizontal) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
break;
|
|
31
|
+
case 1:
|
|
32
|
+
if (table.coverage.vertical || table.coverage.variation) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`Unsupported kerning table version ${table.version}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let val = 0;
|
|
42
|
+
let s = table.subtable;
|
|
43
|
+
switch (table.format) {
|
|
44
|
+
case 0: {
|
|
45
|
+
let pairIdx = binarySearch(s.pairs, function (pair) {
|
|
46
|
+
return (left - pair.left) || (right - pair.right);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (pairIdx >= 0) {
|
|
50
|
+
val = s.pairs[pairIdx].value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
case 2: {
|
|
57
|
+
let leftOffset, rightOffset = 0;
|
|
58
|
+
if (left >= s.leftTable.firstGlyph && left < s.leftTable.firstGlyph + s.leftTable.nGlyphs) {
|
|
59
|
+
leftOffset = s.leftTable.offsets[left - s.leftTable.firstGlyph];
|
|
60
|
+
} else {
|
|
61
|
+
leftOffset = s.array.off;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (right >= s.rightTable.firstGlyph && right < s.rightTable.firstGlyph + s.rightTable.nGlyphs) {
|
|
65
|
+
rightOffset = s.rightTable.offsets[right - s.rightTable.firstGlyph];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let index = (leftOffset + rightOffset - s.array.off) / 2;
|
|
69
|
+
val = s.array.values.get(index);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case 3: {
|
|
74
|
+
if (left >= s.glyphCount || right >= s.glyphCount) {
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
val = s.kernValue[s.kernIndex[s.leftClass[left] * s.rightClassCount + s.rightClass[right]]];
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
default:
|
|
83
|
+
throw new Error(`Unsupported kerning sub-table format ${table.format}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Microsoft supports the override flag, which resets the result
|
|
87
|
+
// Otherwise, the sum of the results from all subtables is returned
|
|
88
|
+
if (table.coverage.override) {
|
|
89
|
+
res = val;
|
|
90
|
+
} else {
|
|
91
|
+
res += val;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return res;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import KernProcessor from './KernProcessor';
|
|
2
|
+
import UnicodeLayoutEngine from './UnicodeLayoutEngine';
|
|
3
|
+
import GlyphRun from './GlyphRun';
|
|
4
|
+
import GlyphPosition from './GlyphPosition';
|
|
5
|
+
import * as Script from './Script';
|
|
6
|
+
import AATLayoutEngine from '../aat/AATLayoutEngine';
|
|
7
|
+
import OTLayoutEngine from '../opentype/OTLayoutEngine';
|
|
8
|
+
|
|
9
|
+
export default class LayoutEngine {
|
|
10
|
+
constructor(font) {
|
|
11
|
+
this.font = font;
|
|
12
|
+
this.unicodeLayoutEngine = null;
|
|
13
|
+
this.kernProcessor = null;
|
|
14
|
+
|
|
15
|
+
// Choose an advanced layout engine. We try the AAT morx table first since more
|
|
16
|
+
// scripts are currently supported because the shaping logic is built into the font.
|
|
17
|
+
if (this.font.morx) {
|
|
18
|
+
this.engine = new AATLayoutEngine(this.font);
|
|
19
|
+
|
|
20
|
+
} else if (this.font.GSUB || this.font.GPOS) {
|
|
21
|
+
this.engine = new OTLayoutEngine(this.font);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
layout(string, features, script, language, direction) {
|
|
26
|
+
// Make the features parameter optional
|
|
27
|
+
if (typeof features === 'string') {
|
|
28
|
+
direction = language;
|
|
29
|
+
language = script;
|
|
30
|
+
script = features;
|
|
31
|
+
features = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Map string to glyphs if needed
|
|
35
|
+
let glyphs;
|
|
36
|
+
if (typeof string === 'string') {
|
|
37
|
+
// Attempt to detect the script from the string if not provided.
|
|
38
|
+
if (script == null) {
|
|
39
|
+
script = Script.forString(string);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
glyphs = this.font.glyphsForString(string);
|
|
43
|
+
} else {
|
|
44
|
+
// Attempt to detect the script from the glyph code points if not provided.
|
|
45
|
+
if (script == null) {
|
|
46
|
+
let codePoints = [];
|
|
47
|
+
for (let glyph of string) {
|
|
48
|
+
codePoints.push(...glyph.codePoints);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
script = Script.forCodePoints(codePoints);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
glyphs = string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let glyphRun = new GlyphRun(glyphs, features, script, language, direction);
|
|
58
|
+
|
|
59
|
+
// Return early if there are no glyphs
|
|
60
|
+
if (glyphs.length === 0) {
|
|
61
|
+
glyphRun.positions = [];
|
|
62
|
+
return glyphRun;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Setup the advanced layout engine
|
|
66
|
+
if (this.engine && this.engine.setup) {
|
|
67
|
+
this.engine.setup(glyphRun);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Substitute and position the glyphs
|
|
71
|
+
this.substitute(glyphRun);
|
|
72
|
+
this.position(glyphRun);
|
|
73
|
+
|
|
74
|
+
this.hideDefaultIgnorables(glyphRun.glyphs, glyphRun.positions);
|
|
75
|
+
|
|
76
|
+
// Let the layout engine clean up any state it might have
|
|
77
|
+
if (this.engine && this.engine.cleanup) {
|
|
78
|
+
this.engine.cleanup();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return glyphRun;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
substitute(glyphRun) {
|
|
85
|
+
// Call the advanced layout engine to make substitutions
|
|
86
|
+
if (this.engine && this.engine.substitute) {
|
|
87
|
+
this.engine.substitute(glyphRun);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
position(glyphRun) {
|
|
92
|
+
// Get initial glyph positions
|
|
93
|
+
glyphRun.positions = glyphRun.glyphs.map(glyph => new GlyphPosition(glyph.advanceWidth));
|
|
94
|
+
let positioned = null;
|
|
95
|
+
|
|
96
|
+
// Call the advanced layout engine. Returns the features applied.
|
|
97
|
+
if (this.engine && this.engine.position) {
|
|
98
|
+
positioned = this.engine.position(glyphRun);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// if there is no GPOS table, use unicode properties to position marks.
|
|
102
|
+
if (!positioned && (!this.engine || this.engine.fallbackPosition)) {
|
|
103
|
+
if (!this.unicodeLayoutEngine) {
|
|
104
|
+
this.unicodeLayoutEngine = new UnicodeLayoutEngine(this.font);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.unicodeLayoutEngine.positionGlyphs(glyphRun.glyphs, glyphRun.positions);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// if kerning is not supported by GPOS, do kerning with the TrueType/AAT kern table
|
|
111
|
+
if ((!positioned || !positioned.kern) && glyphRun.features.kern !== false && this.font.kern) {
|
|
112
|
+
if (!this.kernProcessor) {
|
|
113
|
+
this.kernProcessor = new KernProcessor(this.font);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.kernProcessor.process(glyphRun.glyphs, glyphRun.positions);
|
|
117
|
+
glyphRun.features.kern = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
hideDefaultIgnorables(glyphs, positions) {
|
|
122
|
+
let space = this.font.glyphForCodePoint(0x20);
|
|
123
|
+
for (let i = 0; i < glyphs.length; i++) {
|
|
124
|
+
if (this.isDefaultIgnorable(glyphs[i].codePoints[0])) {
|
|
125
|
+
glyphs[i] = space;
|
|
126
|
+
positions[i].xAdvance = 0;
|
|
127
|
+
positions[i].yAdvance = 0;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
isDefaultIgnorable(ch) {
|
|
133
|
+
// From DerivedCoreProperties.txt in the Unicode database,
|
|
134
|
+
// minus U+115F, U+1160, U+3164 and U+FFA0, which is what
|
|
135
|
+
// Harfbuzz and Uniscribe do.
|
|
136
|
+
let plane = ch >> 16;
|
|
137
|
+
if (plane === 0) {
|
|
138
|
+
// BMP
|
|
139
|
+
switch (ch >> 8) {
|
|
140
|
+
case 0x00: return ch === 0x00AD;
|
|
141
|
+
case 0x03: return ch === 0x034F;
|
|
142
|
+
case 0x06: return ch === 0x061C;
|
|
143
|
+
case 0x17: return 0x17B4 <= ch && ch <= 0x17B5;
|
|
144
|
+
case 0x18: return 0x180B <= ch && ch <= 0x180E;
|
|
145
|
+
case 0x20: return (0x200B <= ch && ch <= 0x200F) || (0x202A <= ch && ch <= 0x202E) || (0x2060 <= ch && ch <= 0x206F);
|
|
146
|
+
case 0xFE: return (0xFE00 <= ch && ch <= 0xFE0F) || ch === 0xFEFF;
|
|
147
|
+
case 0xFF: return 0xFFF0 <= ch && ch <= 0xFFF8;
|
|
148
|
+
default: return false;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// Other planes
|
|
152
|
+
switch (plane) {
|
|
153
|
+
case 0x01: return (0x1BCA0 <= ch && ch <= 0x1BCA3) || (0x1D173 <= ch && ch <= 0x1D17A);
|
|
154
|
+
case 0x0E: return 0xE0000 <= ch && ch <= 0xE0FFF;
|
|
155
|
+
default: return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
getAvailableFeatures(script, language) {
|
|
161
|
+
let features = [];
|
|
162
|
+
|
|
163
|
+
if (this.engine) {
|
|
164
|
+
features.push(...this.engine.getAvailableFeatures(script, language));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (this.font.kern && features.indexOf('kern') === -1) {
|
|
168
|
+
features.push('kern');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return features;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
stringsForGlyph(gid) {
|
|
175
|
+
let result = new Set;
|
|
176
|
+
|
|
177
|
+
let codePoints = this.font._cmapProcessor.codePointsForGlyph(gid);
|
|
178
|
+
for (let codePoint of codePoints) {
|
|
179
|
+
result.add(String.fromCodePoint(codePoint));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (this.engine && this.engine.stringsForGlyph) {
|
|
183
|
+
for (let string of this.engine.stringsForGlyph(gid)) {
|
|
184
|
+
result.add(string);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return Array.from(result);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {getScript} from '../packages/unicode-properties/index.js';
|
|
2
|
+
|
|
3
|
+
// This maps the Unicode Script property to an OpenType script tag
|
|
4
|
+
// Data from http://www.microsoft.com/typography/otspec/scripttags.htm
|
|
5
|
+
// and http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt.
|
|
6
|
+
const UNICODE_SCRIPTS = {
|
|
7
|
+
Caucasian_Albanian: 'aghb',
|
|
8
|
+
Arabic: 'arab',
|
|
9
|
+
Imperial_Aramaic: 'armi',
|
|
10
|
+
Armenian: 'armn',
|
|
11
|
+
Avestan: 'avst',
|
|
12
|
+
Balinese: 'bali',
|
|
13
|
+
Bamum: 'bamu',
|
|
14
|
+
Bassa_Vah: 'bass',
|
|
15
|
+
Batak: 'batk',
|
|
16
|
+
Bengali: ['bng2', 'beng'],
|
|
17
|
+
Bopomofo: 'bopo',
|
|
18
|
+
Brahmi: 'brah',
|
|
19
|
+
Braille: 'brai',
|
|
20
|
+
Buginese: 'bugi',
|
|
21
|
+
Buhid: 'buhd',
|
|
22
|
+
Chakma: 'cakm',
|
|
23
|
+
Canadian_Aboriginal: 'cans',
|
|
24
|
+
Carian: 'cari',
|
|
25
|
+
Cham: 'cham',
|
|
26
|
+
Cherokee: 'cher',
|
|
27
|
+
Coptic: 'copt',
|
|
28
|
+
Cypriot: 'cprt',
|
|
29
|
+
Cyrillic: 'cyrl',
|
|
30
|
+
Devanagari: ['dev2', 'deva'],
|
|
31
|
+
Deseret: 'dsrt',
|
|
32
|
+
Duployan: 'dupl',
|
|
33
|
+
Egyptian_Hieroglyphs: 'egyp',
|
|
34
|
+
Elbasan: 'elba',
|
|
35
|
+
Ethiopic: 'ethi',
|
|
36
|
+
Georgian: 'geor',
|
|
37
|
+
Glagolitic: 'glag',
|
|
38
|
+
Gothic: 'goth',
|
|
39
|
+
Grantha: 'gran',
|
|
40
|
+
Greek: 'grek',
|
|
41
|
+
Gujarati: ['gjr2', 'gujr'],
|
|
42
|
+
Gurmukhi: ['gur2', 'guru'],
|
|
43
|
+
Hangul: 'hang',
|
|
44
|
+
Han: 'hani',
|
|
45
|
+
Hanunoo: 'hano',
|
|
46
|
+
Hebrew: 'hebr',
|
|
47
|
+
Hiragana: 'hira',
|
|
48
|
+
Pahawh_Hmong: 'hmng',
|
|
49
|
+
Katakana_Or_Hiragana: 'hrkt',
|
|
50
|
+
Old_Italic: 'ital',
|
|
51
|
+
Javanese: 'java',
|
|
52
|
+
Kayah_Li: 'kali',
|
|
53
|
+
Katakana: 'kana',
|
|
54
|
+
Kharoshthi: 'khar',
|
|
55
|
+
Khmer: 'khmr',
|
|
56
|
+
Khojki: 'khoj',
|
|
57
|
+
Kannada: ['knd2', 'knda'],
|
|
58
|
+
Kaithi: 'kthi',
|
|
59
|
+
Tai_Tham: 'lana',
|
|
60
|
+
Lao: 'lao ',
|
|
61
|
+
Latin: 'latn',
|
|
62
|
+
Lepcha: 'lepc',
|
|
63
|
+
Limbu: 'limb',
|
|
64
|
+
Linear_A: 'lina',
|
|
65
|
+
Linear_B: 'linb',
|
|
66
|
+
Lisu: 'lisu',
|
|
67
|
+
Lycian: 'lyci',
|
|
68
|
+
Lydian: 'lydi',
|
|
69
|
+
Mahajani: 'mahj',
|
|
70
|
+
Mandaic: 'mand',
|
|
71
|
+
Manichaean: 'mani',
|
|
72
|
+
Mende_Kikakui: 'mend',
|
|
73
|
+
Meroitic_Cursive: 'merc',
|
|
74
|
+
Meroitic_Hieroglyphs: 'mero',
|
|
75
|
+
Malayalam: ['mlm2', 'mlym'],
|
|
76
|
+
Modi: 'modi',
|
|
77
|
+
Mongolian: 'mong',
|
|
78
|
+
Mro: 'mroo',
|
|
79
|
+
Meetei_Mayek: 'mtei',
|
|
80
|
+
Myanmar: ['mym2', 'mymr'],
|
|
81
|
+
Old_North_Arabian: 'narb',
|
|
82
|
+
Nabataean: 'nbat',
|
|
83
|
+
Nko: 'nko ',
|
|
84
|
+
Ogham: 'ogam',
|
|
85
|
+
Ol_Chiki: 'olck',
|
|
86
|
+
Old_Turkic: 'orkh',
|
|
87
|
+
Oriya: ['ory2', 'orya'],
|
|
88
|
+
Osmanya: 'osma',
|
|
89
|
+
Palmyrene: 'palm',
|
|
90
|
+
Pau_Cin_Hau: 'pauc',
|
|
91
|
+
Old_Permic: 'perm',
|
|
92
|
+
Phags_Pa: 'phag',
|
|
93
|
+
Inscriptional_Pahlavi: 'phli',
|
|
94
|
+
Psalter_Pahlavi: 'phlp',
|
|
95
|
+
Phoenician: 'phnx',
|
|
96
|
+
Miao: 'plrd',
|
|
97
|
+
Inscriptional_Parthian: 'prti',
|
|
98
|
+
Rejang: 'rjng',
|
|
99
|
+
Runic: 'runr',
|
|
100
|
+
Samaritan: 'samr',
|
|
101
|
+
Old_South_Arabian: 'sarb',
|
|
102
|
+
Saurashtra: 'saur',
|
|
103
|
+
Shavian: 'shaw',
|
|
104
|
+
Sharada: 'shrd',
|
|
105
|
+
Siddham: 'sidd',
|
|
106
|
+
Khudawadi: 'sind',
|
|
107
|
+
Sinhala: 'sinh',
|
|
108
|
+
Sora_Sompeng: 'sora',
|
|
109
|
+
Sundanese: 'sund',
|
|
110
|
+
Syloti_Nagri: 'sylo',
|
|
111
|
+
Syriac: 'syrc',
|
|
112
|
+
Tagbanwa: 'tagb',
|
|
113
|
+
Takri: 'takr',
|
|
114
|
+
Tai_Le: 'tale',
|
|
115
|
+
New_Tai_Lue: 'talu',
|
|
116
|
+
Tamil: ['tml2', 'taml'],
|
|
117
|
+
Tai_Viet: 'tavt',
|
|
118
|
+
Telugu: ['tel2', 'telu'],
|
|
119
|
+
Tifinagh: 'tfng',
|
|
120
|
+
Tagalog: 'tglg',
|
|
121
|
+
Thaana: 'thaa',
|
|
122
|
+
Thai: 'thai',
|
|
123
|
+
Tibetan: 'tibt',
|
|
124
|
+
Tirhuta: 'tirh',
|
|
125
|
+
Ugaritic: 'ugar',
|
|
126
|
+
Vai: 'vai ',
|
|
127
|
+
Warang_Citi: 'wara',
|
|
128
|
+
Old_Persian: 'xpeo',
|
|
129
|
+
Cuneiform: 'xsux',
|
|
130
|
+
Yi: 'yi ',
|
|
131
|
+
Inherited: 'zinh',
|
|
132
|
+
Common: 'zyyy',
|
|
133
|
+
Unknown: 'zzzz'
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const OPENTYPE_SCRIPTS = {};
|
|
137
|
+
for (let script in UNICODE_SCRIPTS) {
|
|
138
|
+
let tag = UNICODE_SCRIPTS[script];
|
|
139
|
+
if (Array.isArray(tag)) {
|
|
140
|
+
for (let t of tag) {
|
|
141
|
+
OPENTYPE_SCRIPTS[t] = script;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
OPENTYPE_SCRIPTS[tag] = script;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function fromUnicode(script) {
|
|
149
|
+
return UNICODE_SCRIPTS[script];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function fromOpenType(tag) {
|
|
153
|
+
return OPENTYPE_SCRIPTS[tag];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function forString(string) {
|
|
157
|
+
let len = string.length;
|
|
158
|
+
let idx = 0;
|
|
159
|
+
while (idx < len) {
|
|
160
|
+
let code = string.charCodeAt(idx++);
|
|
161
|
+
|
|
162
|
+
// Check if this is a high surrogate
|
|
163
|
+
if (0xd800 <= code && code <= 0xdbff && idx < len) {
|
|
164
|
+
let next = string.charCodeAt(idx);
|
|
165
|
+
|
|
166
|
+
// Check if this is a low surrogate
|
|
167
|
+
if (0xdc00 <= next && next <= 0xdfff) {
|
|
168
|
+
idx++;
|
|
169
|
+
code = ((code & 0x3FF) << 10) + (next & 0x3FF) + 0x10000;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let script = getScript(code);
|
|
174
|
+
if (script !== 'Common' && script !== 'Inherited' && script !== 'Unknown') {
|
|
175
|
+
return UNICODE_SCRIPTS[script];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return UNICODE_SCRIPTS.Unknown;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function forCodePoints(codePoints) {
|
|
183
|
+
for (let i = 0; i < codePoints.length; i++) {
|
|
184
|
+
let codePoint = codePoints[i];
|
|
185
|
+
let script = getScript(codePoint);
|
|
186
|
+
if (script !== 'Common' && script !== 'Inherited' && script !== 'Unknown') {
|
|
187
|
+
return UNICODE_SCRIPTS[script];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return UNICODE_SCRIPTS.Unknown;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// The scripts in this map are written from right to left
|
|
195
|
+
const RTL = {
|
|
196
|
+
arab: true, // Arabic
|
|
197
|
+
hebr: true, // Hebrew
|
|
198
|
+
syrc: true, // Syriac
|
|
199
|
+
thaa: true, // Thaana
|
|
200
|
+
cprt: true, // Cypriot Syllabary
|
|
201
|
+
khar: true, // Kharosthi
|
|
202
|
+
phnx: true, // Phoenician
|
|
203
|
+
'nko ': true, // N'Ko
|
|
204
|
+
lydi: true, // Lydian
|
|
205
|
+
avst: true, // Avestan
|
|
206
|
+
armi: true, // Imperial Aramaic
|
|
207
|
+
phli: true, // Inscriptional Pahlavi
|
|
208
|
+
prti: true, // Inscriptional Parthian
|
|
209
|
+
sarb: true, // Old South Arabian
|
|
210
|
+
orkh: true, // Old Turkic, Orkhon Runic
|
|
211
|
+
samr: true, // Samaritan
|
|
212
|
+
mand: true, // Mandaic, Mandaean
|
|
213
|
+
merc: true, // Meroitic Cursive
|
|
214
|
+
mero: true, // Meroitic Hieroglyphs
|
|
215
|
+
|
|
216
|
+
// Unicode 7.0 (not listed on http://www.microsoft.com/typography/otspec/scripttags.htm)
|
|
217
|
+
mani: true, // Manichaean
|
|
218
|
+
mend: true, // Mende Kikakui
|
|
219
|
+
nbat: true, // Nabataean
|
|
220
|
+
narb: true, // Old North Arabian
|
|
221
|
+
palm: true, // Palmyrene
|
|
222
|
+
phlp: true // Psalter Pahlavi
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export function direction(script) {
|
|
226
|
+
if (RTL[script]) {
|
|
227
|
+
return 'rtl';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return 'ltr';
|
|
231
|
+
}
|