@react-x11/components 0.13.0 → 0.14.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/dist/html/controls.d.ts +29 -2
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +70 -2
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts +42 -1
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +336 -16
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +18 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +27 -0
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/parse.d.ts +18 -4
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +66 -28
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/shapes.d.ts +44 -0
- package/dist/html/css/shapes.d.ts.map +1 -0
- package/dist/html/css/shapes.js +194 -0
- package/dist/html/css/shapes.js.map +1 -0
- package/dist/html/css/style.d.ts +128 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +547 -144
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/transform.d.ts +85 -0
- package/dist/html/css/transform.d.ts.map +1 -0
- package/dist/html/css/transform.js +425 -0
- package/dist/html/css/transform.js.map +1 -0
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +14 -2
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +4 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/fonts.d.ts +55 -5
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +284 -23
- package/dist/html/fonts.js.map +1 -1
- package/dist/html/layout/axes.d.ts +14 -0
- package/dist/html/layout/axes.d.ts.map +1 -0
- package/dist/html/layout/axes.js +28 -0
- package/dist/html/layout/axes.js.map +1 -0
- package/dist/html/layout/block.d.ts +104 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +410 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +72 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +40 -2
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +1 -1
- package/dist/html/layout/cache.d.ts.map +1 -1
- package/dist/html/layout/cache.js +6 -0
- package/dist/html/layout/cache.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +144 -24
- package/dist/html/layout/css-grid.js.map +1 -1
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +585 -85
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +3 -0
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +144 -54
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/multicol.d.ts +42 -0
- package/dist/html/layout/multicol.d.ts.map +1 -0
- package/dist/html/layout/multicol.js +897 -0
- package/dist/html/layout/multicol.js.map +1 -0
- package/dist/html/layout/shaping.d.ts +7 -0
- package/dist/html/layout/shaping.d.ts.map +1 -1
- package/dist/html/layout/shaping.js +25 -20
- package/dist/html/layout/shaping.js.map +1 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +97 -31
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +4 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +319 -47
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +83 -5
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1474 -217
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +39 -9
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +482 -37
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.js +87 -7
- package/dist/html/widgets.js.map +1 -1
- package/dist/html/woff2.d.ts +14 -0
- package/dist/html/woff2.d.ts.map +1 -0
- package/dist/html/woff2.js +608 -0
- package/dist/html/woff2.js.map +1 -0
- package/dist/maps/controller.d.ts +17 -1
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +27 -7
- package/dist/maps/controller.js.map +1 -1
- package/dist/richtext/node.d.ts +8 -1
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +5 -1
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +25 -6
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +240 -24
- package/dist/richtext/runs.js.map +1 -1
- package/package.json +1 -1
- package/src/html/controls.ts +85 -2
- package/src/html/css/cascade.ts +366 -8
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +71 -31
- package/src/html/css/shapes.ts +239 -0
- package/src/html/css/style.ts +652 -147
- package/src/html/css/transform.ts +459 -0
- package/src/html/css/ua.ts +15 -2
- package/src/html/css/values.ts +4 -0
- package/src/html/fonts.ts +312 -29
- package/src/html/layout/axes.ts +62 -0
- package/src/html/layout/block.ts +466 -37
- package/src/html/layout/boxes.ts +95 -3
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +169 -32
- package/src/html/layout/flex.ts +686 -79
- package/src/html/layout/inline.ts +149 -55
- package/src/html/layout/multicol.ts +977 -0
- package/src/html/layout/shaping.ts +27 -18
- package/src/html/layout/table.ts +105 -35
- package/src/html/node.ts +354 -48
- package/src/html/paint.ts +1804 -315
- package/src/html/svg.ts +573 -36
- package/src/html/widgets.ts +95 -9
- package/src/html/woff2.ts +612 -0
- package/src/maps/controller.ts +28 -7
- package/src/richtext/node.ts +13 -2
- package/src/richtext/runs.ts +313 -35
|
@@ -42,8 +42,10 @@ import {
|
|
|
42
42
|
scrolls,
|
|
43
43
|
} from '../css/style.js';
|
|
44
44
|
import { inkColor, isTransparent, resolve } from '../css/values.js';
|
|
45
|
+
import { tagOf } from '../dom.js';
|
|
45
46
|
import {
|
|
46
47
|
BOX_RAISES,
|
|
48
|
+
GRID_TRACKS,
|
|
47
49
|
LINE_BOX_RAISES,
|
|
48
50
|
PADDED_FACES,
|
|
49
51
|
isOffset,
|
|
@@ -415,13 +417,21 @@ interface Cut {
|
|
|
415
417
|
function cutOf(
|
|
416
418
|
style: ComputedStyle,
|
|
417
419
|
clamp: InlineOptions['clamp'],
|
|
420
|
+
width: number,
|
|
418
421
|
): Cut | null {
|
|
419
422
|
// the ellipsis a clamp ends in is placed apart (`ellipsized`)
|
|
420
423
|
if (clamp) return { maxLines: clamp.lines, overflow: 'clip' };
|
|
424
|
+
// `text-overflow` is how the line is drawn where it runs out of its
|
|
425
|
+
// box, and no part of how wide it is (CSS Overflow 3, 5.1): in a box of
|
|
426
|
+
// no width, which shows none of it and is what the box's content is
|
|
427
|
+
// measured in at its least (`MIN_CONTENT_PROBE`), the line is left
|
|
428
|
+
// whole. Cut there, ntk left the ellipsis alone, and a button whose
|
|
429
|
+
// label is a `truncate` span was measured as wide as one
|
|
421
430
|
if (
|
|
422
431
|
style.textOverflow === 'ellipsis' &&
|
|
423
432
|
!wraps(style) &&
|
|
424
|
-
style.overflowX !== 'visible'
|
|
433
|
+
style.overflowX !== 'visible' &&
|
|
434
|
+
width > 0
|
|
425
435
|
) {
|
|
426
436
|
return { maxLines: 1, overflow: 'ellipsis', wrap: false };
|
|
427
437
|
}
|
|
@@ -644,7 +654,7 @@ function linesOf(
|
|
|
644
654
|
// line at a time, or the lines after the first were lost. A clamp is
|
|
645
655
|
// the paragraph's, and stays one layout.
|
|
646
656
|
const clamp = options.clamp;
|
|
647
|
-
let cut = cutOf(style, clamp);
|
|
657
|
+
let cut = cutOf(style, clamp, options.width);
|
|
648
658
|
const perLine = cut !== null && !clamp && hasNewline;
|
|
649
659
|
// an embedding cannot be cut into chunks
|
|
650
660
|
if (perLine && !hasControls(items)) {
|
|
@@ -1420,6 +1430,7 @@ function linesOf(
|
|
|
1420
1430
|
if (!text) continue;
|
|
1421
1431
|
const m = hung.exec(text);
|
|
1422
1432
|
if (!m) break;
|
|
1433
|
+
if (!trailing) placed.trailRun = segment.runs[i];
|
|
1423
1434
|
trailing = m[0] + trailing;
|
|
1424
1435
|
if (m[0].length < text.length) break;
|
|
1425
1436
|
}
|
|
@@ -1436,6 +1447,7 @@ function linesOf(
|
|
|
1436
1447
|
: spaceAdvance(fonts, segment.runs[segment.runs.length - 1]) *
|
|
1437
1448
|
trailing.length;
|
|
1438
1449
|
open.x += open.hang;
|
|
1450
|
+
placed.trail = open.hang;
|
|
1439
1451
|
}
|
|
1440
1452
|
} else if (hung.total) holdHung();
|
|
1441
1453
|
index = segment.nextIndex;
|
|
@@ -2390,6 +2402,24 @@ function finishLine(
|
|
|
2390
2402
|
if (!open.texts.length && !open.atomics.length && !open.edges.length) {
|
|
2391
2403
|
return null;
|
|
2392
2404
|
}
|
|
2405
|
+
if (open.hang > 0) {
|
|
2406
|
+
// The line ends on the spaces its last text ends on, and they are
|
|
2407
|
+
// removed (CSS Text 3, 4.1.2): the text takes no room for them, and
|
|
2408
|
+
// what was set after them, the end edges of the boxes they are in,
|
|
2409
|
+
// stands where the text's content ends. Left a space past it, a list
|
|
2410
|
+
// item that ended its line was a space wider than its link.
|
|
2411
|
+
for (let i = open.order.length - 1; i >= 0; i -= 1) {
|
|
2412
|
+
const placed = open.order[i];
|
|
2413
|
+
if (placed.kind === 'text') {
|
|
2414
|
+
placed.item.trail = 0;
|
|
2415
|
+
placed.item.trailRun = undefined;
|
|
2416
|
+
break;
|
|
2417
|
+
}
|
|
2418
|
+
if (placed.kind !== 'edge') break;
|
|
2419
|
+
placed.at -= open.hang;
|
|
2420
|
+
placed.item.x -= open.hang;
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2393
2423
|
const reordered = levels
|
|
2394
2424
|
? levelPieces(open, levels) ||
|
|
2395
2425
|
open.order.some((p) => p.kind === 'edge' && needsOrdering(p, rtl))
|
|
@@ -3298,7 +3328,19 @@ function atomicRaise(
|
|
|
3298
3328
|
* be after.
|
|
3299
3329
|
*/
|
|
3300
3330
|
function atomicBaseline(box: Box): number {
|
|
3301
|
-
const
|
|
3331
|
+
const margin = box.height + box.marginTop + box.marginBottom;
|
|
3332
|
+
const button = isButton(box);
|
|
3333
|
+
// A `<button>` with no line in it sits on the bottom of its content box,
|
|
3334
|
+
// not of its margin box: where its label would have sat. No specification
|
|
3335
|
+
// says so and every browser does — Blink gives the element the content
|
|
3336
|
+
// box as the edge its baseline is synthesized from
|
|
3337
|
+
// (`HTMLButtonElement::AdjustStyle`). An icon button drawn of blocks, the
|
|
3338
|
+
// three bars of a menu toggle, stood its padding under the baseline, and
|
|
3339
|
+
// the line it was on was as much taller: GitHub's header, by four pixels.
|
|
3340
|
+
// And so one whose layout containment keeps its label's baseline in.
|
|
3341
|
+
const bottom = button
|
|
3342
|
+
? margin - box.marginBottom - box.borderBottom - box.padBottom
|
|
3343
|
+
: margin;
|
|
3302
3344
|
if (
|
|
3303
3345
|
box.kind === 'replaced' ||
|
|
3304
3346
|
// a box that clips sits on its bottom margin edge, for legacy reasons
|
|
@@ -3307,8 +3349,8 @@ function atomicBaseline(box: Box): number {
|
|
|
3307
3349
|
// sits on its first item's, as it does unclipped. A MediaWiki button
|
|
3308
3350
|
// is an `overflow: hidden` inline flex box of one icon, and stood its
|
|
3309
3351
|
// whole height on the baseline, the line under it the strut's descent
|
|
3310
|
-
// taller
|
|
3311
|
-
(scrolls(box.style) && box.kind !== 'flex') ||
|
|
3352
|
+
// taller. Nor a `<button>`, which sits on its label clipped or not
|
|
3353
|
+
(scrolls(box.style) && box.kind !== 'flex' && !button) ||
|
|
3312
3354
|
// layout containment keeps its baseline in (CSS Containment 2, 3.3)
|
|
3313
3355
|
box.style.contain & CONTAIN_LAYOUT
|
|
3314
3356
|
) {
|
|
@@ -3325,17 +3367,31 @@ function atomicBaseline(box: Box): number {
|
|
|
3325
3367
|
return baseline === null ? bottom : box.marginTop + (baseline - box.y);
|
|
3326
3368
|
}
|
|
3327
3369
|
|
|
3370
|
+
/** Whether a box is a `<button>` element's: one drawn as the document's,
|
|
3371
|
+
* which a replaced control is not. */
|
|
3372
|
+
export function isButton(box: Box): boolean {
|
|
3373
|
+
return (
|
|
3374
|
+
box.el !== null && box.kind !== 'replaced' && tagOf(box.el) === 'button'
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3328
3378
|
/**
|
|
3329
|
-
* A flex container's
|
|
3330
|
-
*
|
|
3331
|
-
*
|
|
3332
|
-
*
|
|
3333
|
-
*
|
|
3334
|
-
*
|
|
3335
|
-
*
|
|
3379
|
+
* A flex container's baseline, its first (CSS Flexbox 8.5): that of the
|
|
3380
|
+
* first item on its first line that is aligned by its baseline, or where
|
|
3381
|
+
* none is, of its first item, in `order`. An item gives its own, or where
|
|
3382
|
+
* it has none, its border box's bottom edge. Not its last child's: an
|
|
3383
|
+
* `inline-flex` of a small item and a big one sat on the big one's
|
|
3384
|
+
* baseline. Null for a box with no item.
|
|
3385
|
+
*
|
|
3386
|
+
* A grid's is that of its first item in row-major order, by where it was
|
|
3387
|
+
* placed and not where it was written (CSS Grid 1, 10.6).
|
|
3336
3388
|
*/
|
|
3337
|
-
function flexBaseline(box: Box
|
|
3338
|
-
|
|
3389
|
+
function flexBaseline(box: Box): number | null {
|
|
3390
|
+
if (box.style.grid) {
|
|
3391
|
+
const item = GRID_TRACKS.get(box)?.first;
|
|
3392
|
+
return item ? itemBaselineOf(item) : null;
|
|
3393
|
+
}
|
|
3394
|
+
const items: Box[] = [];
|
|
3339
3395
|
let reordered = false;
|
|
3340
3396
|
for (const child of box.children) {
|
|
3341
3397
|
if (child.outOfFlow || child.isFloat) continue;
|
|
@@ -3345,15 +3401,11 @@ function flexBaseline(box: Box, first: boolean): number | null {
|
|
|
3345
3401
|
}
|
|
3346
3402
|
if (!items.length) return null;
|
|
3347
3403
|
if (reordered) items.sort((a, b) => a.style.order - b.style.order);
|
|
3348
|
-
if (!first) items = items.reverse();
|
|
3349
3404
|
const style = box.style;
|
|
3350
|
-
if (style.flexDirection.startsWith('row')
|
|
3351
|
-
// a line ends where the next item does not go on along the main axis
|
|
3352
|
-
// which from the last item is where it goes on
|
|
3405
|
+
if (style.flexDirection.startsWith('row')) {
|
|
3406
|
+
// a line ends where the next item does not go on along the main axis
|
|
3353
3407
|
const back =
|
|
3354
|
-
(
|
|
3355
|
-
(style.direction === 'rtl')) !==
|
|
3356
|
-
!first;
|
|
3408
|
+
(style.flexDirection === 'row-reverse') !== (style.direction === 'rtl');
|
|
3357
3409
|
let last = NaN;
|
|
3358
3410
|
for (const item of items) {
|
|
3359
3411
|
if (!Number.isNaN(last) && (back ? item.x >= last : item.x <= last)) {
|
|
@@ -3364,24 +3416,20 @@ function flexBaseline(box: Box, first: boolean): number | null {
|
|
|
3364
3416
|
item.style.alignSelf === 'auto'
|
|
3365
3417
|
? style.alignItems
|
|
3366
3418
|
: item.style.alignSelf;
|
|
3367
|
-
if (align === 'baseline') return itemBaselineOf(item
|
|
3419
|
+
if (align === 'baseline') return itemBaselineOf(item);
|
|
3368
3420
|
}
|
|
3369
3421
|
}
|
|
3370
|
-
return itemBaselineOf(items[0]
|
|
3422
|
+
return itemBaselineOf(items[0]);
|
|
3371
3423
|
}
|
|
3372
3424
|
|
|
3373
|
-
/** A flex item's baseline, in document coordinates: its
|
|
3374
|
-
*
|
|
3375
|
-
*
|
|
3376
|
-
*
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
): number | null {
|
|
3382
|
-
const found = childBaseline(item, first ? firstBaselineIn : lastBaselineIn);
|
|
3383
|
-
if (found !== null) return found;
|
|
3384
|
-
return container.grid ? null : item.y + item.height;
|
|
3425
|
+
/** A flex item's baseline or a grid item's, in document coordinates: its
|
|
3426
|
+
* first line's, or where it has none, one synthesized from its border
|
|
3427
|
+
* edges, the bottom one (CSS Flexbox 8.5, CSS Grid 1, 10.6). A grid took
|
|
3428
|
+
* none from such an item and had none of its own: a grid of icons stood
|
|
3429
|
+
* its whole height on the baseline, where a browser stands it on the
|
|
3430
|
+
* first icon's bottom edge. */
|
|
3431
|
+
function itemBaselineOf(item: Box): number {
|
|
3432
|
+
return childBaseline(item, firstBaselineIn) ?? item.y + item.height;
|
|
3385
3433
|
}
|
|
3386
3434
|
|
|
3387
3435
|
/**
|
|
@@ -3409,10 +3457,18 @@ function tableBaseline(table: Box): number | null {
|
|
|
3409
3457
|
* what overflows it gives its bottom margin edge and no deeper, whatever
|
|
3410
3458
|
* text it holds (CSS Box Alignment's synthesized baseline). Null where
|
|
3411
3459
|
* nothing in it has one.
|
|
3460
|
+
*
|
|
3461
|
+
* A flex box or a grid among them gives its first baseline, the one it has
|
|
3462
|
+
* on a line of its own, and a table gives none: what an inline-block takes
|
|
3463
|
+
* from a block-level child in Blink, where only a block container is asked
|
|
3464
|
+
* for its last (`UseLastBaselineForInlineBaseline`), and in Gecko, where a
|
|
3465
|
+
* child is asked for its default one and a table is passed over
|
|
3466
|
+
* (`nsBlockFrame::GetNaturalBaselineBOffset`). Asked for its last, a grid
|
|
3467
|
+
* of an icon, a label and a chevron in a button sat the button on the
|
|
3468
|
+
* chevron, and the line it was on came out shorter than a browser's.
|
|
3412
3469
|
*/
|
|
3413
3470
|
function lastBaselineIn(box: Box): number | null {
|
|
3414
|
-
|
|
3415
|
-
if (box.kind === 'flex') return flexBaseline(box, false);
|
|
3471
|
+
if (box.kind === 'flex') return flexBaseline(box);
|
|
3416
3472
|
if (box.lines?.length) {
|
|
3417
3473
|
const line = box.lines[box.lines.length - 1];
|
|
3418
3474
|
return line.y + line.baseline;
|
|
@@ -3427,7 +3483,7 @@ function lastBaselineIn(box: Box): number | null {
|
|
|
3427
3483
|
/** The same, from the first line box or child: a table's baseline is its
|
|
3428
3484
|
* first row's, and so is a table cell's. */
|
|
3429
3485
|
export function firstBaselineIn(box: Box): number | null {
|
|
3430
|
-
if (box.kind === 'flex') return flexBaseline(box
|
|
3486
|
+
if (box.kind === 'flex') return flexBaseline(box);
|
|
3431
3487
|
if (box.lines?.length) return box.lines[0].y + box.lines[0].baseline;
|
|
3432
3488
|
for (const child of box.children) {
|
|
3433
3489
|
const found = childBaseline(child, firstBaselineIn);
|
|
@@ -3443,12 +3499,17 @@ function childBaseline(
|
|
|
3443
3499
|
if (child.outOfFlow || child.isFloat || child.kind === 'replaced') {
|
|
3444
3500
|
return null;
|
|
3445
3501
|
}
|
|
3502
|
+
// a table is passed over for a block's last baseline (`lastBaselineIn`)
|
|
3503
|
+
if (inside === lastBaselineIn && child.kind === 'table') return null;
|
|
3446
3504
|
// the legacy rule is a block container's last baseline alone (CSS Box
|
|
3447
|
-
// Alignment 3, 9.2): its first is its first line's, clipped or not
|
|
3505
|
+
// Alignment 3, 9.2): its first is its first line's, clipped or not —
|
|
3506
|
+
// and a button that clips keeps its label's, here as on a line of its
|
|
3507
|
+
// own (`atomicBaseline`)
|
|
3448
3508
|
if (
|
|
3449
3509
|
inside === lastBaselineIn &&
|
|
3450
3510
|
child.kind !== 'flex' &&
|
|
3451
|
-
scrolls(child.style)
|
|
3511
|
+
scrolls(child.style) &&
|
|
3512
|
+
!isButton(child)
|
|
3452
3513
|
) {
|
|
3453
3514
|
return child.y + child.height + child.marginBottom;
|
|
3454
3515
|
}
|
|
@@ -4143,6 +4204,8 @@ const RUN_STYLE = [
|
|
|
4143
4204
|
'underlineOffset',
|
|
4144
4205
|
'underlineThickness',
|
|
4145
4206
|
'strike',
|
|
4207
|
+
'strikeStyle',
|
|
4208
|
+
'strikeThickness',
|
|
4146
4209
|
] as const;
|
|
4147
4210
|
|
|
4148
4211
|
/**
|
|
@@ -4710,26 +4773,57 @@ export function runFor(text: string, style: ComputedStyle): TextRun {
|
|
|
4710
4773
|
// colours of the elements that set them (`decorate`)
|
|
4711
4774
|
if (style.underline) {
|
|
4712
4775
|
run.underline = style.underline;
|
|
4713
|
-
|
|
4714
|
-
//
|
|
4715
|
-
// `
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4776
|
+
run.underlineStyle = ruleStyle(style.underlineStyle);
|
|
4777
|
+
// The band the rule is drawn in: as thick as the box that set it made
|
|
4778
|
+
// it (`usedThickness`), and as far under the baseline as that box said.
|
|
4779
|
+
// `auto` leaves how far to the user agent, at or under the baseline
|
|
4780
|
+
// (CSS Text Decoration 4, 2.7 and 2.8), and it is half the rule's
|
|
4781
|
+
// thickness, a pixel at the least — Blink's gap, which keeps a thick
|
|
4782
|
+
// rule as clear of its letters as a thin one. A length is from the
|
|
4783
|
+
// baseline itself.
|
|
4784
|
+
const band = style.underlineThickness ?? 1;
|
|
4785
|
+
const top =
|
|
4786
|
+
style.underlineOffset === null
|
|
4787
|
+
? Math.max(1, Math.ceil(band / 2))
|
|
4788
|
+
: Math.round(style.underlineOffset);
|
|
4789
|
+
if (run.underlineStyle === 'dotted' || run.underlineStyle === 'dashed') {
|
|
4790
|
+
// dots and dashes are a stroke along the band's middle, its width the
|
|
4791
|
+
// nearest whole pixel to the band's: 1.6 is two, where a solid rule's
|
|
4792
|
+
// is the one pixel it fills
|
|
4793
|
+
const width = Math.round(band);
|
|
4794
|
+
run.underlineThickness = width;
|
|
4795
|
+
run.underlineOffset =
|
|
4796
|
+
top + Math.floor(Math.max(band / 2, 0.5)) - Math.floor(width / 2);
|
|
4797
|
+
} else {
|
|
4798
|
+
run.underlineThickness = Math.floor(band);
|
|
4799
|
+
run.underlineOffset = top;
|
|
4727
4800
|
}
|
|
4728
4801
|
}
|
|
4729
|
-
if (style.lineThrough)
|
|
4802
|
+
if (style.lineThrough) {
|
|
4803
|
+
run.strike = style.lineThrough;
|
|
4804
|
+
run.strikeStyle = ruleStyle(style.lineThroughStyle);
|
|
4805
|
+
// as thick as the box that set it made it, on whole pixels as the
|
|
4806
|
+
// underline's is: a solid rule fills the ones it covers, and dots and
|
|
4807
|
+
// dashes are the nearest whole pixel wide. Where it is drawn is each
|
|
4808
|
+
// run's own face's to say (`paintRunRules`).
|
|
4809
|
+
const band = style.lineThroughThickness ?? 1;
|
|
4810
|
+
run.strikeThickness =
|
|
4811
|
+
run.strikeStyle === 'dotted' || run.strikeStyle === 'dashed'
|
|
4812
|
+
? Math.round(band)
|
|
4813
|
+
: Math.floor(band);
|
|
4814
|
+
}
|
|
4730
4815
|
return run;
|
|
4731
4816
|
}
|
|
4732
4817
|
|
|
4818
|
+
/** A CSS rule style as richtext names it. CSS's five and SGR 4's five are
|
|
4819
|
+
* the same set under two names; richtext speaks SGR's, so `solid` is
|
|
4820
|
+
* `single` and `wavy` is `curly`. The other three are spelled identically. */
|
|
4821
|
+
function ruleStyle(
|
|
4822
|
+
style: ComputedStyle['underlineStyle'],
|
|
4823
|
+
): NonNullable<TextRun['underlineStyle']> {
|
|
4824
|
+
return style === 'wavy' ? 'curly' : style === 'solid' ? 'single' : style;
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4733
4827
|
/**
|
|
4734
4828
|
* Maps a code-unit offset in text handed to `TextLayout` back to its offset
|
|
4735
4829
|
* in the document index. The two differ because a layout covers one segment
|