@react-x11/components 0.14.1 → 0.16.0
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/code-editor/node.d.ts +13 -0
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +23 -5
- package/dist/code-editor/node.js.map +1 -1
- package/dist/html/css/cascade.d.ts +171 -26
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +616 -216
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +25 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +307 -19
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/content.d.ts +11 -6
- package/dist/html/css/content.d.ts.map +1 -1
- package/dist/html/css/content.js +171 -12
- package/dist/html/css/content.js.map +1 -1
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +62 -9
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/shapes.d.ts +18 -0
- package/dist/html/css/shapes.d.ts.map +1 -1
- package/dist/html/css/shapes.js +21 -1
- package/dist/html/css/shapes.js.map +1 -1
- package/dist/html/css/style.d.ts +42 -5
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +74 -12
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/ua.js +15 -0
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +5 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +18 -9
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +7 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +29 -9
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +141 -52
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +16 -2
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +144 -23
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +11 -9
- 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 +1631 -221
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +15 -3
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +23 -8
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/table.d.ts +27 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +886 -324
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +35 -4
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +118 -26
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +558 -178
- package/dist/html/paint.js.map +1 -1
- package/dist/html/resources.js +14 -1
- package/dist/html/resources.js.map +1 -1
- package/dist/html/svg.d.ts +23 -7
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +264 -59
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.d.ts.map +1 -1
- package/dist/html/widgets.js +57 -4
- package/dist/html/widgets.js.map +1 -1
- package/package.json +3 -3
- package/src/code-editor/node.ts +24 -5
- package/src/html/css/cascade.ts +697 -221
- package/src/html/css/color.ts +345 -18
- package/src/html/css/content.ts +173 -15
- package/src/html/css/parse.ts +60 -8
- package/src/html/css/shapes.ts +35 -1
- package/src/html/css/style.ts +122 -17
- package/src/html/css/ua.ts +15 -0
- package/src/html/css/values.ts +23 -9
- package/src/html/index.ts +7 -0
- package/src/html/layout/block.ts +149 -58
- package/src/html/layout/boxes.ts +171 -27
- package/src/html/layout/css-grid.ts +12 -9
- package/src/html/layout/flex.ts +1843 -212
- package/src/html/layout/inline.ts +27 -7
- package/src/html/layout/table.ts +961 -332
- package/src/html/node.ts +151 -27
- package/src/html/paint.ts +692 -234
- package/src/html/resources.ts +13 -1
- package/src/html/svg.ts +299 -56
- package/src/html/widgets.ts +61 -4
package/src/html/layout/boxes.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// reason richtext's node gives for answering from what it draws: an index
|
|
17
17
|
// built by a second traversal can disagree with the boxes, and a selection
|
|
18
18
|
// that disagrees with the glyphs is worse than no selection.
|
|
19
|
-
import type { Element } from 'domhandler';
|
|
19
|
+
import type { ChildNode, Element } from 'domhandler';
|
|
20
20
|
|
|
21
21
|
import type { TextRun } from '../../richtext/index.js';
|
|
22
22
|
import {
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
NON_RENDERED,
|
|
29
29
|
tagOf,
|
|
30
30
|
} from '../dom.js';
|
|
31
|
+
import { ShapeCopies, languageOf, metaColorScheme } from '../css/cascade.js';
|
|
31
32
|
import type {
|
|
32
33
|
Cascade,
|
|
33
34
|
FirstLetterRules,
|
|
@@ -48,7 +49,7 @@ import {
|
|
|
48
49
|
inherit,
|
|
49
50
|
} from '../css/style.js';
|
|
50
51
|
import { AUTO } from '../css/values.js';
|
|
51
|
-
import { svgIntrinsics } from '../svg.js';
|
|
52
|
+
import { concreteSize, svgIntrinsics } from '../svg.js';
|
|
52
53
|
import type { IntrinsicSize } from '../svg.js';
|
|
53
54
|
import type { ComputedStyle } from '../css/style.js';
|
|
54
55
|
import type { GridLines } from './grid-lines.js';
|
|
@@ -82,15 +83,32 @@ export interface Marker {
|
|
|
82
83
|
/** Its own style where a `::marker` rule gives it one; the item's where
|
|
83
84
|
* none does. */
|
|
84
85
|
style: ComputedStyle | null;
|
|
85
|
-
/** The image it is, `list-style-image`'s,
|
|
86
|
-
*
|
|
87
|
-
|
|
86
|
+
/** The image it is, `list-style-image`'s, where that has arrived, at its
|
|
87
|
+
* size in device pixels — its own, or the one a marker image with none
|
|
88
|
+
* is given (`Builder._markerImageSize`); its text is then not drawn.
|
|
89
|
+
* `gap` is the room between it and the content, in device pixels
|
|
90
|
+
* (`MARKER_IMAGE_GAP`). */
|
|
91
|
+
image?: { url: string; width: number; height: number; gap: number };
|
|
88
92
|
/** Its text is its own — a string `list-style-type`, a `::marker`'s
|
|
89
93
|
* `content` — and ends at the content's edge, with no gap a number
|
|
90
94
|
* or a bullet is set apart by. */
|
|
91
95
|
flush?: true;
|
|
92
96
|
}
|
|
93
97
|
|
|
98
|
+
/**
|
|
99
|
+
* The room between a list marker's image and the item's content, in CSS
|
|
100
|
+
* pixels: between the image and the content's edge outside the item, and
|
|
101
|
+
* after the image inside it. CSS 2.1 (12.5.1) leaves where a marker goes
|
|
102
|
+
* to the user agent, and this is Blink's `kCMarkerPaddingPx`
|
|
103
|
+
* (`ListMarker::InlineMarginsForOutside` and `…ForInside`), which WebKit
|
|
104
|
+
* has too. Outside, ours was the gap a bullet has, 0.4em — 16 pixels at
|
|
105
|
+
* 40px text where Chrome has 7 — and inside the space a marker's text ends
|
|
106
|
+
* in, a space's width. Blink writes it into the marker's margins unzoomed,
|
|
107
|
+
* so at a device scale of 2 Chrome's is 7 device pixels; here it is 7 CSS
|
|
108
|
+
* pixels at any scale, so that a page at 2x is the page at 1x doubled.
|
|
109
|
+
*/
|
|
110
|
+
const MARKER_IMAGE_GAP = 7;
|
|
111
|
+
|
|
94
112
|
/** An out-of-flow box's static position, as an offset from the box whose
|
|
95
113
|
* flow it was taken from, which may yet move. */
|
|
96
114
|
export interface StaticPosition {
|
|
@@ -789,6 +807,11 @@ export interface BoxTree {
|
|
|
789
807
|
* could reach one: worked out as a drawing is first painted, since a
|
|
790
808
|
* page of icons shows few of them at once. */
|
|
791
809
|
shapeStyler: ShapeStyler | null;
|
|
810
|
+
/** What the drawings of this build share in `Cascade.shapeStyles`: the
|
|
811
|
+
* document's elements by their ids, indexed when first asked, where a
|
|
812
|
+
* `<use>` finds the icon a sprite has for it; and what the rules matched
|
|
813
|
+
* in each copy a `<use>` makes. Null where `shapeStyler` is. */
|
|
814
|
+
shapeCopies: ShapeCopies | null;
|
|
792
815
|
/** Whether a float or an out-of-flow box sits in an inline box: where
|
|
793
816
|
* none does, layout looks for them among a block's own children and
|
|
794
817
|
* goes through no inline box to find them. */
|
|
@@ -826,6 +849,10 @@ export interface BuildOptions {
|
|
|
826
849
|
imageSize(el: Element): IntrinsicSize | null;
|
|
827
850
|
/** The same for an image named by url — generated content's. */
|
|
828
851
|
urlSize?(url: string): IntrinsicSize | null;
|
|
852
|
+
/** How far a style's first face reaches above its baseline, in device
|
|
853
|
+
* pixels: what a list marker's image with no size of its own is sized
|
|
854
|
+
* by (`_markerImageSize`). Where it is not known, 0.8em. */
|
|
855
|
+
faceAscent?(style: ComputedStyle): number | undefined;
|
|
829
856
|
/** The size a real widget wants, so the box in the flow is the size the
|
|
830
857
|
* control will be drawn at. */
|
|
831
858
|
controlSize(
|
|
@@ -847,6 +874,28 @@ export function buildBoxes(
|
|
|
847
874
|
return builder.run(root as Element);
|
|
848
875
|
}
|
|
849
876
|
|
|
877
|
+
/** A document's first element with an id: one walk of it, the first time
|
|
878
|
+
* an id is asked for (`ShapeCopies`). */
|
|
879
|
+
function idIndex(root: Element): (id: string) => Element | null {
|
|
880
|
+
let index: Map<string, Element> | null = null;
|
|
881
|
+
return (id) => {
|
|
882
|
+
if (!index) {
|
|
883
|
+
index = new Map();
|
|
884
|
+
const stack: ChildNode[] = [...root.children].reverse();
|
|
885
|
+
for (let node = stack.pop(); node; node = stack.pop()) {
|
|
886
|
+
if (!isElement(node)) continue;
|
|
887
|
+
const own = node.attribs.id;
|
|
888
|
+
if (own && !index.has(own)) index.set(own, node);
|
|
889
|
+
const children = node.children;
|
|
890
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
891
|
+
stack.push(children[i]);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return index.get(id) ?? null;
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
|
|
850
899
|
/**
|
|
851
900
|
* How deep the box tree may go. Everything downstream of the builder — the
|
|
852
901
|
* fix-up pass, layout, paint, the accessor walks — recurses on box depth, so
|
|
@@ -854,8 +903,17 @@ export function buildBoxes(
|
|
|
854
903
|
* output, a runaway template) from a stack overflow five phases later.
|
|
855
904
|
* Blink's parser flattens at 512 for the same reason; content past the cap
|
|
856
905
|
* is dropped, which beats the alternative of crashing the application.
|
|
906
|
+
*
|
|
857
907
|
* The parser keeps a document to 256 elements (`dom.ts`), so what reaches
|
|
858
|
-
* this
|
|
908
|
+
* this is the anonymous boxes a table builds round them, which the builder
|
|
909
|
+
* counts as it goes (`wrappersAround`), since the fix-up makes them after
|
|
910
|
+
* it. Counted as elements, a `display: table-cell` box in another was one
|
|
911
|
+
* level where it is four boxes — a table, a row group, a row and the cell
|
|
912
|
+
* — and every pass pays for a box: painting one takes some 800 bytes of
|
|
913
|
+
* the stack. Two hundred and fifty cells deep, a thousand boxes, layout
|
|
914
|
+
* and paint each ran out of the 984 KB V8 gives the main thread, and the
|
|
915
|
+
* document came out blank. 512 boxes paint in under half of it, and are a
|
|
916
|
+
* cell in a cell 128 deep.
|
|
859
917
|
*/
|
|
860
918
|
const MAX_DEPTH = 512;
|
|
861
919
|
|
|
@@ -916,11 +974,15 @@ class Builder {
|
|
|
916
974
|
run(root: Element): BoxTree {
|
|
917
975
|
const cascade = this._options.cascade;
|
|
918
976
|
cascade.beginSharing(this._options.kept ?? null);
|
|
977
|
+
cascade.pageColorScheme = metaColorScheme(root);
|
|
919
978
|
const { style: rootStyle, html: impliedHtml } = cascade.rootStyle(
|
|
920
979
|
hasBody(root),
|
|
921
980
|
hasHtml(root),
|
|
922
981
|
);
|
|
923
982
|
const rootBox = new Box('block', null, rootStyle);
|
|
983
|
+
// the root standing in for a `<body>` has its background clipped to
|
|
984
|
+
// the document's text as the body's would be
|
|
985
|
+
if (rootStyle.backgroundClipText) this._clipText = true;
|
|
924
986
|
// a fragment's root stands in for a `<body>`, counters and all
|
|
925
987
|
this._scopes.open();
|
|
926
988
|
this._counterChanges(rootStyle, {
|
|
@@ -938,6 +1000,7 @@ class Builder {
|
|
|
938
1000
|
const anonymous = anonymousStyles(cascade.initial);
|
|
939
1001
|
fixUp(rootBox, anonymous);
|
|
940
1002
|
assignSubtreeRanges(rootBox);
|
|
1003
|
+
const copies = cascade.stylesShapes ? new ShapeCopies(idIndex(root)) : null;
|
|
941
1004
|
return {
|
|
942
1005
|
root: rootBox,
|
|
943
1006
|
anonymous,
|
|
@@ -954,7 +1017,8 @@ class Builder {
|
|
|
954
1017
|
firstLine: this._firstLine,
|
|
955
1018
|
firstLineStyler: this._firstLine ? this._firstLineStyler() : null,
|
|
956
1019
|
selectionStyler: cascade.hasSelection ? this._selectionStyler() : null,
|
|
957
|
-
shapeStyler:
|
|
1020
|
+
shapeStyler: copies ? this._shapeStyler(copies) : null,
|
|
1021
|
+
shapeCopies: copies,
|
|
958
1022
|
nestedOutOfLine: this._nestedOutOfLine,
|
|
959
1023
|
movedInline: this._movedInline,
|
|
960
1024
|
clipText: this._clipText,
|
|
@@ -989,12 +1053,12 @@ class Builder {
|
|
|
989
1053
|
|
|
990
1054
|
/** `BoxTree.shapeStyler`, over this build's cascade: each drawing's
|
|
991
1055
|
* once, from its box's style as it is when first asked. */
|
|
992
|
-
private _shapeStyler(): ShapeStyler {
|
|
1056
|
+
private _shapeStyler(copies: ShapeCopies): ShapeStyler {
|
|
993
1057
|
const cascade = this._options.cascade;
|
|
994
1058
|
return (box) => {
|
|
995
1059
|
let shapes = SHAPE_STYLES.get(box);
|
|
996
1060
|
if (shapes === undefined) {
|
|
997
|
-
shapes = box.el ? cascade.shapeStyles(box.el, box.style) : null;
|
|
1061
|
+
shapes = box.el ? cascade.shapeStyles(box.el, box.style, copies) : null;
|
|
998
1062
|
SHAPE_STYLES.set(box, shapes);
|
|
999
1063
|
}
|
|
1000
1064
|
return shapes;
|
|
@@ -1190,8 +1254,10 @@ class Builder {
|
|
|
1190
1254
|
return;
|
|
1191
1255
|
}
|
|
1192
1256
|
|
|
1193
|
-
if (this._depth >= MAX_DEPTH) return;
|
|
1194
1257
|
const kind = boxKindFor(style.display);
|
|
1258
|
+
// the box, and the anonymous boxes the fix-up will put round it
|
|
1259
|
+
const depth = 1 + wrappersAround(into.kind, kind, style);
|
|
1260
|
+
if (this._depth + depth > MAX_DEPTH) return;
|
|
1195
1261
|
const box = new Box(kind, el, style);
|
|
1196
1262
|
into.append(box);
|
|
1197
1263
|
if (
|
|
@@ -1221,7 +1287,7 @@ class Builder {
|
|
|
1221
1287
|
let markerStyle: ComputedStyle | null = null;
|
|
1222
1288
|
let ownMarker = false;
|
|
1223
1289
|
let markerImage: { url: string; size: IntrinsicSize } | null = null;
|
|
1224
|
-
let insideImage:
|
|
1290
|
+
let insideImage: NonNullable<Marker['image']> | null = null;
|
|
1225
1291
|
if (style.display === 'list-item' && style.listStyleImage) {
|
|
1226
1292
|
// asked for as generated content's images are, and the tree built
|
|
1227
1293
|
// again when it arrives; until it has, and where it never does, the
|
|
@@ -1256,20 +1322,21 @@ class Builder {
|
|
|
1256
1322
|
flush = true;
|
|
1257
1323
|
}
|
|
1258
1324
|
if (markerImage && !ownMarker) {
|
|
1259
|
-
|
|
1325
|
+
const [width, height] = this._markerImageSize(
|
|
1326
|
+
markerImage.size,
|
|
1327
|
+
markerStyle ?? style,
|
|
1328
|
+
);
|
|
1329
|
+
const gap = MARKER_IMAGE_GAP * (this._options.scale ?? 1);
|
|
1330
|
+
const image = { url: markerImage.url, width, height, gap };
|
|
1331
|
+
if (style.listStylePosition === 'inside') insideImage = image;
|
|
1260
1332
|
else {
|
|
1261
|
-
const scale = this._options.scale ?? 1;
|
|
1262
1333
|
box.marker = {
|
|
1263
1334
|
text: '',
|
|
1264
1335
|
layout: null,
|
|
1265
1336
|
x: 0,
|
|
1266
1337
|
y: 0,
|
|
1267
1338
|
style: markerStyle,
|
|
1268
|
-
image
|
|
1269
|
-
url: markerImage.url,
|
|
1270
|
-
width: (markerImage.size.width ?? 0) * scale,
|
|
1271
|
-
height: (markerImage.size.height ?? 0) * scale,
|
|
1272
|
-
},
|
|
1339
|
+
image,
|
|
1273
1340
|
};
|
|
1274
1341
|
}
|
|
1275
1342
|
} else if (text && style.listStylePosition === 'inside') {
|
|
@@ -1302,19 +1369,23 @@ class Builder {
|
|
|
1302
1369
|
: null;
|
|
1303
1370
|
const ownLetter = ownRules ? { rules: ownRules, punctuation: [] } : null;
|
|
1304
1371
|
if (ownLetter) this._firstLetter = ownLetter;
|
|
1305
|
-
this._depth +=
|
|
1372
|
+
this._depth += depth;
|
|
1306
1373
|
if (insideImage) {
|
|
1307
1374
|
// an inline image at the start of the first line, as a generated
|
|
1308
|
-
// image is, and the
|
|
1309
|
-
|
|
1310
|
-
|
|
1375
|
+
// image is, and the room after it Blink gives it rather than a
|
|
1376
|
+
// space: the content's own white space after it is kept, as it is
|
|
1377
|
+
// after an image (`MARKER_IMAGE_GAP`)
|
|
1378
|
+
const { url, gap } = insideImage;
|
|
1379
|
+
const image = this._contentImage(url, box, style, el, insideImage);
|
|
1380
|
+
if (style.direction === 'rtl') image.style.marginLeft = gap;
|
|
1381
|
+
else image.style.marginRight = gap;
|
|
1311
1382
|
} else if (insideMarker) {
|
|
1312
1383
|
this._insideMarker(insideMarker, style, markerStyle, box, el);
|
|
1313
1384
|
}
|
|
1314
1385
|
this._pseudo(el, 'before', style, box);
|
|
1315
1386
|
this._children(el, box, style, childInFlex, el, key);
|
|
1316
1387
|
this._pseudo(el, 'after', style, box);
|
|
1317
|
-
this._depth -=
|
|
1388
|
+
this._depth -= depth;
|
|
1318
1389
|
this._letterAfter(flow, skipped, outerLetter, ownLetter);
|
|
1319
1390
|
if (flow !== 'inline') this._endLine();
|
|
1320
1391
|
this._ws = after(flow, this._ws, around);
|
|
@@ -1754,14 +1825,14 @@ class Builder {
|
|
|
1754
1825
|
.join(item.separator);
|
|
1755
1826
|
break;
|
|
1756
1827
|
case 'open-quote':
|
|
1757
|
-
text += quoteAt(style.quotes, this._quoteDepth, 0);
|
|
1828
|
+
text += quoteAt(style.quotes, this._quoteDepth, 0, languageOf(el));
|
|
1758
1829
|
this._quoteDepth += 1;
|
|
1759
1830
|
break;
|
|
1760
1831
|
case 'close-quote':
|
|
1761
1832
|
// a close with nothing open writes nothing and closes nothing
|
|
1762
1833
|
if (this._quoteDepth > 0) {
|
|
1763
1834
|
this._quoteDepth -= 1;
|
|
1764
|
-
text += quoteAt(style.quotes, this._quoteDepth, 1);
|
|
1835
|
+
text += quoteAt(style.quotes, this._quoteDepth, 1, languageOf(el));
|
|
1765
1836
|
}
|
|
1766
1837
|
break;
|
|
1767
1838
|
case 'no-open-quote':
|
|
@@ -1787,7 +1858,10 @@ class Builder {
|
|
|
1787
1858
|
into: Box,
|
|
1788
1859
|
style: ComputedStyle,
|
|
1789
1860
|
owner: Element,
|
|
1790
|
-
|
|
1861
|
+
/** Its size where it is a list marker's, which has one whatever the
|
|
1862
|
+
* image says (`_markerImageSize`). */
|
|
1863
|
+
marker?: { width: number; height: number },
|
|
1864
|
+
): Box {
|
|
1791
1865
|
const box = new Box('replaced', null, {
|
|
1792
1866
|
...inherit(style, this._options.cascade.initial),
|
|
1793
1867
|
display: 'inline',
|
|
@@ -1797,11 +1871,40 @@ class Builder {
|
|
|
1797
1871
|
CONTENT_IMAGES.set(box, url);
|
|
1798
1872
|
const size = this._options.urlSize?.(url) ?? null;
|
|
1799
1873
|
this._contentImages.push({ url, element: owner, sized: !!size });
|
|
1800
|
-
if (
|
|
1874
|
+
if (marker) {
|
|
1875
|
+
const { width, height } = marker;
|
|
1876
|
+
const ratio = width > 0 && height > 0 ? width / height : 0;
|
|
1877
|
+
box.intrinsic = { width, height, missing: 0, ratio };
|
|
1878
|
+
} else if (size) setIntrinsics(box, size, this._options.scale ?? 1);
|
|
1801
1879
|
else box.intrinsic = { width: 0, height: 0, missing: 0, ratio: 0 };
|
|
1802
1880
|
this._ws = after('atomic', this._ws, this._ws);
|
|
1803
1881
|
this._lettered = false;
|
|
1804
1882
|
this._abandonLetter();
|
|
1883
|
+
return box;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
/**
|
|
1887
|
+
* A list marker image's size, in device pixels: its own where it has one,
|
|
1888
|
+
* and where it lacks some — an SVG with only a `viewBox`, or with no size
|
|
1889
|
+
* and no ratio — CSS Images' default sizing in a square half its face's
|
|
1890
|
+
* ascent across. CSS Lists 3 (3.3) makes the square 1em, which both
|
|
1891
|
+
* engines find too large (w3c/csswg-drafts#4207): Blink's is half the
|
|
1892
|
+
* ascent, rounded to a whole pixel first
|
|
1893
|
+
* (`LayoutListMarkerImage::DefaultSize`), Gecko's 0.4em, and this is
|
|
1894
|
+
* Blink's. A `viewBox` alone came to 0 by 0 and drew no marker at all,
|
|
1895
|
+
* and inside the item to the 300 by 150 a generated image defaults to.
|
|
1896
|
+
*/
|
|
1897
|
+
private _markerImageSize(
|
|
1898
|
+
size: IntrinsicSize,
|
|
1899
|
+
style: ComputedStyle,
|
|
1900
|
+
): [number, number] {
|
|
1901
|
+
let side = 0;
|
|
1902
|
+
// CoreText reads a size of 0 as its default twelve points
|
|
1903
|
+
if ((size.width === null || size.height === null) && style.fontSize > 0) {
|
|
1904
|
+
const ascent = this._options.faceAscent?.(style) ?? style.fontSize * 0.8;
|
|
1905
|
+
side = Math.round(ascent) / 2;
|
|
1906
|
+
}
|
|
1907
|
+
return concreteSize(size, side, side, this._options.scale ?? 1);
|
|
1805
1908
|
}
|
|
1806
1909
|
|
|
1807
1910
|
/** A text node, whitespace-processed per the inherited `white-space`. */
|
|
@@ -2467,6 +2570,47 @@ function after(
|
|
|
2467
2570
|
}
|
|
2468
2571
|
}
|
|
2469
2572
|
|
|
2573
|
+
/**
|
|
2574
|
+
* How many anonymous boxes the fix-up will put between a box of `kind` and
|
|
2575
|
+
* the box it is appended to, `parent` (`fixUpTable`, `wrapOrphans`,
|
|
2576
|
+
* `wrapTableParts`): a table part outside a table is given what it is
|
|
2577
|
+
* missing of one, and what is in a table and no part of it is given a
|
|
2578
|
+
* cell, a row and a row group. A cell in a block is in a table, a row group
|
|
2579
|
+
* and a row of its own, and a block in a row is in a cell. Counted against
|
|
2580
|
+
* `MAX_DEPTH`, which bounds the boxes and not the elements.
|
|
2581
|
+
*/
|
|
2582
|
+
function wrappersAround(
|
|
2583
|
+
parent: BoxKind,
|
|
2584
|
+
kind: BoxKind,
|
|
2585
|
+
style: ComputedStyle,
|
|
2586
|
+
): number {
|
|
2587
|
+
const column =
|
|
2588
|
+
style.display === 'table-column' || style.display === 'table-column-group';
|
|
2589
|
+
switch (parent) {
|
|
2590
|
+
case 'table':
|
|
2591
|
+
if (kind === 'table-row-group' || kind === 'table-caption' || column) {
|
|
2592
|
+
return 0;
|
|
2593
|
+
}
|
|
2594
|
+
return kind === 'table-row' ? 1 : kind === 'table-cell' ? 2 : 3;
|
|
2595
|
+
case 'table-row-group':
|
|
2596
|
+
return kind === 'table-row' ? 0 : kind === 'table-cell' ? 1 : 2;
|
|
2597
|
+
case 'table-row':
|
|
2598
|
+
return kind === 'table-cell' ? 0 : 1;
|
|
2599
|
+
}
|
|
2600
|
+
// a part out of flow is no part (`isTablePart`)
|
|
2601
|
+
if (
|
|
2602
|
+
style.position === 'absolute' ||
|
|
2603
|
+
style.position === 'fixed' ||
|
|
2604
|
+
style.float !== 'none'
|
|
2605
|
+
) {
|
|
2606
|
+
return 0;
|
|
2607
|
+
}
|
|
2608
|
+
if (kind === 'table-row-group' || kind === 'table-caption' || column) {
|
|
2609
|
+
return 1;
|
|
2610
|
+
}
|
|
2611
|
+
return kind === 'table-row' ? 2 : kind === 'table-cell' ? 3 : 0;
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2470
2614
|
function boxKindFor(display: ComputedStyle['display']): BoxKind {
|
|
2471
2615
|
switch (display) {
|
|
2472
2616
|
case 'inline':
|
|
@@ -374,18 +374,19 @@ export function layoutGrid(
|
|
|
374
374
|
} else if (align === 'center') dy = (tall - outerHeight) / 2;
|
|
375
375
|
else if (align === 'flex-end') dy = tall - outerHeight;
|
|
376
376
|
else if (
|
|
377
|
-
(align === 'stretch' || align === 'baseline') &&
|
|
377
|
+
(align === 'stretch' || align === 'normal' || align === 'baseline') &&
|
|
378
378
|
child.style.height === AUTO &&
|
|
379
379
|
!child.style.heightKeyword &&
|
|
380
|
-
(
|
|
380
|
+
(align === 'stretch' ||
|
|
381
381
|
(child.kind !== 'replaced' && !child.style.aspectRatio))
|
|
382
382
|
) {
|
|
383
383
|
// a stretched item is its area's height, within its own least and
|
|
384
384
|
// greatest (10.3): taller than what it holds, or shorter where its
|
|
385
385
|
// tracks let it be, what it holds then running past it. An image, a
|
|
386
|
-
// control or a box with an `aspect-ratio` keeps its own height
|
|
387
|
-
// `normal
|
|
388
|
-
//
|
|
386
|
+
// control or a box with an `aspect-ratio` keeps its own height under
|
|
387
|
+
// `normal`, which stretches only an item with neither a natural size
|
|
388
|
+
// nor a ratio, and is stretched by `stretch`, the grid's or its own
|
|
389
|
+
// (6.2, and CSS Box Alignment 3, 6.1).
|
|
389
390
|
const stretched = tall - child.marginTop - child.marginBottom;
|
|
390
391
|
const height = clampHeight(
|
|
391
392
|
child,
|
|
@@ -939,9 +940,9 @@ function percentOwn(box: Box): boolean {
|
|
|
939
940
|
/**
|
|
940
941
|
* An item's border-box height before the rows are sized, where it has one
|
|
941
942
|
* then: a height of its own — a percentage of the rows it spans where they
|
|
942
|
-
* have a length for a size — or the rows' where
|
|
943
|
-
*
|
|
944
|
-
* height is its content's.
|
|
943
|
+
* have a length for a size — or the rows' where `stretch` stretches it
|
|
944
|
+
* down them, its own `align-self` or the grid's `align-items`. Null where
|
|
945
|
+
* it has none, which is where its height is its content's.
|
|
945
946
|
*/
|
|
946
947
|
function heightBeforeRows(box: Box, rows: number): number | null {
|
|
947
948
|
const style = box.style;
|
|
@@ -954,10 +955,12 @@ function heightBeforeRows(box: Box, rows: number): number | null {
|
|
|
954
955
|
: own + box.verticalExtra,
|
|
955
956
|
);
|
|
956
957
|
}
|
|
958
|
+
const align =
|
|
959
|
+
style.alignSelf === AUTO ? box.parent?.style.alignItems : style.alignSelf;
|
|
957
960
|
if (
|
|
958
961
|
style.height === AUTO &&
|
|
959
962
|
!style.heightKeyword &&
|
|
960
|
-
|
|
963
|
+
align === 'stretch' &&
|
|
961
964
|
Number.isFinite(rows) &&
|
|
962
965
|
!autoMargins(box, 'y').some(Boolean)
|
|
963
966
|
) {
|