@react-x11/components 0.13.0 → 0.14.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.
Files changed (128) 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.map +1 -1
  6. package/dist/html/css/cascade.js +26 -4
  7. package/dist/html/css/cascade.js.map +1 -1
  8. package/dist/html/css/color.d.ts +18 -0
  9. package/dist/html/css/color.d.ts.map +1 -1
  10. package/dist/html/css/color.js +27 -0
  11. package/dist/html/css/color.js.map +1 -1
  12. package/dist/html/css/parse.d.ts +18 -4
  13. package/dist/html/css/parse.d.ts.map +1 -1
  14. package/dist/html/css/parse.js +66 -28
  15. package/dist/html/css/parse.js.map +1 -1
  16. package/dist/html/css/style.d.ts +128 -15
  17. package/dist/html/css/style.d.ts.map +1 -1
  18. package/dist/html/css/style.js +561 -144
  19. package/dist/html/css/style.js.map +1 -1
  20. package/dist/html/css/transform.d.ts +85 -0
  21. package/dist/html/css/transform.d.ts.map +1 -0
  22. package/dist/html/css/transform.js +425 -0
  23. package/dist/html/css/transform.js.map +1 -0
  24. package/dist/html/css/ua.d.ts.map +1 -1
  25. package/dist/html/css/ua.js +14 -2
  26. package/dist/html/css/ua.js.map +1 -1
  27. package/dist/html/css/values.d.ts +4 -0
  28. package/dist/html/css/values.d.ts.map +1 -1
  29. package/dist/html/css/values.js.map +1 -1
  30. package/dist/html/fonts.d.ts +55 -5
  31. package/dist/html/fonts.d.ts.map +1 -1
  32. package/dist/html/fonts.js +284 -23
  33. package/dist/html/fonts.js.map +1 -1
  34. package/dist/html/layout/axes.d.ts +14 -0
  35. package/dist/html/layout/axes.d.ts.map +1 -0
  36. package/dist/html/layout/axes.js +28 -0
  37. package/dist/html/layout/axes.js.map +1 -0
  38. package/dist/html/layout/block.d.ts +93 -12
  39. package/dist/html/layout/block.d.ts.map +1 -1
  40. package/dist/html/layout/block.js +389 -39
  41. package/dist/html/layout/block.js.map +1 -1
  42. package/dist/html/layout/boxes.d.ts +59 -1
  43. package/dist/html/layout/boxes.d.ts.map +1 -1
  44. package/dist/html/layout/boxes.js +22 -2
  45. package/dist/html/layout/boxes.js.map +1 -1
  46. package/dist/html/layout/cache.d.ts +1 -1
  47. package/dist/html/layout/cache.d.ts.map +1 -1
  48. package/dist/html/layout/cache.js +6 -0
  49. package/dist/html/layout/cache.js.map +1 -1
  50. package/dist/html/layout/css-grid.d.ts.map +1 -1
  51. package/dist/html/layout/css-grid.js +90 -18
  52. package/dist/html/layout/css-grid.js.map +1 -1
  53. package/dist/html/layout/flex.d.ts.map +1 -1
  54. package/dist/html/layout/flex.js +570 -83
  55. package/dist/html/layout/flex.js.map +1 -1
  56. package/dist/html/layout/inline.d.ts +3 -0
  57. package/dist/html/layout/inline.d.ts.map +1 -1
  58. package/dist/html/layout/inline.js +144 -54
  59. package/dist/html/layout/inline.js.map +1 -1
  60. package/dist/html/layout/multicol.d.ts +42 -0
  61. package/dist/html/layout/multicol.d.ts.map +1 -0
  62. package/dist/html/layout/multicol.js +897 -0
  63. package/dist/html/layout/multicol.js.map +1 -0
  64. package/dist/html/layout/shaping.d.ts +7 -0
  65. package/dist/html/layout/shaping.d.ts.map +1 -1
  66. package/dist/html/layout/shaping.js +25 -20
  67. package/dist/html/layout/shaping.js.map +1 -1
  68. package/dist/html/layout/table.d.ts.map +1 -1
  69. package/dist/html/layout/table.js +62 -18
  70. package/dist/html/layout/table.js.map +1 -1
  71. package/dist/html/node.d.ts +3 -0
  72. package/dist/html/node.d.ts.map +1 -1
  73. package/dist/html/node.js +263 -36
  74. package/dist/html/node.js.map +1 -1
  75. package/dist/html/paint.d.ts +79 -4
  76. package/dist/html/paint.d.ts.map +1 -1
  77. package/dist/html/paint.js +1213 -141
  78. package/dist/html/paint.js.map +1 -1
  79. package/dist/html/svg.d.ts +15 -2
  80. package/dist/html/svg.d.ts.map +1 -1
  81. package/dist/html/svg.js +249 -17
  82. package/dist/html/svg.js.map +1 -1
  83. package/dist/html/widgets.js +87 -7
  84. package/dist/html/widgets.js.map +1 -1
  85. package/dist/html/woff2.d.ts +14 -0
  86. package/dist/html/woff2.d.ts.map +1 -0
  87. package/dist/html/woff2.js +608 -0
  88. package/dist/html/woff2.js.map +1 -0
  89. package/dist/maps/controller.d.ts +17 -1
  90. package/dist/maps/controller.d.ts.map +1 -1
  91. package/dist/maps/controller.js +27 -7
  92. package/dist/maps/controller.js.map +1 -1
  93. package/dist/richtext/node.d.ts +8 -1
  94. package/dist/richtext/node.d.ts.map +1 -1
  95. package/dist/richtext/node.js +5 -1
  96. package/dist/richtext/node.js.map +1 -1
  97. package/dist/richtext/runs.d.ts +25 -6
  98. package/dist/richtext/runs.d.ts.map +1 -1
  99. package/dist/richtext/runs.js +240 -24
  100. package/dist/richtext/runs.js.map +1 -1
  101. package/package.json +1 -1
  102. package/src/html/controls.ts +85 -2
  103. package/src/html/css/cascade.ts +23 -0
  104. package/src/html/css/color.ts +29 -0
  105. package/src/html/css/parse.ts +71 -31
  106. package/src/html/css/style.ts +664 -147
  107. package/src/html/css/transform.ts +459 -0
  108. package/src/html/css/ua.ts +15 -2
  109. package/src/html/css/values.ts +4 -0
  110. package/src/html/fonts.ts +312 -29
  111. package/src/html/layout/axes.ts +62 -0
  112. package/src/html/layout/block.ts +444 -37
  113. package/src/html/layout/boxes.ts +65 -3
  114. package/src/html/layout/cache.ts +6 -0
  115. package/src/html/layout/css-grid.ts +95 -22
  116. package/src/html/layout/flex.ts +671 -77
  117. package/src/html/layout/inline.ts +149 -55
  118. package/src/html/layout/multicol.ts +977 -0
  119. package/src/html/layout/shaping.ts +27 -18
  120. package/src/html/layout/table.ts +62 -19
  121. package/src/html/node.ts +300 -37
  122. package/src/html/paint.ts +1406 -206
  123. package/src/html/svg.ts +277 -19
  124. package/src/html/widgets.ts +95 -9
  125. package/src/html/woff2.ts +612 -0
  126. package/src/maps/controller.ts +28 -7
  127. package/src/richtext/node.ts +13 -2
  128. package/src/richtext/runs.ts +313 -35
package/dist/html/node.js CHANGED
@@ -43,9 +43,11 @@ import { attr, HtmlSource, imageUrlOf, isElement, tagOf } from './dom.js';
43
43
  import { Cascade, HOVER_FOLLOWED, HOVER_PSEUDO_NONE, HOVER_PSEUDO_OTHER, HOVER_UNTOUCHED, } from './css/cascade.js';
44
44
  import { mediaMatches, parseStylesheet } from './css/parse.js';
45
45
  import { uaStylesheet } from './css/ua.js';
46
- import { BOX_RAISES, buildBoxes, CONTENT_IMAGES, CLEARED_FROM, CUT_BLOCKS, GENERATED_FROM, INLINE_OFFSETS, LINE_BOX_RAISES, SHIFTED_LINES, TEXT_SHIFTS, } from './layout/boxes.js';
47
- import { layoutDocument, retranslate, transformed } from './layout/block.js';
46
+ import { BOX_RAISES, buildBoxes, CONTENT_IMAGES, CLEARED_FROM, COLUMN_LINES, COLUMN_PIECES, COLUMN_ROWS, CUT_BLOCKS, GENERATED_FROM, INLINE_OFFSETS, LINE_BOX_RAISES, SHIFTED_LINES, TEXT_SHIFTS, columned, } from './layout/boxes.js';
47
+ import { layoutDocument, placedMatrix, retranslate } from './layout/block.js';
48
+ import { invert, mapPoint, mapRect, transformed } from './css/transform.js';
48
49
  import { TextLayoutCache } from './layout/cache.js';
50
+ import { weightAxes } from './layout/axes.js';
49
51
  import { shapingSafe } from './layout/shaping.js';
50
52
  import { SurfaceCache, newSurface } from './surfaces.js';
51
53
  import { faceExtentOf, inlineDecoration, runFor } from './layout/inline.js';
@@ -53,7 +55,7 @@ import { faceExtentOf, inlineDecoration, runFor } from './layout/inline.js';
53
55
  // a layout is built once, on the first selection that needs it.
54
56
  import { documentOffsetOf, layoutOffsetOf, layoutOffsets as layoutOffsetsOf, } from './layout/inline.js';
55
57
  import { lineBands as bandsFor } from '../richtext/runs.js';
56
- import { clipsOverflow, computePaintBounds, containingBlockOf, FIXED_BOXES, fixedToViewport, forgetDecoratedAncestors, hasRect, hoistNegative, holds, holdsAbsolute, paintDocument, queryChildIndex, selectionRows, stackLayers, } from './paint.js';
58
+ import { clipsOverflow, computePaintBounds, containingBlockOf, FIXED_BOXES, fixedToViewport, forgetDecoratedAncestors, hasRect, hoistNegative, holds, holdsAbsolute, inClip, inClipPath, onLine, ownBounds, paintDocument, pathClips, queryChildIndex, selectionRows, stackLayers, stacksLayers, } from './paint.js';
57
59
  import { controlRectsOf, measureControl } from './controls.js';
58
60
  import { ResourceStore } from './resources.js';
59
61
  import { WebFonts } from './fonts.js';
@@ -545,8 +547,16 @@ export class HtmlViewNode extends Node {
545
547
  * next restyle whether the sheets read the same (`_sameSheets`). A sheet
546
548
  * that imports itself, or one of the sheets importing it, is read once.
547
549
  */
548
- _placeImports(sheet, encoding, element, layers, seen, place, depth = 0, chain = new Set()) {
549
- for (const url of sheet.imports) {
550
+ _placeImports(sheet, encoding, element, layers, seen, place, depth = 0, chain = new Set(),
551
+ /** The media queries `sheet` is itself under, where it was imported
552
+ * under some. */
553
+ under = null) {
554
+ for (let i = 0; i < sheet.imports.length; i += 1) {
555
+ const url = sheet.imports[i];
556
+ // what it imports is under its import's media queries, and under
557
+ // the ones the sheet importing it is under
558
+ const conditions = sheet.importConditions[i];
559
+ const media = conditions ? [...(under ?? []), conditions] : under;
550
560
  this._resources.request({ url, kind: 'stylesheet', element });
551
561
  const fetched = this._resources.stylesheet(url, [encoding]);
552
562
  const base = this._resources.sheetBase(url);
@@ -554,9 +564,9 @@ export class HtmlViewNode extends Node {
554
564
  const key = base ?? url;
555
565
  if (!fetched || depth >= MAX_IMPORT_DEPTH || chain.has(key))
556
566
  continue;
557
- const imported = parseStylesheet(fetched.text, 0, layers, base);
567
+ const imported = parseStylesheet(fetched.text, 0, layers, base, media);
558
568
  chain.add(key);
559
- this._placeImports(imported, fetched.encoding, element, layers, seen, place, depth + 1, chain);
569
+ this._placeImports(imported, fetched.encoding, element, layers, seen, place, depth + 1, chain, media);
560
570
  chain.delete(key);
561
571
  place(imported, element);
562
572
  }
@@ -671,11 +681,22 @@ export class HtmlViewNode extends Node {
671
681
  const height = root?.abs?.height;
672
682
  return height && height > 0 ? height : 600;
673
683
  }
684
+ /** The engine this document lays text out with, and the one it is over:
685
+ * one object while the engine is, since caches are kept by it. */
686
+ _engine = null;
674
687
  _fonts() {
675
688
  const fonts = this.app?.fonts;
689
+ if (!fonts)
690
+ return null;
676
691
  // a face the engine cannot shape from costs its characters, not the
677
692
  // document (`shaping.ts`)
678
- return fonts ? shapingSafe(fonts) : null;
693
+ const safe = shapingSafe(fonts);
694
+ if (this._engine?.over !== safe) {
695
+ // and a variable face of the document's is set at the weight its
696
+ // rule has for a style's (`axes.ts`)
697
+ this._engine = { over: safe, fonts: weightAxes(safe, this._webFonts) };
698
+ }
699
+ return this._engine.fonts;
679
700
  }
680
701
  /** The text layouts the last pass made, for this one to reuse. */
681
702
  _layouts = null;
@@ -869,7 +890,7 @@ export class HtmlViewNode extends Node {
869
890
  // The boxes are device pixels; each rect becomes the style of a widget
870
891
  // mounted beside this element, and a style is logical.
871
892
  const s = this._scale;
872
- const rects = controlRectsOf(tree).map((r) => s === 1
893
+ const rects = controlRectsOf(tree, s).map((r) => s === 1
873
894
  ? r
874
895
  : {
875
896
  ...r,
@@ -878,6 +899,14 @@ export class HtmlViewNode extends Node {
878
899
  width: r.width / s,
879
900
  height: r.height / s,
880
901
  fontSize: r.fontSize / s,
902
+ ...(r.clip && {
903
+ clip: {
904
+ x: r.clip.x / s,
905
+ y: r.clip.y / s,
906
+ width: r.clip.width / s,
907
+ height: r.clip.height / s,
908
+ },
909
+ }),
881
910
  ...(r.bare && {
882
911
  bare: {
883
912
  ...r.bare,
@@ -1184,6 +1213,9 @@ export class HtmlViewNode extends Node {
1184
1213
  rect = { x: caret.x, y: caret.y, width: 0, height: caret.height };
1185
1214
  }
1186
1215
  }
1216
+ // where it is drawn: the rectangle around it, turned and scaled as the
1217
+ // boxes it is in are, and itself (`getBoundingClientRect`, CSSOM View)
1218
+ rect = throughTransforms(rect, box);
1187
1219
  const s = this._scale;
1188
1220
  return {
1189
1221
  x: rect.x / s,
@@ -2114,12 +2146,18 @@ function sameRects(a, b) {
2114
2146
  p.fontFamily !== q.fontFamily ||
2115
2147
  p.fontSize !== q.fontSize ||
2116
2148
  p.opacity !== q.opacity ||
2149
+ !sameClip(p.clip, q.clip) ||
2117
2150
  !sameBare(p.bare, q.bare)) {
2118
2151
  return false;
2119
2152
  }
2120
2153
  }
2121
2154
  return true;
2122
2155
  }
2156
+ function sameClip(a, b) {
2157
+ if (!a || !b)
2158
+ return a === b;
2159
+ return (a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height);
2160
+ }
2123
2161
  function sameBare(a, b) {
2124
2162
  if (!a || !b)
2125
2163
  return a === b;
@@ -2166,7 +2204,13 @@ function nearestText(box, x, y) {
2166
2204
  if (distance >= bestDistance)
2167
2205
  continue;
2168
2206
  bestDistance = distance;
2169
- const local = text.layout.indexAt(x - text.drawX, y - text.drawY);
2207
+ // in the row that is this line's, where the layout's other lines are
2208
+ // in another column and a point past this one is not over them
2209
+ let row = y - text.drawY;
2210
+ if (columned.any && COLUMN_ROWS.has(text)) {
2211
+ row = Math.max(natural.y, Math.min(row, natural.y + natural.height - 0.01));
2212
+ }
2213
+ const local = text.layout.indexAt(x - text.drawX, row);
2170
2214
  const offsets = layoutOffsetsOf(text.layout);
2171
2215
  const units = offsets.length
2172
2216
  ? offsets[Math.max(0, Math.min(local, offsets.length - 1))]
@@ -2179,13 +2223,38 @@ function nearestText(box, x, y) {
2179
2223
  axisDistance(x, node.boundsX, node.boundsWidth);
2180
2224
  if (boundsDistance >= bestDistance)
2181
2225
  return;
2226
+ // in a box painted through a matrix, the point taken back through it
2227
+ // (`deepestAt`): the text is where it was laid out
2228
+ const matrix = placedMatrix(node);
2229
+ if (!matrix) {
2230
+ visitIn(node);
2231
+ return;
2232
+ }
2233
+ const back = invert(matrix);
2234
+ if (!back)
2235
+ return;
2236
+ const px = x;
2237
+ const py = y;
2238
+ [x, y] = mapPoint(back, px, py);
2239
+ try {
2240
+ visitIn(node);
2241
+ }
2242
+ finally {
2243
+ x = px;
2244
+ y = py;
2245
+ }
2246
+ };
2247
+ const visitIn = (node) => {
2182
2248
  const lines = node.lines;
2183
2249
  if (lines?.length) {
2184
2250
  // The line nearest in y, by binary search; then outward both ways
2185
2251
  // while vertical distance alone could still beat the best.
2186
2252
  let lo = 0;
2187
2253
  let hi = lines.length;
2188
- while (lo < hi) {
2254
+ // the lines columns took apart are in no order down the page: each
2255
+ // is tried
2256
+ const apart = columned.any && COLUMN_LINES.has(lines);
2257
+ while (!apart && lo < hi) {
2189
2258
  const mid = (lo + hi) >> 1;
2190
2259
  if (lines[mid].y > y)
2191
2260
  hi = mid;
@@ -2198,8 +2267,11 @@ function nearestText(box, x, y) {
2198
2267
  tryLine(lines[i]);
2199
2268
  }
2200
2269
  for (let i = lo; i < lines.length; i += 1) {
2201
- if (axisDistance(y, lines[i].y, lines[i].height) * 4 >= bestDistance)
2270
+ if (axisDistance(y, lines[i].y, lines[i].height) * 4 >= bestDistance) {
2271
+ if (apart)
2272
+ continue;
2202
2273
  break;
2274
+ }
2203
2275
  tryLine(lines[i]);
2204
2276
  }
2205
2277
  }
@@ -2287,7 +2359,13 @@ function caretAt(box, units) {
2287
2359
  const offsets = layoutOffsetsOf(text.layout);
2288
2360
  const layoutUnits = layoutOffsetOf(text, units);
2289
2361
  const caret = text.layout.caretPosition(codePointAtOffset(offsets, layoutUnits));
2290
- found = { x: text.drawX + caret.x, y: line.y, height: line.height };
2362
+ const at = throughTransforms({
2363
+ x: text.drawX + caret.x,
2364
+ y: line.y,
2365
+ width: 0,
2366
+ height: line.height,
2367
+ }, node);
2368
+ found = { x: at.x, y: at.y, height: at.height };
2291
2369
  return;
2292
2370
  }
2293
2371
  }
@@ -2303,6 +2381,21 @@ function caretAt(box, units) {
2303
2381
  visit(box);
2304
2382
  return found;
2305
2383
  }
2384
+ /**
2385
+ * A rectangle in a box's own coordinates — the ones it and what it holds
2386
+ * were laid out in — as the rectangle around where it is drawn: through
2387
+ * the matrix of each box from `from` up that is painted through one
2388
+ * (`placedMatrix`). The rectangle itself, in a document that transforms
2389
+ * nothing but by moving it.
2390
+ */
2391
+ function throughTransforms(rect, from) {
2392
+ for (let at = from; at; at = at.parent) {
2393
+ const matrix = placedMatrix(at);
2394
+ if (matrix)
2395
+ rect = mapRect(matrix, rect.x, rect.y, rect.width, rect.height);
2396
+ }
2397
+ return rect;
2398
+ }
2306
2399
  /** Every band a document range covers, in window coordinates. The subtree
2307
2400
  * text ranges prune the walk to the boxes the range actually crosses, so a
2308
2401
  * drag's small range costs its own paragraphs; only Ctrl+A pays for all. */
@@ -2451,6 +2544,19 @@ ink = false) {
2451
2544
  height: rows.height,
2452
2545
  });
2453
2546
  }
2547
+ // The spaces a piece of a line ends on, where the line goes on
2548
+ // after them: the engine stripped them from the piece it laid out
2549
+ // as a line, and they are the text's all the same, in the elements
2550
+ // that hold its end — a link whose text ends in a space, before
2551
+ // the next link, is that space wider than its letters
2552
+ if (text.trail && b >= text.textEnd && !rtlLine(natural)) {
2553
+ out.push({
2554
+ x: dx + natural.x + natural.width + text.drawX - moved,
2555
+ y: dy + rows.y,
2556
+ width: text.trail,
2557
+ height: rows.height,
2558
+ });
2559
+ }
2454
2560
  // the spaces `pre-wrap` keeps that the line ends on, which have no
2455
2561
  // run: the engine hung them past the line (`LineText.hung`)
2456
2562
  for (const space of text.hung ?? []) {
@@ -2468,6 +2574,11 @@ ink = false) {
2468
2574
  }
2469
2575
  }
2470
2576
  }
2577
+ /** Whether a laid-out line's last run reads right to left, its end at its
2578
+ * left. */
2579
+ function rtlLine(natural) {
2580
+ return natural.runs[natural.runs.length - 1]?.run?.direction === 'rtl';
2581
+ }
2471
2582
  /** Whether a line's text is where the line ends: its last, with nothing
2472
2583
  * placed after it — an inline-block or an image past its content. */
2473
2584
  function endsLine(line, text, natural) {
@@ -2485,6 +2596,7 @@ function collectBands(box, from, to, dx, dy, out, ink = false) {
2485
2596
  return;
2486
2597
  if (box.subtreeTextEnd <= from || box.subtreeTextStart >= to)
2487
2598
  return;
2599
+ const first = out.length;
2488
2600
  if (box.lines)
2489
2601
  lineBands(box.lines, from, to, dx, dy, out, false, ink);
2490
2602
  // Atomics are ordinary children, reached below.
@@ -2493,6 +2605,15 @@ function collectBands(box, from, to, dx, dy, out, ink = false) {
2493
2605
  continue;
2494
2606
  collectBands(child, from, to, dx, dy, out, ink);
2495
2607
  }
2608
+ // where a box painted through a matrix draws them
2609
+ const matrix = out.length > first ? placedMatrix(box) : null;
2610
+ if (!matrix)
2611
+ return;
2612
+ for (let i = first; i < out.length; i += 1) {
2613
+ const band = out[i];
2614
+ const to = mapRect(matrix, band.x - dx, band.y - dy, band.width, band.height);
2615
+ out[i] = { ...band, ...to, x: to.x + dx, y: to.y + dy };
2616
+ }
2496
2617
  }
2497
2618
  /** The layers of a hit test, in the order CSS paints them within a
2498
2619
  * context (`deepestAt`). */
@@ -2526,7 +2647,17 @@ fixedShift = null) {
2526
2647
  // are painted in `z-index` order and then the document's (`byZIndex`),
2527
2648
  // the negative ones under the flow: the Zen Garden's `›` has
2528
2649
  // `z-index: 3` over the bar the "View All Designs" link fills after it.
2529
- const take = (el, key, text) => {
2650
+ // Nor is a box the pointer passes through under it: one that is not
2651
+ // visible, which is no target for the pointer in any browser (CSS 2.1
2652
+ // 11.2 has it invisible, and a hit test finds what is seen), or one with
2653
+ // `pointer-events: none` (CSS UI 4, 5.2). Both are inherited, and what is
2654
+ // in such a box may say otherwise, so the walk goes on through it. A
2655
+ // site's closed menu is laid out over its page, hidden: GitHub's covered
2656
+ // its repository's tabs, and the pointer over a tab was over the menu.
2657
+ const take = (el, style, key, text) => {
2658
+ if (style.visibility !== 'visible' || style.pointerEvents === 'none') {
2659
+ return;
2660
+ }
2530
2661
  if (compareKeys(key, foundKey) < 0)
2531
2662
  return;
2532
2663
  found = el;
@@ -2568,14 +2699,79 @@ fixedShift = null) {
2568
2699
  atViewport = false;
2569
2700
  }
2570
2701
  };
2702
+ // A box painted through a matrix (`placedMatrix`) is under the point
2703
+ // where the matrix puts it: inside the rectangle around what it draws
2704
+ // there, the point is taken back through the matrix, into the
2705
+ // coordinates the box and all it holds were laid out in, and the walk
2706
+ // goes on with that. An icon turned a quarter is pressed where it is
2707
+ // drawn; a box flattened to nothing is nowhere.
2571
2708
  const enterAt = (child, context, clipped) => {
2709
+ const matrix = placedMatrix(child);
2710
+ if (!matrix) {
2711
+ enterIn(child, context, clipped, null);
2712
+ return;
2713
+ }
2714
+ if (x < child.boundsX ||
2715
+ x >= child.boundsX + child.boundsWidth ||
2716
+ y < child.boundsY ||
2717
+ y >= child.boundsY + child.boundsHeight) {
2718
+ return;
2719
+ }
2720
+ const back = invert(matrix);
2721
+ if (!back)
2722
+ return;
2723
+ const px = x;
2724
+ const py = y;
2725
+ [x, y] = mapPoint(back, px, py);
2726
+ try {
2727
+ enterIn(child, context, clipped, ownBounds(child));
2728
+ }
2729
+ finally {
2730
+ x = px;
2731
+ y = py;
2732
+ }
2733
+ };
2734
+ const enterIn = (child, context, clipped,
2735
+ /** What the box draws in its own coordinates, where those are not the
2736
+ * ones its bounds are in: a box painted through a matrix. */
2737
+ bounds) => {
2572
2738
  const style = child.style;
2739
+ // What a `clip-path` cuts away of a box it cuts away of all the box
2740
+ // holds, whatever that is positioned from (CSS Masking 1, 5.1), and
2741
+ // nothing not drawn is under a pointer: a label a page hides for a
2742
+ // screen reader alone under `clip-path: inset(50%)` took the hover and
2743
+ // the press of what was drawn where it lay.
2744
+ if (pathClips(child) && !inClipPath(child, x, y))
2745
+ return;
2746
+ // `clip` is not that rule as paint has it. It shows the part of an
2747
+ // absolute box it names (CSS 2.1 11.1.2), and past that part nothing is
2748
+ // drawn of the box, nor of what is painted with it. A stacking context
2749
+ // paints all it holds, inside its clip. A box that is none leaves its
2750
+ // positioned boxes to the context around it, which cuts each to the
2751
+ // clips its containing block is under (`clipsFor`): this one for all
2752
+ // but a fixed box, which is under none and is drawn past it. So past
2753
+ // its clip the first is left, and the second is walked as a box that
2754
+ // clips its overflow is past its edge — whether or not the point is in
2755
+ // its own rectangle, which a clip may show only a part of. Both were
2756
+ // walked as if they showed whole: a label hidden for a screen reader
2757
+ // alone under `clip: rect(0, 0, 0, 0)` took the hover and the press of
2758
+ // the link drawn where it lay.
2759
+ let cut = !inClip(child, x, y);
2760
+ if (cut && stacksLayers(child))
2761
+ return;
2573
2762
  if (style.position !== 'static' ||
2574
2763
  (child.parent?.kind === 'flex' && typeof style.zIndex === 'number')) {
2575
2764
  // a flex item with a `z-index` is layered unpositioned (`layered`)
2576
2765
  const z = style.zIndex === 'auto' ? 0 : style.zIndex;
2577
2766
  context = [...context, z < 0 ? HIT_NEGATIVE : HIT_POSITIONED, z];
2578
2767
  }
2768
+ else if (transformed(style) &&
2769
+ child.kind !== 'inline' &&
2770
+ child.parent &&
2771
+ !onLine(child.parent, child)) {
2772
+ // a transformed box is painted with the positioned ones (`layered`)
2773
+ context = [...context, HIT_POSITIONED, 0];
2774
+ }
2579
2775
  else if (style.float !== 'none')
2580
2776
  context = [...context, HIT_FLOAT];
2581
2777
  if (clipped.length !== 0 && child.outOfFlow) {
@@ -2584,33 +2780,45 @@ fixedShift = null) {
2584
2780
  ? clipped.filter((clip) => holds(clip, containing))
2585
2781
  : [];
2586
2782
  }
2587
- const inside = x >= child.x &&
2588
- x < child.x + child.width &&
2589
- y >= child.y &&
2590
- y < child.y + child.height;
2783
+ // in one of its pieces, where columns broke it: its rect takes in the
2784
+ // columns between them, which are other boxes'
2785
+ const pieces = columned.any ? COLUMN_PIECES.get(child) : undefined;
2786
+ const inside = pieces
2787
+ ? pieces.some((piece) => x >= piece.x &&
2788
+ x < piece.x + piece.width &&
2789
+ y >= piece.y &&
2790
+ y < piece.y + piece.height)
2791
+ : x >= child.x &&
2792
+ x < child.x + child.width &&
2793
+ y >= child.y &&
2794
+ y < child.y + child.height;
2591
2795
  const own = inside && hasRect(child);
2592
2796
  if (!own) {
2593
- const reach = child.boundsY;
2594
- const known = Number.isFinite(reach) &&
2595
- (child.boundsWidth > 0 || child.boundsHeight > 0);
2797
+ const left = bounds ? bounds.x : child.boundsX;
2798
+ const reach = bounds ? bounds.y : child.boundsY;
2799
+ const across = bounds ? bounds.width : child.boundsWidth;
2800
+ const down = bounds ? bounds.height : child.boundsHeight;
2801
+ const known = Number.isFinite(reach) && (across > 0 || down > 0);
2596
2802
  if (!known) {
2597
2803
  if (!inside)
2598
2804
  return;
2599
2805
  }
2600
- else if (x < child.boundsX ||
2601
- x >= child.boundsX + child.boundsWidth ||
2806
+ else if (x < left ||
2807
+ x >= left + across ||
2602
2808
  y < reach ||
2603
- y >= reach + child.boundsHeight) {
2809
+ y >= reach + down) {
2604
2810
  return;
2605
2811
  }
2606
- if (clipsOverflow(child)) {
2607
- if (!holdsAbsolute(child))
2608
- return;
2609
- clipped = [...clipped, child];
2610
- }
2812
+ if (clipsOverflow(child))
2813
+ cut = true;
2814
+ }
2815
+ if (cut) {
2816
+ if (!holdsAbsolute(child))
2817
+ return;
2818
+ clipped = [...clipped, child];
2611
2819
  }
2612
2820
  if (own && child.el && clipped.length === 0) {
2613
- take(child.el, [...context, HIT_BLOCK], false);
2821
+ take(child.el, style, [...context, HIT_BLOCK], false);
2614
2822
  }
2615
2823
  visit(child, context, clipped);
2616
2824
  };
@@ -2652,8 +2860,9 @@ fixedShift = null) {
2652
2860
  const left = text.drawX + natural.x + run.x;
2653
2861
  if (x >= left && x < left + run.width) {
2654
2862
  const owner = ownerOf(tree.textBoxes, text.spans.documentAt(run.start));
2655
- if (owner)
2656
- take(owner, [...context, HIT_INLINE], true);
2863
+ const style = owner && tree.styles.get(owner)?.style;
2864
+ if (style)
2865
+ take(owner, style, [...context, HIT_INLINE], true);
2657
2866
  }
2658
2867
  }
2659
2868
  }
@@ -2717,6 +2926,9 @@ const PAINT_ONLY = new Set([
2717
2926
  'color',
2718
2927
  'textFillColor',
2719
2928
  'cursor',
2929
+ 'pointerEvents',
2930
+ 'fill',
2931
+ 'stroke',
2720
2932
  'backgroundColor',
2721
2933
  'borderTopColor',
2722
2934
  'borderRightColor',
@@ -2733,6 +2945,8 @@ const PAINT_ONLY = new Set([
2733
2945
  'underlineThickness',
2734
2946
  'underlineOffset',
2735
2947
  'lineThrough',
2948
+ 'lineThroughStyle',
2949
+ 'lineThroughThickness',
2736
2950
  ]);
2737
2951
  /** The fields of a run its ink is: what `runFor` takes from `PAINT_ONLY`. */
2738
2952
  const INK_FIELDS = [
@@ -2742,6 +2956,8 @@ const INK_FIELDS = [
2742
2956
  'underlineOffset',
2743
2957
  'underlineThickness',
2744
2958
  'strike',
2959
+ 'strikeStyle',
2960
+ 'strikeThickness',
2745
2961
  ];
2746
2962
  /** The fields of a run its shape is, which ink never changes. */
2747
2963
  const FACE_FIELDS = [
@@ -2776,10 +2992,19 @@ const INK_REACH = new Set([
2776
2992
  'outlineWidth',
2777
2993
  'outlineOffset',
2778
2994
  ]);
2995
+ /** What transforms a box: it moves, turns or scales where it is, and
2996
+ * nothing around it does (CSS Transforms 1, 3). */
2997
+ const TRANSFORM_FIELDS = new Set([
2998
+ 'translate',
2999
+ 'rotate',
3000
+ 'scale',
3001
+ 'transform',
3002
+ 'transformOrigin',
3003
+ ]);
2779
3004
  /**
2780
3005
  * How two styles of one element differ, for a restyle in place: null where
2781
3006
  * they do not, a `HoverChange` where every difference is ink, how far ink
2782
- * reaches, a `z-index` that stays a stacking context's, or a translation —
3007
+ * reaches, a `z-index` that stays a stacking context's, or a transform —
2783
3008
  * none of which moves anything but the box and what it holds (CSS
2784
3009
  * Transforms 1: a transform does not affect layout) — and false where
2785
3010
  * anything else differs.
@@ -2819,7 +3044,7 @@ function hoverChange(was, now) {
2819
3044
  change.order = true;
2820
3045
  continue;
2821
3046
  }
2822
- if (key === 'transformTranslate' || key === 'translate') {
3047
+ if (TRANSFORM_FIELDS.has(key)) {
2823
3048
  change.move = true;
2824
3049
  continue;
2825
3050
  }
@@ -2867,12 +3092,14 @@ function inkOf(box) {
2867
3092
  return null;
2868
3093
  if (!(at.boundsWidth > 0 && at.boundsHeight > 0))
2869
3094
  return null;
2870
- return {
3095
+ // its bounds are in the coordinates of the box it is in, which a box
3096
+ // around it painted through a matrix draws somewhere else
3097
+ return throughTransforms({
2871
3098
  x: at.boundsX,
2872
3099
  y: at.boundsY,
2873
3100
  width: at.boundsWidth,
2874
3101
  height: at.boundsHeight,
2875
- };
3102
+ }, at.parent);
2876
3103
  }
2877
3104
  /** Structural equality for a computed value: a number, a string, or the
2878
3105
  * plain objects and arrays a length or a shadow list is. */