@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.
- package/dist/html/controls.d.ts +29 -2
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +70 -2
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +26 -4
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +18 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +27 -0
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/parse.d.ts +18 -4
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +66 -28
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +128 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +561 -144
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/transform.d.ts +85 -0
- package/dist/html/css/transform.d.ts.map +1 -0
- package/dist/html/css/transform.js +425 -0
- package/dist/html/css/transform.js.map +1 -0
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +14 -2
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +4 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/fonts.d.ts +55 -5
- package/dist/html/fonts.d.ts.map +1 -1
- package/dist/html/fonts.js +284 -23
- package/dist/html/fonts.js.map +1 -1
- package/dist/html/layout/axes.d.ts +14 -0
- package/dist/html/layout/axes.d.ts.map +1 -0
- package/dist/html/layout/axes.js +28 -0
- package/dist/html/layout/axes.js.map +1 -0
- package/dist/html/layout/block.d.ts +93 -12
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +389 -39
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +59 -1
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +22 -2
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +1 -1
- package/dist/html/layout/cache.d.ts.map +1 -1
- package/dist/html/layout/cache.js +6 -0
- package/dist/html/layout/cache.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +90 -18
- 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 +570 -83
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +3 -0
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +144 -54
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/multicol.d.ts +42 -0
- package/dist/html/layout/multicol.d.ts.map +1 -0
- package/dist/html/layout/multicol.js +897 -0
- package/dist/html/layout/multicol.js.map +1 -0
- package/dist/html/layout/shaping.d.ts +7 -0
- package/dist/html/layout/shaping.d.ts.map +1 -1
- package/dist/html/layout/shaping.js +25 -20
- package/dist/html/layout/shaping.js.map +1 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +62 -18
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +3 -0
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +263 -36
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +79 -4
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +1213 -141
- package/dist/html/paint.js.map +1 -1
- package/dist/html/svg.d.ts +15 -2
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +249 -17
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.js +87 -7
- package/dist/html/widgets.js.map +1 -1
- package/dist/html/woff2.d.ts +14 -0
- package/dist/html/woff2.d.ts.map +1 -0
- package/dist/html/woff2.js +608 -0
- package/dist/html/woff2.js.map +1 -0
- package/dist/maps/controller.d.ts +17 -1
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +27 -7
- package/dist/maps/controller.js.map +1 -1
- package/dist/richtext/node.d.ts +8 -1
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +5 -1
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +25 -6
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +240 -24
- package/dist/richtext/runs.js.map +1 -1
- package/package.json +1 -1
- package/src/html/controls.ts +85 -2
- package/src/html/css/cascade.ts +23 -0
- package/src/html/css/color.ts +29 -0
- package/src/html/css/parse.ts +71 -31
- package/src/html/css/style.ts +664 -147
- package/src/html/css/transform.ts +459 -0
- package/src/html/css/ua.ts +15 -2
- package/src/html/css/values.ts +4 -0
- package/src/html/fonts.ts +312 -29
- package/src/html/layout/axes.ts +62 -0
- package/src/html/layout/block.ts +444 -37
- package/src/html/layout/boxes.ts +65 -3
- package/src/html/layout/cache.ts +6 -0
- package/src/html/layout/css-grid.ts +95 -22
- package/src/html/layout/flex.ts +671 -77
- package/src/html/layout/inline.ts +149 -55
- package/src/html/layout/multicol.ts +977 -0
- package/src/html/layout/shaping.ts +27 -18
- package/src/html/layout/table.ts +62 -19
- package/src/html/node.ts +300 -37
- package/src/html/paint.ts +1406 -206
- package/src/html/svg.ts +277 -19
- package/src/html/widgets.ts +95 -9
- package/src/html/woff2.ts +612 -0
- package/src/maps/controller.ts +28 -7
- package/src/richtext/node.ts +13 -2
- package/src/richtext/runs.ts +313 -35
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
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
|
|
2594
|
-
const
|
|
2595
|
-
|
|
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 <
|
|
2601
|
-
x >=
|
|
2806
|
+
else if (x < left ||
|
|
2807
|
+
x >= left + across ||
|
|
2602
2808
|
y < reach ||
|
|
2603
|
-
y >= reach +
|
|
2809
|
+
y >= reach + down) {
|
|
2604
2810
|
return;
|
|
2605
2811
|
}
|
|
2606
|
-
if (clipsOverflow(child))
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
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
|
-
|
|
2656
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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. */
|