buninu-browser 0.2.2 → 0.2.4

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 (118) hide show
  1. package/lib/audio/playback-buffer.js +27 -0
  2. package/lib/audio/pulse-client.js +18 -8
  3. package/lib/cdp-server.js +53 -14
  4. package/lib/happy-dom/document-base.js +33 -0
  5. package/lib/happy-dom/parser.js +20 -6
  6. package/lib/happy-dom/selector-matcher.js +2 -2
  7. package/lib/happy-dom/selector-pseudo-adapter.js +33 -0
  8. package/lib/happy-dom/svg-attribute-adapter.js +50 -0
  9. package/lib/headless-shell.js +12 -6
  10. package/lib/input/hit-test.js +67 -19
  11. package/lib/layout/text-layout.js +289 -131
  12. package/lib/media/byte-pipe.js +2 -2
  13. package/lib/media/position-audio.js +10 -1
  14. package/lib/media/source-snapshots.js +126 -0
  15. package/lib/media/video-keyframe.js +42 -0
  16. package/lib/media/webm-stream.js +106 -0
  17. package/lib/network/network-service.js +268 -120
  18. package/lib/paint/display-list.js +22 -27
  19. package/lib/paint/frame-cache.js +25 -0
  20. package/lib/paint/frame.js +42 -13
  21. package/lib/paint/paragraph-text.js +24 -0
  22. package/lib/paint/raster-readback.js +41 -0
  23. package/lib/paint/rounded-rect.js +82 -0
  24. package/lib/paint/shared-frame-pool.js +105 -0
  25. package/lib/render-tree/index.js +40 -6
  26. package/lib/render-tree/svg.js +15 -7
  27. package/lib/renderer/bindings.js +244 -82
  28. package/lib/renderer/broadcast-channel.js +76 -0
  29. package/lib/renderer/canvas-2d.js +257 -14
  30. package/lib/renderer/canvas-text.js +120 -0
  31. package/lib/renderer/compositor.js +27 -10
  32. package/lib/renderer/custom-element-reactions.js +42 -0
  33. package/lib/renderer/font-loading.js +227 -0
  34. package/lib/renderer/history.js +42 -0
  35. package/lib/renderer/host.js +36 -5
  36. package/lib/renderer/image-loading.js +27 -0
  37. package/lib/renderer/image-resources.js +65 -0
  38. package/lib/renderer/interfaces.js +28 -0
  39. package/lib/renderer/keyboard-input.js +12 -0
  40. package/lib/renderer/layout-observers.js +236 -0
  41. package/lib/renderer/main.js +33 -5
  42. package/lib/renderer/media-playback-events.js +13 -0
  43. package/lib/renderer/media-source.js +126 -55
  44. package/lib/renderer/page-realm.js +278 -147
  45. package/lib/renderer/page-renderer.js +840 -301
  46. package/lib/renderer/piano-input.js +22 -0
  47. package/lib/renderer/pointer-move.js +29 -0
  48. package/lib/renderer/prepared-script-cache.js +50 -0
  49. package/lib/renderer/rendered-text.js +108 -0
  50. package/lib/renderer/rewrite-worker.js +4 -3
  51. package/lib/renderer/script-rewrite.js +13 -2
  52. package/lib/renderer/scroll-into-view.js +28 -0
  53. package/lib/renderer/slot-assignment.js +60 -0
  54. package/lib/renderer/video-presentation.js +145 -0
  55. package/lib/renderer/workers.js +2 -2
  56. package/lib/style/computed-style.js +632 -108
  57. package/lib/style/selector-traits.js +49 -5
  58. package/package.json +1 -1
  59. package/test/broadcast-channel.test.js +26 -0
  60. package/test/canvas-2d.test.js +83 -2
  61. package/test/canvas-paint.test.js +9 -0
  62. package/test/canvas-text.test.js +41 -0
  63. package/test/cdp-stream.test.js +56 -0
  64. package/test/compositor.test.js +38 -0
  65. package/test/computed-style-binding.test.js +151 -0
  66. package/test/computed-style.test.js +279 -1
  67. package/test/display-list.test.js +26 -0
  68. package/test/document-base.test.js +87 -0
  69. package/test/dom-platform.test.js +461 -0
  70. package/test/download.test.js +8 -0
  71. package/test/fetch-lifecycle.test.js +161 -0
  72. package/test/fixtures/canvas-paint.js +117 -0
  73. package/test/fixtures/canvas-text.js +42 -0
  74. package/test/fixtures/image-lifetime.js +90 -0
  75. package/test/fixtures/media-seek-snapshot.js +77 -0
  76. package/test/fixtures/mse-audio-chirp.webm +0 -0
  77. package/test/fixtures/mse-switch-large.mp4 +0 -0
  78. package/test/fixtures/mse-switch-small.mp4 +0 -0
  79. package/test/fixtures/renderer-memory.js +110 -0
  80. package/test/fixtures/summary-style.js +28 -0
  81. package/test/font-loading.test.js +97 -0
  82. package/test/grid.test.js +58 -0
  83. package/test/headless-shell.test.js +22 -0
  84. package/test/hit-test.test.js +21 -1
  85. package/test/image-lifetime.test.js +12 -0
  86. package/test/image-resources.test.js +94 -0
  87. package/test/local-media.test.js +84 -0
  88. package/test/media-playback-events.test.js +22 -0
  89. package/test/media-seek-snapshot.test.js +11 -0
  90. package/test/media-source-config.test.js +98 -0
  91. package/test/media-source-webm-accounting.test.js +98 -0
  92. package/test/media-source-webm.test.js +108 -0
  93. package/test/navigation.test.js +1 -0
  94. package/test/network-service.test.js +388 -0
  95. package/test/page-scripts.test.js +160 -2
  96. package/test/paint-frame.test.js +103 -0
  97. package/test/paint-paragraph-cache.test.js +87 -0
  98. package/test/piano-input.test.js +44 -0
  99. package/test/playback-buffer.test.js +31 -0
  100. package/test/position-audio.test.js +24 -0
  101. package/test/positioning.test.js +22 -0
  102. package/test/prepared-script-cache.test.js +45 -0
  103. package/test/pulse-client.test.js +27 -5
  104. package/test/raster-readback.test.js +40 -0
  105. package/test/render-tree.test.js +28 -0
  106. package/test/renderer-memory.test.js +11 -0
  107. package/test/selector-traits.test.js +24 -0
  108. package/test/shared-frame-pool.test.js +63 -0
  109. package/test/style-sheets.test.js +51 -0
  110. package/test/svg.test.js +29 -0
  111. package/test/text-layout.test.js +168 -0
  112. package/test/video-keyframe.test.js +61 -0
  113. package/test/video-presentation.test.js +136 -0
  114. package/tools/browser-lab.js +78 -0
  115. package/tools/browser-soak.js +75 -0
  116. package/tools/network-reference.js +49 -0
  117. package/tools/process-memory.js +38 -0
  118. package/tools/script-benchmark.js +25 -0
@@ -80,39 +80,82 @@ export function hitTest(tree, layout, x, y, scroll, viewport) {
80
80
  * pointer events. Null when the point hits nothing.
81
81
  */
82
82
  export function elementAtPoint(tree, displayList, x, y, scroll) {
83
+ const domNode = renderNodeAtPoint(tree, displayList, x, y, scroll)?.domNode;
84
+ return domNode?.nodeType === 1 ? domNode : domNode?.parentElement ?? null;
85
+ }
86
+
87
+ /** Also preserves generated controls, whose owning DOM element differs from their render node. */
88
+ export function renderNodeAtPoint(tree, displayList, x, y, scroll) {
83
89
  const hittable = hitTestable(tree);
84
90
  const nodeId = hitTarget(displayList, x, y, scroll, (id) => !hittable(tree.nodesById.get(id)));
85
- const domNode = nodeId == null ? null : tree.nodesById.get(nodeId)?.domNode;
86
- return domNode?.nodeType === 1 ? domNode : domNode?.parentElement ?? null;
91
+ return nodeId == null ? null : tree.nodesById.get(nodeId) ?? null;
87
92
  }
88
93
 
89
- /** Returns the content-coordinate bounds contributed by an element's text descendants. */
90
- export function elementBounds(tree, layout, element) {
91
- const rects = [];
94
+ // Layout objects are immutable after the layout pass. Keeping their lookup
95
+ // tables under a weak key releases old document nodes when a layout is dropped.
96
+ const geometryIndexes = new WeakMap();
97
+
98
+ function geometryIndex(tree, layout) {
99
+ let index = geometryIndexes.get(layout);
100
+ if (index?.tree === tree) return index;
101
+ const byNode = new Map(), boxes = new WeakMap();
102
+ for (const box of layout.boxes) if (!box.inline && !byNode.has(box.nodeId)) byNode.set(box.nodeId, box);
103
+ for (const node of tree.nodesById.values()) {
104
+ if (node.pseudo || node.domNode?.nodeType !== 1 || boxes.has(node.domNode)) continue;
105
+ // The first actual render node is authoritative, even if it is inline.
106
+ const box = byNode.get(node.id);
107
+ boxes.set(node.domNode, box ? { node, box } : null);
108
+ }
109
+ index = { tree, boxes, textBounds: null };
110
+ geometryIndexes.set(layout, index);
111
+ return index;
112
+ }
113
+
114
+ /** The first real render node and block box belonging to an element. */
115
+ export function elementBox(tree, layout, element) {
116
+ return tree && layout ? geometryIndex(tree, layout).boxes.get(element) ?? null : null;
117
+ }
118
+
119
+ function textBoundsIndex(tree, layout) {
120
+ const bounds = new WeakMap();
92
121
  for (const fragment of layout.fragments) {
93
122
  for (const run of fragment.runs) {
94
123
  const renderNode = tree.nodesById.get(run.nodeId);
95
124
  const owner = renderNode?.domNode?.nodeType === 1
96
125
  ? renderNode.domNode
97
126
  : renderNode?.domNode?.parentElement;
98
- if (!owner || (owner !== element && !element.contains(owner))) continue;
127
+ if (!owner) continue;
99
128
  // A replaced element (an image) spans its own box, not its line's height.
100
129
  const replaced = run.type === "image" && run.y != null;
101
130
  const top = replaced ? run.y : fragment.y;
102
- rects.push({
103
- left: run.x,
104
- top,
105
- right: run.x + run.width,
106
- bottom: top + (replaced ? run.height : fragment.height),
107
- });
131
+ const right = run.x + run.width;
132
+ const bottom = top + (replaced ? run.height : fragment.height);
133
+ for (let ancestor = owner; ancestor; ancestor = ancestor.parentElement) {
134
+ const rect = bounds.get(ancestor);
135
+ if (rect) {
136
+ rect.left = Math.min(rect.left, run.x);
137
+ rect.top = Math.min(rect.top, top);
138
+ rect.right = Math.max(rect.right, right);
139
+ rect.bottom = Math.max(rect.bottom, bottom);
140
+ } else bounds.set(ancestor, { left: run.x, top, right, bottom });
141
+ }
108
142
  }
109
143
  }
110
- if (!rects.length) return null;
111
- const left = Math.min(...rects.map((rect) => rect.left));
112
- const top = Math.min(...rects.map((rect) => rect.top));
113
- const right = Math.max(...rects.map((rect) => rect.right));
114
- const bottom = Math.max(...rects.map((rect) => rect.bottom));
115
- return Object.freeze({ left, top, right, bottom, width: right - left, height: bottom - top });
144
+ return bounds;
145
+ }
146
+
147
+ /** Returns the content-coordinate bounds contributed by an element's text descendants. */
148
+ export function elementBounds(tree, layout, element) {
149
+ const index = geometryIndex(tree, layout);
150
+ index.textBounds ??= textBoundsIndex(tree, layout);
151
+ const rect = index.textBounds.get(element);
152
+ if (!rect) return null;
153
+ if (rect.width === undefined) {
154
+ rect.width = rect.right - rect.left;
155
+ rect.height = rect.bottom - rect.top;
156
+ Object.freeze(rect);
157
+ }
158
+ return rect;
116
159
  }
117
160
 
118
161
  /**
@@ -120,19 +163,24 @@ export function elementBounds(tree, layout, element) {
120
163
  * visibility: hidden or pointer-events: none (both inherited, so a visible
121
164
  * or pointer-events: auto descendant still does). Text uses its element's style.
122
165
  */
166
+ const hitTestableIndexes = new WeakMap();
123
167
  function hitTestable(tree) {
168
+ const cached = hitTestableIndexes.get(tree);
169
+ if (cached) return cached;
124
170
  const styles = new Map();
125
171
  for (const node of tree.nodesById.values()) {
126
172
  if (node.domNode?.nodeType === 1 && node.style && !node.pseudo && !styles.has(node.domNode)) {
127
173
  styles.set(node.domNode, node.style);
128
174
  }
129
175
  }
130
- return (renderNode) => {
176
+ const accepts = (renderNode) => {
131
177
  const domNode = renderNode?.domNode;
132
178
  const element = domNode?.nodeType === 1 ? domNode : domNode?.parentElement;
133
179
  const style = (renderNode?.pseudo ? renderNode.style : null) ?? styles.get(element);
134
180
  return !style || (style.visibility !== "hidden" && style.pointerEvents !== "none");
135
181
  };
182
+ hitTestableIndexes.set(tree, accepts);
183
+ return accepts;
136
184
  }
137
185
 
138
186
  function closestInteractive(node) {