ntk 8.16.2 → 8.17.1

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/fontconfig.js CHANGED
@@ -226,8 +226,26 @@ export function platformFamilies(family, platform = globalThis.process?.platform
226
226
  return changed ? out.join(',') : family;
227
227
  }
228
228
 
229
+ /**
230
+ * A family name as fontconfig's pattern syntax reads it (FcNameParse): a
231
+ * `-` starts the point size, a `:` the properties, a `,` the next family,
232
+ * and a `\` escapes each of them. Unescaped, the CSS list
233
+ * `tablet-gothic-condensed, "arial narrow", arial` was the family `tablet`
234
+ * and a size fc-match could not read, the families after it were gone, and
235
+ * the face was fontconfig's default for nothing: Verdana, where a browser
236
+ * sets Arial Narrow.
237
+ */
238
+ function fcName(name) {
239
+ return name.replace(/[\\\-:,]/g, '\\$&');
240
+ }
241
+
229
242
  function patternFor({ family, weight, style }) {
230
- let fc = platformFamilies(family || 'sans-serif');
243
+ let fc = String(platformFamilies(family || 'sans-serif'))
244
+ .split(',')
245
+ .map((name) => name.trim().replace(/^["']|["']$/g, ''))
246
+ .filter(Boolean)
247
+ .map(fcName)
248
+ .join(',');
231
249
  const fcWeight = normalizeWeight(weight);
232
250
  if (fcWeight !== undefined) fc += `:weight=${fcWeight}`;
233
251
  if (style && style.includes('italic')) fc += ':slant=italic';
@@ -110,6 +110,30 @@ function sameItem(before, span) {
110
110
  return before === span || span.kernAcross || before.kernAcross;
111
111
  }
112
112
 
113
+ /**
114
+ * The width a line's entries take as the line is fitted, white space and
115
+ * all: each item's part — a span's, or a run of them `sameItem` joins —
116
+ * rounded as the layout rounds (`LineFit`), with its kerning. A line's
117
+ * `advance`: where the text goes on after the line on the same one, as it
118
+ * does after a piece of a line composed a piece at a time, the white space
119
+ * it ends on is inside the line, and in the item it ends, which is rounded
120
+ * once with it, as Blink measures an element's text with its spaces.
121
+ */
122
+ function fittedEntries(entries, round) {
123
+ let fitted = 0;
124
+ let item = 0;
125
+ let span = null;
126
+ for (const e of entries) {
127
+ if (span !== null && !sameItem(span, e.span)) {
128
+ fitted += round(item);
129
+ item = 0;
130
+ }
131
+ item += (e.kern ?? 0) + e.run.width + (e.kernAfter ?? 0);
132
+ span = e.span;
133
+ }
134
+ return entries.length ? fitted + round(item) : 0;
135
+ }
136
+
113
137
  /** How a layout rounds its items before it adds them (`LineFit`). */
114
138
  function itemRounding(options) {
115
139
  return options.fit === 'items' ? snapUp : unrounded;
@@ -187,12 +211,15 @@ function isWsGlyph(g) {
187
211
  * is that sum. Default: the advances as they add up (`LineFit`)
188
212
  *
189
213
  * The result is inspectable before/without drawing: `width`, `height`,
190
- * `truncated`, and `lines[] = { x, y, height, baseline, width, ascent,
191
- * descent, runs, start, end }` with
214
+ * `truncated`, and `lines[] = { x, y, height, baseline, width, advance,
215
+ * ascent, descent, runs, start, end }` with
192
216
  * `runs[] = { x, width, run, span, start, end }` in visual order
193
217
  * (`start`/`end` are logical UTF-16 ranges into the full text). A line's
194
218
  * box is `y` to `y + height`; its glyphs sit centred in it, from
195
- * `baseline - ascent` to `baseline + descent`.
219
+ * `baseline - ascent` to `baseline + descent`. Its `width` leaves out the
220
+ * white space it ends on, as a line's end does; its `advance` keeps it, in
221
+ * the item it ends, which is how far the line moves the pen where text goes
222
+ * on after it on the same line.
196
223
  *
197
224
  * `caretPosition(index)` / `indexAt(x, y)` map logical code-point indices
198
225
  * to visual caret geometry and back (bidi/ligature/trailing-whitespace
@@ -334,6 +361,9 @@ export class TextLayout {
334
361
  }
335
362
  }
336
363
  }
364
+ // how far the line moves the pen where text goes on after it on the
365
+ // same line: its trailing white space kept, in the item it ends
366
+ let advance = fittedEntries(entries, round);
337
367
  let trailing = stripTrailingWhitespace(entries);
338
368
  const contentEnd = trailing
339
369
  ? trailing.start
@@ -363,6 +393,7 @@ export class TextLayout {
363
393
  // whatever whitespace was stripped is gone for good, not merely
364
394
  // pushed past the line edge: there is no wrap for it to precede
365
395
  trailing = null;
396
+ advance = null;
366
397
  lineEnd = contentEnd;
367
398
  }
368
399
  entries = reorderRuns(entries);
@@ -424,6 +455,7 @@ export class TextLayout {
424
455
  height: box,
425
456
  baseline: y + leading + ascent,
426
457
  width: fitted,
458
+ advance: trailing && advance !== null ? Math.max(fitted, advance) : fitted,
427
459
  ascent,
428
460
  descent,
429
461
  runs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ntk",
3
- "version": "8.16.2",
3
+ "version": "8.17.1",
4
4
  "description": "Desktop UI toolkit for X11 with canvas-like 2d and OpenGL rendering",
5
5
  "author": "Andrey Sidorov <sidorares@yandex.ru>",
6
6
  "license": "MIT",