@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.
Files changed (134) hide show
  1. package/dist/html/controls.d.ts +29 -2
  2. package/dist/html/controls.d.ts.map +1 -1
  3. package/dist/html/controls.js +70 -2
  4. package/dist/html/controls.js.map +1 -1
  5. package/dist/html/css/cascade.d.ts +42 -1
  6. package/dist/html/css/cascade.d.ts.map +1 -1
  7. package/dist/html/css/cascade.js +336 -16
  8. package/dist/html/css/cascade.js.map +1 -1
  9. package/dist/html/css/color.d.ts +18 -0
  10. package/dist/html/css/color.d.ts.map +1 -1
  11. package/dist/html/css/color.js +27 -0
  12. package/dist/html/css/color.js.map +1 -1
  13. package/dist/html/css/parse.d.ts +18 -4
  14. package/dist/html/css/parse.d.ts.map +1 -1
  15. package/dist/html/css/parse.js +66 -28
  16. package/dist/html/css/parse.js.map +1 -1
  17. package/dist/html/css/shapes.d.ts +44 -0
  18. package/dist/html/css/shapes.d.ts.map +1 -0
  19. package/dist/html/css/shapes.js +194 -0
  20. package/dist/html/css/shapes.js.map +1 -0
  21. package/dist/html/css/style.d.ts +128 -15
  22. package/dist/html/css/style.d.ts.map +1 -1
  23. package/dist/html/css/style.js +547 -144
  24. package/dist/html/css/style.js.map +1 -1
  25. package/dist/html/css/transform.d.ts +85 -0
  26. package/dist/html/css/transform.d.ts.map +1 -0
  27. package/dist/html/css/transform.js +425 -0
  28. package/dist/html/css/transform.js.map +1 -0
  29. package/dist/html/css/ua.d.ts.map +1 -1
  30. package/dist/html/css/ua.js +14 -2
  31. package/dist/html/css/ua.js.map +1 -1
  32. package/dist/html/css/values.d.ts +4 -0
  33. package/dist/html/css/values.d.ts.map +1 -1
  34. package/dist/html/css/values.js.map +1 -1
  35. package/dist/html/fonts.d.ts +55 -5
  36. package/dist/html/fonts.d.ts.map +1 -1
  37. package/dist/html/fonts.js +284 -23
  38. package/dist/html/fonts.js.map +1 -1
  39. package/dist/html/layout/axes.d.ts +14 -0
  40. package/dist/html/layout/axes.d.ts.map +1 -0
  41. package/dist/html/layout/axes.js +28 -0
  42. package/dist/html/layout/axes.js.map +1 -0
  43. package/dist/html/layout/block.d.ts +104 -12
  44. package/dist/html/layout/block.d.ts.map +1 -1
  45. package/dist/html/layout/block.js +410 -39
  46. package/dist/html/layout/block.js.map +1 -1
  47. package/dist/html/layout/boxes.d.ts +72 -1
  48. package/dist/html/layout/boxes.d.ts.map +1 -1
  49. package/dist/html/layout/boxes.js +40 -2
  50. package/dist/html/layout/boxes.js.map +1 -1
  51. package/dist/html/layout/cache.d.ts +1 -1
  52. package/dist/html/layout/cache.d.ts.map +1 -1
  53. package/dist/html/layout/cache.js +6 -0
  54. package/dist/html/layout/cache.js.map +1 -1
  55. package/dist/html/layout/css-grid.d.ts.map +1 -1
  56. package/dist/html/layout/css-grid.js +144 -24
  57. package/dist/html/layout/css-grid.js.map +1 -1
  58. package/dist/html/layout/flex.d.ts.map +1 -1
  59. package/dist/html/layout/flex.js +585 -85
  60. package/dist/html/layout/flex.js.map +1 -1
  61. package/dist/html/layout/inline.d.ts +3 -0
  62. package/dist/html/layout/inline.d.ts.map +1 -1
  63. package/dist/html/layout/inline.js +144 -54
  64. package/dist/html/layout/inline.js.map +1 -1
  65. package/dist/html/layout/multicol.d.ts +42 -0
  66. package/dist/html/layout/multicol.d.ts.map +1 -0
  67. package/dist/html/layout/multicol.js +897 -0
  68. package/dist/html/layout/multicol.js.map +1 -0
  69. package/dist/html/layout/shaping.d.ts +7 -0
  70. package/dist/html/layout/shaping.d.ts.map +1 -1
  71. package/dist/html/layout/shaping.js +25 -20
  72. package/dist/html/layout/shaping.js.map +1 -1
  73. package/dist/html/layout/table.d.ts.map +1 -1
  74. package/dist/html/layout/table.js +97 -31
  75. package/dist/html/layout/table.js.map +1 -1
  76. package/dist/html/node.d.ts +4 -0
  77. package/dist/html/node.d.ts.map +1 -1
  78. package/dist/html/node.js +319 -47
  79. package/dist/html/node.js.map +1 -1
  80. package/dist/html/paint.d.ts +83 -5
  81. package/dist/html/paint.d.ts.map +1 -1
  82. package/dist/html/paint.js +1474 -217
  83. package/dist/html/paint.js.map +1 -1
  84. package/dist/html/svg.d.ts +39 -9
  85. package/dist/html/svg.d.ts.map +1 -1
  86. package/dist/html/svg.js +482 -37
  87. package/dist/html/svg.js.map +1 -1
  88. package/dist/html/widgets.js +87 -7
  89. package/dist/html/widgets.js.map +1 -1
  90. package/dist/html/woff2.d.ts +14 -0
  91. package/dist/html/woff2.d.ts.map +1 -0
  92. package/dist/html/woff2.js +608 -0
  93. package/dist/html/woff2.js.map +1 -0
  94. package/dist/maps/controller.d.ts +17 -1
  95. package/dist/maps/controller.d.ts.map +1 -1
  96. package/dist/maps/controller.js +27 -7
  97. package/dist/maps/controller.js.map +1 -1
  98. package/dist/richtext/node.d.ts +8 -1
  99. package/dist/richtext/node.d.ts.map +1 -1
  100. package/dist/richtext/node.js +5 -1
  101. package/dist/richtext/node.js.map +1 -1
  102. package/dist/richtext/runs.d.ts +25 -6
  103. package/dist/richtext/runs.d.ts.map +1 -1
  104. package/dist/richtext/runs.js +240 -24
  105. package/dist/richtext/runs.js.map +1 -1
  106. package/package.json +1 -1
  107. package/src/html/controls.ts +85 -2
  108. package/src/html/css/cascade.ts +366 -8
  109. package/src/html/css/color.ts +29 -0
  110. package/src/html/css/parse.ts +71 -31
  111. package/src/html/css/shapes.ts +239 -0
  112. package/src/html/css/style.ts +652 -147
  113. package/src/html/css/transform.ts +459 -0
  114. package/src/html/css/ua.ts +15 -2
  115. package/src/html/css/values.ts +4 -0
  116. package/src/html/fonts.ts +312 -29
  117. package/src/html/layout/axes.ts +62 -0
  118. package/src/html/layout/block.ts +466 -37
  119. package/src/html/layout/boxes.ts +95 -3
  120. package/src/html/layout/cache.ts +6 -0
  121. package/src/html/layout/css-grid.ts +169 -32
  122. package/src/html/layout/flex.ts +686 -79
  123. package/src/html/layout/inline.ts +149 -55
  124. package/src/html/layout/multicol.ts +977 -0
  125. package/src/html/layout/shaping.ts +27 -18
  126. package/src/html/layout/table.ts +105 -35
  127. package/src/html/node.ts +354 -48
  128. package/src/html/paint.ts +1804 -315
  129. package/src/html/svg.ts +573 -36
  130. package/src/html/widgets.ts +95 -9
  131. package/src/html/woff2.ts +612 -0
  132. package/src/maps/controller.ts +28 -7
  133. package/src/richtext/node.ts +13 -2
  134. package/src/richtext/runs.ts +313 -35
@@ -47,29 +47,38 @@ export function shapingSafe(engine: FontsLike): FontsLike {
47
47
  return engine.layout(stood.content, style, options);
48
48
  }
49
49
  };
50
- // Everything else the engine answers is its own, called on it: `match`,
51
- // and what a caller feature-detects — ntk's `prewarm`, which
52
- // `_warmFaces` asks for — where a wrapper that forwarded only the two
53
- // it knew of hid the rest, and warming stopped without a word.
54
- const bound = new Map<PropertyKey, { from: unknown; to: unknown }>();
55
- safe = new Proxy(engine, {
56
- get(target, key) {
57
- if (key === 'layout') return layout;
58
- const value: unknown = Reflect.get(target, key, target);
59
- if (typeof value !== 'function') return value;
60
- let hit = bound.get(key);
61
- if (hit?.from !== value) {
62
- hit = { from: value, to: value.bind(target) };
63
- bound.set(key, hit);
64
- }
65
- return hit.to;
66
- },
67
- });
50
+ safe = withLayout(engine, layout);
68
51
  SAFE.set(engine, safe);
69
52
  }
70
53
  return safe;
71
54
  }
72
55
 
56
+ /**
57
+ * `engine` with another `layout`. Everything else the engine answers is its
58
+ * own, called on it: `match`, and what a caller feature-detects — ntk's
59
+ * `prewarm`, which `_warmFaces` asks for — where a wrapper that forwarded
60
+ * only the two it knew of hid the rest, and warming stopped without a word.
61
+ */
62
+ export function withLayout(
63
+ engine: FontsLike,
64
+ layout: FontsLike['layout'],
65
+ ): FontsLike {
66
+ const bound = new Map<PropertyKey, { from: unknown; to: unknown }>();
67
+ return new Proxy(engine, {
68
+ get(target, key) {
69
+ if (key === 'layout') return layout;
70
+ const value: unknown = Reflect.get(target, key, target);
71
+ if (typeof value !== 'function') return value;
72
+ let hit = bound.get(key);
73
+ if (hit?.from !== value) {
74
+ hit = { from: value, to: value.bind(target) };
75
+ bound.set(key, hit);
76
+ }
77
+ return hit.to;
78
+ },
79
+ });
80
+ }
81
+
73
82
  /** `content` with each character its face cannot shape replaced, or null
74
83
  * when there is none to replace. */
75
84
  function standIns(
@@ -13,11 +13,16 @@
13
13
  // algorithm is too slow — which, on a table with a thousand rows, it is.
14
14
  import { AUTO, isPct, resolveOrNull } from '../css/values.js';
15
15
  import type { Len } from '../css/values.js';
16
+ import type { ComputedStyle } from '../css/style.js';
16
17
  import { Box, CLIPPED_CELLS, COLLAPSED_CELLS, isBlank } from './boxes.js';
17
18
  import {
18
19
  CELL_CONTENT,
20
+ FLEXED_HEIGHT,
19
21
  MIN_CONTENT_PROBE,
22
+ STRETCHED_ACROSS,
23
+ USED_HEIGHT,
20
24
  clampHeight,
25
+ cyclicWidth,
21
26
  exactMinContent,
22
27
  layoutBlockIn,
23
28
  measureIntrinsicWidth,
@@ -40,12 +45,19 @@ export function layoutTable(
40
45
  tableGrid(table);
41
46
  table.captionTop = 0;
42
47
  table.captionBottom = 0;
48
+ // a percentage of a width that is not known is `auto`: the table is as
49
+ // wide as its columns where its content is measured (`cyclicWidth`)
50
+ const own =
51
+ table.style.width === AUTO || cyclicWidth(table.style, contentWidth);
52
+ // — and one a grid stretches across its area is as wide as that, as a
53
+ // table with a width of its own is (`STRETCHED_ACROSS`)
54
+ const auto = own && !STRETCHED_ACROSS.has(table);
43
55
  if (!columnCount) {
44
56
  // With no columns, an auto table is as wide as its widest caption can
45
57
  // be and its `min-width` asks, as one with columns is at the least
46
58
  // (17.5.2), rather than as the room on offer: a caption over no cells
47
59
  // was centred in the width of the page.
48
- if (table.style.width === AUTO) {
60
+ if (auto) {
49
61
  let inner = captions.length
50
62
  ? captionMinimum(captions, ctx) - table.horizontalExtra
51
63
  : 0;
@@ -72,11 +84,18 @@ export function layoutTable(
72
84
  const gaps = spacing * (columnCount + 1);
73
85
  const available = Math.max(0, contentWidth - gaps);
74
86
 
75
- for (const cell of cells) resolveEdges(cell.box, contentWidth);
87
+ // While the columns are sized, a percentage in a cell's padding is of
88
+ // nothing: the width it is of is the one the columns are being sized to
89
+ // come to (CSS Sizing 3, 5.2.1), and a cell asks of its column what its
90
+ // content does. It is a share of the row once the columns have their
91
+ // widths, below. Taken of the table's width here, and of the cell's own
92
+ // where the cell was laid out, a padded cell's column was wider than
93
+ // its share and its padding narrower.
94
+ for (const cell of cells) resolveEdges(cell.box, 0);
76
95
 
77
96
  // a fixed layout needs a width to be fixed to; with `auto` a table is laid
78
- // out by its contents after all (CSS 2.1 17.5.2.1)
79
- const fixed = style.tableLayout === 'fixed' && style.width !== AUTO;
97
+ // out by its contents after all (CSS 2.1 17.5.2.1), stretched or not
98
+ const fixed = style.tableLayout === 'fixed' && !own;
80
99
  // a percentage of the table's width less its spacing (CSS 2.1 17.5.2.1)
81
100
  const set = columnWidths(columnBoxes, columnGroups, available);
82
101
  const widths = fixed
@@ -88,14 +107,14 @@ export function layoutTable(
88
107
  available,
89
108
  ctx,
90
109
  contentWidth,
91
- style.width !== AUTO,
110
+ !auto,
92
111
  spacing,
93
112
  );
94
113
 
95
114
  // --- place ---------------------------------------------------------------
96
115
  // An auto table is at least as wide as its widest caption can be (CSS 2.1
97
116
  // 17.5.2), and as its `min-width` asks; the columns share what that adds.
98
- if (style.width === AUTO) {
117
+ if (auto) {
99
118
  let room = 0;
100
119
  if (captions.length) {
101
120
  room = captionMinimum(captions, ctx) - table.horizontalExtra - gaps;
@@ -145,7 +164,7 @@ export function layoutTable(
145
164
  // gives its room back either way, set width or not.
146
165
  const used = x - table.contentX;
147
166
  let tableContentWidth = contentWidth;
148
- if (style.width === AUTO) {
167
+ if (auto) {
149
168
  tableContentWidth = used;
150
169
  table.width = tableContentWidth + table.horizontalExtra;
151
170
  } else if (used > contentWidth || anyGone) {
@@ -164,11 +183,21 @@ export function layoutTable(
164
183
  // tallest cell in it rather than the first one that was measured. What
165
184
  // its content came to is kept apart from a height the cell sets: it is
166
185
  // that content `vertical-align` moves in the cell.
186
+ //
187
+ // A percentage in a cell's padding is of the width of its row: the
188
+ // columns and the spacing between them, without the spacing either side
189
+ // and the table's own padding. CSS 2.1 8.4 has it of the containing
190
+ // block's width and names none for a cell; the row's is what browsers
191
+ // take, and what the table's content box is wherever there is no
192
+ // spacing. Every column counts, one `visibility: collapse` takes out
193
+ // too, so that taking it out changes no row's height.
194
+ let rowWidth = spacing * Math.max(0, columnCount - 1);
195
+ for (const columnWidth of widths) rowWidth += columnWidth;
167
196
  const natural: number[] = new Array<number>(cells.length);
168
197
  for (let i = 0; i < cells.length; i += 1) {
169
198
  const cell = cells[i];
170
199
  const width = spannedWidth(widths, cell, spacing);
171
- ctx.layoutSubtree(cell.box, width);
200
+ ctx.layoutSubtree(cell.box, width, rowWidth);
172
201
  natural[i] = CELL_CONTENT.get(cell.box) ?? cell.box.height;
173
202
  // A height a cell sets is a least one: its content is laid out as a
174
203
  // block's, which keeps a height it sets and lets the content run out of
@@ -187,15 +216,21 @@ export function layoutTable(
187
216
  // A cell aligned on the baseline — every value but `top`, `middle` and
188
217
  // `bottom` — hangs its first line on its first row's baseline, the lowest
189
218
  // of theirs from the row's top (CSS 2.1 17.5.3), and the row is as tall as
190
- // the cells hung from it need.
191
- const lift = baselineLifts(cells, rows.length);
219
+ // the cells hung from it need. What moves down is the content, so a cell
220
+ // needs the lift and its content, and a height it sets is a least one
221
+ // beside that rather than more room under the lift: two cells set
222
+ // `height: 80px` with text of two sizes in them are a row 80px tall, where
223
+ // the lift on top of the height made it 104px. A cell spanning rows needs
224
+ // the same of them, which is where Chrome differs: it sizes a spanning
225
+ // cell by its content and height alone and lets the lifted content hang
226
+ // out of it, and the rows here "encompass the cell" (17.5.3).
227
+ const lift = baselineLifts(cells, rows.length, natural);
228
+ const needs = (i: number): number =>
229
+ Math.max(cells[i].box.height, lift[i] + natural[i]);
192
230
  for (let i = 0; i < cells.length; i += 1) {
193
231
  const cell = cells[i];
194
232
  if (cell.rowSpan > 1) continue;
195
- rowHeight[cell.row] = Math.max(
196
- rowHeight[cell.row],
197
- lift[i] + cell.box.height,
198
- );
233
+ rowHeight[cell.row] = Math.max(rowHeight[cell.row], needs(i));
199
234
  }
200
235
  for (let r = 0; r < rows.length; r += 1) {
201
236
  const specified = resolveOrNull(rows[r].style.height, NaN);
@@ -211,14 +246,20 @@ export function layoutTable(
211
246
  let covered = 0;
212
247
  for (let r = cell.row; r <= last; r += 1) covered += rowHeight[r];
213
248
  covered += rowSpacing * (last - cell.row);
214
- const missing = lift[i] + cell.box.height - covered;
249
+ const missing = needs(i) - covered;
215
250
  if (missing > 0) rowHeight[last] += missing;
216
251
  }
217
252
 
218
253
  // A table's own height, within its least and greatest, is a least
219
254
  // height: what its rows come short of it goes to them (CSS 2.1 17.5.3,
220
- // which leaves how to its user agents: `growRows`)
255
+ // which leaves how to its user agents: `growRows`). So is the height a
256
+ // flex or grid layout gave it, stretched or flexed (`FLEXED_HEIGHT`,
257
+ // `USED_HEIGHT`), which is its wrapper box's, captions and all (CSS
258
+ // Flexbox 1, 4): taken as the table's box alone, a table stretched down
259
+ // its line kept its rows at their content's height, and a cell had
260
+ // nothing for `vertical-align` to centre its content in.
221
261
  const wanted = resolveOrNull(style.height, table.percentHeightBase);
262
+ const given = FLEXED_HEIGHT.get(table) ?? USED_HEIGHT.get(table) ?? NaN;
222
263
  if (rows.length) {
223
264
  const extraBox = table.verticalExtra;
224
265
  const set =
@@ -227,7 +268,10 @@ export function layoutTable(
227
268
  : style.boxSizing === 'border-box'
228
269
  ? wanted
229
270
  : wanted + extraBox;
230
- const inner = clampHeight(table, set) - extraBox;
271
+ let inner = clampHeight(table, set) - extraBox;
272
+ if (Number.isFinite(given)) {
273
+ inner = Math.max(inner, given - table.captionTop - table.captionBottom);
274
+ }
231
275
  let total = 0;
232
276
  for (const h of rowHeight) total += h;
233
277
  const extra = inner - total - rowSpacing * (rows.length + 1);
@@ -303,7 +347,9 @@ export function layoutTable(
303
347
  // `vertical-align` inside a cell moves the *content*, not the box: the
304
348
  // box fills the row, background and all, and the content sits top,
305
349
  // middle, bottom or on the row's baseline in it — in the box a height
306
- // of its own makes too, which is no content to be moved
350
+ // of its own makes too, which is no content to be moved. The cell was
351
+ // laid out above, in this pass over the cells, so this is the one move
352
+ // its content and its static positions get (`moveContent`)
307
353
  let offset = lift[i];
308
354
  const va = cell.box.style.verticalAlign;
309
355
  const content = natural[i];
@@ -462,7 +508,7 @@ function fixedColumns(
462
508
  }
463
509
  for (const cell of cells) {
464
510
  if (cell.row > 0) break;
465
- const px = tableWidth(cell.box.style.width, available);
511
+ const px = ownWidth(cell.box.style, available);
466
512
  if (px === null) continue;
467
513
  const box = cell.box;
468
514
  const outer =
@@ -706,14 +752,14 @@ function columnWidths(
706
752
  }
707
753
 
708
754
  /** A column's or a column group's width, within its limits, or null where
709
- * it sets none. */
755
+ * it sets none. The limits are lengths: a percentage in them does what it
756
+ * does in a cell's (`cellWidth`). */
710
757
  function partWidth(box: Box, base: number): number | null {
711
758
  const style = box.style;
712
- const width = tableWidth(style.width, base);
713
- const min = lengthAgainst(style.minWidth, base) ?? 0;
759
+ const width = ownWidth(style, base);
760
+ const min = typeof style.minWidth === 'number' ? style.minWidth : 0;
714
761
  if (width === null && !(min > 0)) return null;
715
- const max =
716
- style.maxWidth === 'none' ? null : lengthAgainst(style.maxWidth, base);
762
+ const max = typeof style.maxWidth === 'number' ? style.maxWidth : null;
717
763
  let out = width ?? 0;
718
764
  if (max !== null) out = Math.min(out, max);
719
765
  return Math.max(0, out, min);
@@ -726,15 +772,20 @@ function partWidth(box: Box, base: number): number | null {
726
772
  * `min-width` and `max-width` as a column's is (`partWidth`), which CSS
727
773
  * 2.1 leaves undefined and every browser does: a cell set `width: 3in;
728
774
  * max-width: 1in` is an inch wide, and one with `min-width` alone is as
729
- * wide as that. */
775
+ * wide as that.
776
+ *
777
+ * Where they are lengths. A percentage `min-width` is ignored, and a
778
+ * percentage `max-width` holds a percentage `width` and nothing else
779
+ * (CSS Tables 3, 3.8.2, and `ownWidth`): a cell `width: 100px;
780
+ * max-width: 10%` in a table of 600 is 100 wide, where it was 60, and
781
+ * one set `min-width: 150%` takes no more than its content asks. */
730
782
  function cellWidth(cell: Cell, base: number): number | null {
731
783
  const style = cell.box.style;
732
784
  const len = style.width;
733
- const width = len === AUTO ? null : tableWidth(len, base);
734
- const min = lengthAgainst(style.minWidth, base) ?? 0;
785
+ const width = ownWidth(style, base);
786
+ const min = typeof style.minWidth === 'number' ? style.minWidth : 0;
735
787
  if (width === null && !(min > 0)) return null;
736
- const max =
737
- style.maxWidth === 'none' ? null : lengthAgainst(style.maxWidth, base);
788
+ const max = typeof style.maxWidth === 'number' ? style.maxWidth : null;
738
789
  let own = width ?? 0;
739
790
  if (max !== null) own = Math.min(own, max);
740
791
  own = Math.max(0, own, min);
@@ -744,6 +795,19 @@ function cellWidth(cell: Cell, base: number): number | null {
744
795
  return own + cell.box.horizontalExtra;
745
796
  }
746
797
 
798
+ /** A cell's, a column's or a column group's `width` as the columns read
799
+ * it, or null: a percentage no more than a percentage its `max-width` is
800
+ * — the percentage each contributes is `min(percentage width, percentage
801
+ * max-width)`, a `max-width` that is no percentage counting as an
802
+ * infinite one (CSS Tables 3, 3.8.2). */
803
+ function ownWidth(style: ComputedStyle, base: number): number | null {
804
+ const width = tableWidth(style.width, base);
805
+ const limit = style.maxWidth;
806
+ if (width === null || !isPct(style.width)) return width;
807
+ if (limit === 'none' || !isPct(limit) || limit.px || limit.of) return width;
808
+ return Math.min(width, lengthAgainst(limit, base) ?? width);
809
+ }
810
+
747
811
  /** A cell's or a column's width. One that adds a percentage to a length,
748
812
  * a `calc()`, is `auto` in a table, as browsers read it: a column cannot be
749
813
  * both a share of the table and a size of its own. */
@@ -762,12 +826,18 @@ function lengthAgainst(len: Len, base: number): number | null {
762
826
  * row's: 0 for a cell aligned `top`, `middle` or `bottom`, which is placed
763
827
  * once the row's height is known. A cell's baseline is its first line box's,
764
828
  * at any depth, or the bottom of its content where it has none (CSS 2.1
765
- * 17.5.3); it is taken as laid out, from the cell's top. An empty cell has
766
- * nothing to align and says nothing about the row's, as in a browser: its
767
- * content's bottom is its height, which would hang every other cell in the
768
- * row from the bottom of a cell given a height and nothing in it.
829
+ * 17.5.3); it is taken as laid out, from the cell's top. That bottom is of
830
+ * the content (`natural`) and not of a height the cell sets, which "does not
831
+ * increase the height of the cell box": taken from the set height, a cell
832
+ * holding one block of 30px in 80px hung the text beside it from 80px. An
833
+ * empty cell has nothing to align and says nothing about the row's, as in a
834
+ * browser.
769
835
  */
770
- function baselineLifts(cells: Cell[], rowCount: number): number[] {
836
+ function baselineLifts(
837
+ cells: Cell[],
838
+ rowCount: number,
839
+ natural: number[],
840
+ ): number[] {
771
841
  const lift = new Array<number>(cells.length).fill(0);
772
842
  let any = false;
773
843
  for (const cell of cells) {
@@ -786,7 +856,7 @@ function baselineLifts(cells: Cell[], rowCount: number): number[] {
786
856
  own[i] =
787
857
  first !== null
788
858
  ? first - box.y
789
- : box.height - box.padBottom - box.borderBottom;
859
+ : natural[i] - box.padBottom - box.borderBottom;
790
860
  row[cells[i].row] = Math.max(row[cells[i].row], own[i]);
791
861
  }
792
862
  for (let i = 0; i < cells.length; i += 1) {