ntk 8.12.2 → 8.12.3
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/lib/text/font.js +32 -6
- package/lib/text/layout.js +1 -3
- package/lib/text/shape.js +20 -0
- package/package.json +1 -1
package/lib/text/font.js
CHANGED
|
@@ -75,6 +75,12 @@ export default class Font {
|
|
|
75
75
|
this.path = path;
|
|
76
76
|
/** stable cache key for glyph pages and font caches */
|
|
77
77
|
this.key = `${path}#${postscriptName || fkFont.postscriptName || ''}`;
|
|
78
|
+
// What the face's tables say, read once. fontkit's getters walk to the
|
|
79
|
+
// table on every read, and a text layout asks per run and per word: in
|
|
80
|
+
// a long document they were most of a relayout (see `metrics`).
|
|
81
|
+
this._upem = 0;
|
|
82
|
+
this._vertical = null;
|
|
83
|
+
this._space = -1;
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
static loadSync(path, postscriptName) {
|
|
@@ -214,28 +220,48 @@ export default class Font {
|
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
scale(size) {
|
|
217
|
-
return size / this.fk.unitsPerEm;
|
|
223
|
+
return size / (this._upem ||= this.fk.unitsPerEm);
|
|
218
224
|
}
|
|
219
225
|
|
|
220
226
|
/**
|
|
221
227
|
* Pixel-space metrics for a font size. `ascent`/`capHeight`/`xHeight` are
|
|
222
228
|
* positive (above baseline), `descent` is positive (below baseline).
|
|
229
|
+
*
|
|
230
|
+
* A new object every call, which a caller may keep or change; the numbers
|
|
231
|
+
* behind it are the face's, read from its tables once.
|
|
223
232
|
*/
|
|
224
233
|
metrics(size) {
|
|
234
|
+
const v = (this._vertical ??= {
|
|
235
|
+
ascent: this.fk.ascent,
|
|
236
|
+
descent: -this.fk.descent,
|
|
237
|
+
lineGap: this.fk.lineGap,
|
|
238
|
+
capHeight: this.fk.capHeight,
|
|
239
|
+
xHeight: this.fk.xHeight
|
|
240
|
+
});
|
|
225
241
|
const s = this.scale(size);
|
|
226
|
-
const ascent =
|
|
227
|
-
const descent =
|
|
228
|
-
const lineGap =
|
|
242
|
+
const ascent = v.ascent * s;
|
|
243
|
+
const descent = v.descent * s;
|
|
244
|
+
const lineGap = v.lineGap * s;
|
|
229
245
|
return {
|
|
230
246
|
ascent,
|
|
231
247
|
descent,
|
|
232
248
|
lineGap,
|
|
233
249
|
lineHeight: ascent + descent + lineGap,
|
|
234
|
-
capHeight:
|
|
235
|
-
xHeight:
|
|
250
|
+
capHeight: v.capHeight * s,
|
|
251
|
+
xHeight: v.xHeight * s
|
|
236
252
|
};
|
|
237
253
|
}
|
|
238
254
|
|
|
255
|
+
/**
|
|
256
|
+
* The advance of U+0020 at `size` — what a run of trailing spaces is
|
|
257
|
+
* worth to a line. Looked up once: it was a cmap lookup for every word a
|
|
258
|
+
* layout ended with a space, which in a paragraph is every word.
|
|
259
|
+
*/
|
|
260
|
+
spaceAdvance(size) {
|
|
261
|
+
if (this._space < 0) this._space = this.fk.glyphForCodePoint(0x20).advanceWidth;
|
|
262
|
+
return this._space * this.scale(size);
|
|
263
|
+
}
|
|
264
|
+
|
|
239
265
|
hasGlyph(codepoint) {
|
|
240
266
|
return this.fk.hasGlyphForCodePoint(codepoint);
|
|
241
267
|
}
|
package/lib/text/layout.js
CHANGED
|
@@ -324,10 +324,8 @@ export class TextLayout {
|
|
|
324
324
|
if (last) {
|
|
325
325
|
const m = TRAILING_WS.exec(last.text);
|
|
326
326
|
if (m) {
|
|
327
|
-
const spaceGlyph = last.span.font.fk.glyphForCodePoint(0x20);
|
|
328
327
|
const spacing = Number.isFinite(last.span.letterSpacing) ? last.span.letterSpacing : 0;
|
|
329
|
-
wsWidth =
|
|
330
|
-
m[0].length * (spaceGlyph.advanceWidth * last.span.font.scale(last.span.size) + spacing);
|
|
328
|
+
wsWidth = m[0].length * (last.span.font.spaceAdvance(last.span.size) + spacing);
|
|
331
329
|
}
|
|
332
330
|
}
|
|
333
331
|
return { fragments, width, wsWidth, required, start, end };
|
package/lib/text/shape.js
CHANGED
|
@@ -25,9 +25,29 @@ function neverSwitches(cp) {
|
|
|
25
25
|
*/
|
|
26
26
|
export function embeddingLevels(text, direction = 'auto') {
|
|
27
27
|
const explicit = direction === 'ltr' || direction === 'rtl' ? direction : null;
|
|
28
|
+
// Text that nothing can make right-to-left is level 0 throughout, which
|
|
29
|
+
// is what the algorithm would work out a character at a time: every
|
|
30
|
+
// layout asks, and most text is Latin, CJK or digits with no bidi at all.
|
|
31
|
+
if (explicit !== 'rtl' && !MAY_REVERSE.test(text)) {
|
|
32
|
+
return {
|
|
33
|
+
levels: new Uint8Array(text.length),
|
|
34
|
+
paragraphs: text.length ? [{ start: 0, end: text.length - 1, level: 0 }] : []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
28
37
|
return bidi.getEmbeddingLevels(text, explicit);
|
|
29
38
|
}
|
|
30
39
|
|
|
40
|
+
/**
|
|
41
|
+
* What can raise a level in a left-to-right paragraph: a strong
|
|
42
|
+
* right-to-left character (Hebrew, Arabic, Syriac, Thaana, N'Ko and their
|
|
43
|
+
* neighbours, their presentation forms, and the right-to-left blocks of the
|
|
44
|
+
* supplementary planes, found by their high surrogates), an Arabic number,
|
|
45
|
+
* RLM and ALM, and every explicit embedding, override and isolate. Anything
|
|
46
|
+
* else resolves to 0.
|
|
47
|
+
*/
|
|
48
|
+
const MAY_REVERSE =
|
|
49
|
+
/[\u0590-\u08FF\u200F\u202A-\u202E\u2066-\u2069\uFB1D-\uFDFF\uFE70-\uFEFF]|[\uD802\uD803\uD83A\uD83B]/;
|
|
50
|
+
|
|
31
51
|
/**
|
|
32
52
|
* Compact embedding-levels encoding for the shaping memo key: a single
|
|
33
53
|
* number when uniform over [start, end) — the common case — else
|