@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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/browser-module.mjs +13660 -0
  4. package/dist/browser-module.mjs.map +1 -0
  5. package/dist/browser.cjs +13689 -0
  6. package/dist/browser.cjs.map +1 -0
  7. package/dist/main.cjs +13712 -0
  8. package/dist/main.cjs.map +1 -0
  9. package/dist/module.mjs +13673 -0
  10. package/dist/module.mjs.map +1 -0
  11. package/package.json +99 -0
  12. package/src/CmapProcessor.js +285 -0
  13. package/src/DFont.js +113 -0
  14. package/src/TTFFont.js +621 -0
  15. package/src/TrueTypeCollection.js +65 -0
  16. package/src/WOFF2Font.js +222 -0
  17. package/src/WOFFFont.js +56 -0
  18. package/src/aat/AATFeatureMap.js +545 -0
  19. package/src/aat/AATLayoutEngine.js +48 -0
  20. package/src/aat/AATLookupTable.js +125 -0
  21. package/src/aat/AATMorxProcessor.js +429 -0
  22. package/src/aat/AATStateMachine.js +96 -0
  23. package/src/base.js +29 -0
  24. package/src/cff/CFFCharsets.js +99 -0
  25. package/src/cff/CFFDict.js +166 -0
  26. package/src/cff/CFFEncodings.js +48 -0
  27. package/src/cff/CFFFont.js +158 -0
  28. package/src/cff/CFFIndex.js +150 -0
  29. package/src/cff/CFFOperand.js +135 -0
  30. package/src/cff/CFFPointer.js +50 -0
  31. package/src/cff/CFFPrivateDict.js +39 -0
  32. package/src/cff/CFFStandardStrings.js +71 -0
  33. package/src/cff/CFFTop.js +236 -0
  34. package/src/decorators.js +36 -0
  35. package/src/encodings.js +219 -0
  36. package/src/fs.js +12 -0
  37. package/src/glyph/BBox.js +72 -0
  38. package/src/glyph/CBDTGlyph.js +9 -0
  39. package/src/glyph/CFFGlyph.js +635 -0
  40. package/src/glyph/COLRGlyph.js +108 -0
  41. package/src/glyph/Glyph.js +270 -0
  42. package/src/glyph/GlyphVariationProcessor.js +487 -0
  43. package/src/glyph/Path.js +257 -0
  44. package/src/glyph/SBIXGlyph.js +54 -0
  45. package/src/glyph/StandardNames.js +27 -0
  46. package/src/glyph/TTFGlyph.js +408 -0
  47. package/src/glyph/TTFGlyphEncoder.js +158 -0
  48. package/src/glyph/WOFF2Glyph.js +70 -0
  49. package/src/index.js +15 -0
  50. package/src/layout/GlyphPosition.js +30 -0
  51. package/src/layout/GlyphRun.js +108 -0
  52. package/src/layout/KernProcessor.js +97 -0
  53. package/src/layout/LayoutEngine.js +190 -0
  54. package/src/layout/Script.js +231 -0
  55. package/src/layout/UnicodeLayoutEngine.js +250 -0
  56. package/src/node.js +16 -0
  57. package/src/opentype/GPOSProcessor.js +311 -0
  58. package/src/opentype/GSUBProcessor.js +208 -0
  59. package/src/opentype/GlyphInfo.js +57 -0
  60. package/src/opentype/GlyphIterator.js +82 -0
  61. package/src/opentype/OTLayoutEngine.js +117 -0
  62. package/src/opentype/OTProcessor.js +472 -0
  63. package/src/opentype/ShapingPlan.js +121 -0
  64. package/src/opentype/shapers/ArabicShaper.js +124 -0
  65. package/src/opentype/shapers/DefaultShaper.js +116 -0
  66. package/src/opentype/shapers/HangulShaper.js +285 -0
  67. package/src/opentype/shapers/HebrewShaper.js +105 -0
  68. package/src/opentype/shapers/IndicShaper.js +914 -0
  69. package/src/opentype/shapers/ThaiShaper.js +238 -0
  70. package/src/opentype/shapers/UniversalShaper.js +186 -0
  71. package/src/opentype/shapers/data.trie +0 -0
  72. package/src/opentype/shapers/gen-indic.js +208 -0
  73. package/src/opentype/shapers/gen-use.js +287 -0
  74. package/src/opentype/shapers/generate-data.js +33 -0
  75. package/src/opentype/shapers/index.js +109 -0
  76. package/src/opentype/shapers/indic-data.js +175 -0
  77. package/src/opentype/shapers/indic.json +1 -0
  78. package/src/opentype/shapers/indic.machine +31 -0
  79. package/src/opentype/shapers/indic.trie +0 -0
  80. package/src/opentype/shapers/use.json +1 -0
  81. package/src/opentype/shapers/use.machine +44 -0
  82. package/src/opentype/shapers/use.trie +0 -0
  83. package/src/packages/unicode-properties/LICENSE +8 -0
  84. package/src/packages/unicode-properties/README.md +12 -0
  85. package/src/packages/unicode-properties/data-trie.js +1 -0
  86. package/src/packages/unicode-properties/data.js +1 -0
  87. package/src/packages/unicode-properties/data.json +1 -0
  88. package/src/packages/unicode-properties/data.trie +0 -0
  89. package/src/packages/unicode-properties/dist/index.cjs +257 -0
  90. package/src/packages/unicode-properties/dist/index.cjs.map +7 -0
  91. package/src/packages/unicode-properties/dist/index.mjs +234 -0
  92. package/src/packages/unicode-properties/dist/index.mjs.map +7 -0
  93. package/src/packages/unicode-properties/generate.js +107 -0
  94. package/src/packages/unicode-properties/index.js +184 -0
  95. package/src/packages/unicode-properties/package.json +50 -0
  96. package/src/packages/unicode-trie/LICENSE +8 -0
  97. package/src/packages/unicode-trie/README.md +13 -0
  98. package/src/packages/unicode-trie/builder.js +965 -0
  99. package/src/packages/unicode-trie/dist/builder.cjs +711 -0
  100. package/src/packages/unicode-trie/dist/builder.cjs.map +7 -0
  101. package/src/packages/unicode-trie/dist/builder.mjs +690 -0
  102. package/src/packages/unicode-trie/dist/builder.mjs.map +7 -0
  103. package/src/packages/unicode-trie/dist/index.cjs +112 -0
  104. package/src/packages/unicode-trie/dist/index.cjs.map +7 -0
  105. package/src/packages/unicode-trie/dist/index.mjs +91 -0
  106. package/src/packages/unicode-trie/dist/index.mjs.map +7 -0
  107. package/src/packages/unicode-trie/index.js +135 -0
  108. package/src/packages/unicode-trie/package.json +49 -0
  109. package/src/packages/unicode-trie/swap.js +21 -0
  110. package/src/subset/CFFSubset.js +176 -0
  111. package/src/subset/Subset.js +63 -0
  112. package/src/subset/TTFSubset.js +130 -0
  113. package/src/tables/BASE.js +78 -0
  114. package/src/tables/COLR.js +25 -0
  115. package/src/tables/CPAL.js +24 -0
  116. package/src/tables/DSIG.js +21 -0
  117. package/src/tables/EBDT.js +91 -0
  118. package/src/tables/EBLC.js +80 -0
  119. package/src/tables/GDEF.js +57 -0
  120. package/src/tables/GPOS.js +209 -0
  121. package/src/tables/GSUB.js +85 -0
  122. package/src/tables/HVAR.js +44 -0
  123. package/src/tables/JSTF.js +43 -0
  124. package/src/tables/LTSH.js +10 -0
  125. package/src/tables/OS2.js +84 -0
  126. package/src/tables/PCLT.js +21 -0
  127. package/src/tables/STAT.js +99 -0
  128. package/src/tables/VDMX.js +33 -0
  129. package/src/tables/VORG.js +14 -0
  130. package/src/tables/WOFF2Directory.js +73 -0
  131. package/src/tables/WOFFDirectory.js +37 -0
  132. package/src/tables/aat.js +157 -0
  133. package/src/tables/avar.js +19 -0
  134. package/src/tables/bsln.js +31 -0
  135. package/src/tables/cmap.js +127 -0
  136. package/src/tables/cvt.js +6 -0
  137. package/src/tables/directory.js +58 -0
  138. package/src/tables/feat.js +28 -0
  139. package/src/tables/fpgm.js +8 -0
  140. package/src/tables/fvar.js +31 -0
  141. package/src/tables/gasp.js +15 -0
  142. package/src/tables/glyf.js +4 -0
  143. package/src/tables/gvar.js +27 -0
  144. package/src/tables/hdmx.js +15 -0
  145. package/src/tables/head.js +25 -0
  146. package/src/tables/hhea.js +19 -0
  147. package/src/tables/hmtx.js +11 -0
  148. package/src/tables/index.js +119 -0
  149. package/src/tables/just.js +81 -0
  150. package/src/tables/kern.js +91 -0
  151. package/src/tables/loca.js +30 -0
  152. package/src/tables/maxp.js +20 -0
  153. package/src/tables/morx.js +79 -0
  154. package/src/tables/name.js +157 -0
  155. package/src/tables/opbd.js +15 -0
  156. package/src/tables/opentype.js +217 -0
  157. package/src/tables/post.js +34 -0
  158. package/src/tables/prep.js +6 -0
  159. package/src/tables/sbix.js +17 -0
  160. package/src/tables/variations.js +80 -0
  161. package/src/tables/vhea.js +19 -0
  162. package/src/tables/vmtx.js +12 -0
  163. 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
+ }