gesso-core 0.6.18 → 0.6.20
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/CHANGELOG.md +21 -0
- package/dist/{CanvasSurface-BSvtTgJZ.js → CanvasSurface-VUJRrcXl.js} +656 -91
- package/dist/CanvasSurface-VUJRrcXl.js.map +1 -0
- package/dist/{index-Bi5ggOnd.d.ts → index-lzNLHD-1.d.ts} +271 -29
- package/dist/index.d.ts +2 -2
- package/dist/index.js +250 -11
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- package/dist/CanvasSurface-BSvtTgJZ.js.map +0 -1
|
@@ -804,6 +804,10 @@ var DirtyNodeSet = class {
|
|
|
804
804
|
isEmpty() {
|
|
805
805
|
return this.nodes.size === 0;
|
|
806
806
|
}
|
|
807
|
+
/** The nodes in the set, without draining it. Not to be changed while walked. */
|
|
808
|
+
values() {
|
|
809
|
+
return this.nodes.values();
|
|
810
|
+
}
|
|
807
811
|
/**
|
|
808
812
|
* Whether any node in the set carries one of `flags`, without
|
|
809
813
|
* draining it.
|
|
@@ -3919,6 +3923,19 @@ const UiProperties = {
|
|
|
3919
3923
|
inherited: false,
|
|
3920
3924
|
affects: 6
|
|
3921
3925
|
}),
|
|
3926
|
+
/**
|
|
3927
|
+
* Whether a scroll container shows its overlay scrollbars: \`'auto'\`
|
|
3928
|
+
* (the default) while scrolling, \`'none'\` never, and then they cannot
|
|
3929
|
+
* be grabbed either. For a container scrolled by something else, as a
|
|
3930
|
+
* picture is moved inside a window onto it, where a bar would claim
|
|
3931
|
+
* the person could scroll it.
|
|
3932
|
+
*/
|
|
3933
|
+
scrollbars: defineProperty({
|
|
3934
|
+
name: "scrollbars",
|
|
3935
|
+
defaultValue: void 0,
|
|
3936
|
+
inherited: false,
|
|
3937
|
+
affects: 6
|
|
3938
|
+
}),
|
|
3922
3939
|
inset: defineProperty({
|
|
3923
3940
|
name: "inset",
|
|
3924
3941
|
defaultValue: void 0,
|
|
@@ -5161,6 +5178,36 @@ var UiGraph = class {
|
|
|
5161
5178
|
this.nodeRemovedListener?.(node);
|
|
5162
5179
|
for (let i = removed.length - 1; i > 0; i--) this.detachNode(removed[i]);
|
|
5163
5180
|
}
|
|
5181
|
+
/**
|
|
5182
|
+
* Moves a child before \`reference\` among its own siblings, or to the
|
|
5183
|
+
* end when that is null. Its parent is unchanged, and so is everything
|
|
5184
|
+
* it inherits, so its subtree is not visited: a lazy list recycling its
|
|
5185
|
+
* rows moves one from end to end on every frame of a scroll, and
|
|
5186
|
+
* re-inheriting walked the whole row each time.
|
|
5187
|
+
*/
|
|
5188
|
+
moveWithin(child, reference) {
|
|
5189
|
+
const parent = child.parent;
|
|
5190
|
+
if (parent === null) throw new Error(`Node '${child.id}' has no parent to move within.`);
|
|
5191
|
+
if (reference !== null && reference.parent !== parent) throw new Error(`Reference node '${reference.id}' is not a sibling of '${child.id}'.`);
|
|
5192
|
+
if (child === reference || child.nextSibling === reference) return;
|
|
5193
|
+
this.detachNode(child);
|
|
5194
|
+
parent.childOrderVersion++;
|
|
5195
|
+
child.parent = parent;
|
|
5196
|
+
if (reference === null) {
|
|
5197
|
+
const last = parent.lastChild;
|
|
5198
|
+
child.previousSibling = last;
|
|
5199
|
+
if (last !== null) last.nextSibling = child;
|
|
5200
|
+
else parent.firstChild = child;
|
|
5201
|
+
parent.lastChild = child;
|
|
5202
|
+
return;
|
|
5203
|
+
}
|
|
5204
|
+
const previous = reference.previousSibling;
|
|
5205
|
+
if (previous !== null) previous.nextSibling = child;
|
|
5206
|
+
else parent.firstChild = child;
|
|
5207
|
+
child.previousSibling = previous;
|
|
5208
|
+
child.nextSibling = reference;
|
|
5209
|
+
reference.previousSibling = child;
|
|
5210
|
+
}
|
|
5164
5211
|
detachNode(node) {
|
|
5165
5212
|
const parent = node.parent;
|
|
5166
5213
|
if (!parent) return;
|
|
@@ -7707,9 +7754,14 @@ function linkRunAtPointIn(geometry, x, y) {
|
|
|
7707
7754
|
* testing. This is the same shape as the CSS
|
|
7708
7755
|
* `inert` attribute: a disabled Button stays
|
|
7709
7756
|
* inert even when it wraps Text children.
|
|
7710
|
-
* pointerEvents — 'none' makes the node
|
|
7711
|
-
* by hit testing
|
|
7712
|
-
*
|
|
7757
|
+
* pointerEvents — inherited, as in CSS: 'none' makes the node and
|
|
7758
|
+
* its subtree skipped by hit testing, except where
|
|
7759
|
+
* a descendant sets 'auto', which takes presses
|
|
7760
|
+
* again. An overlay that lets presses through to
|
|
7761
|
+
* what is under it, with popups on it that take
|
|
7762
|
+
* them, is 'none' with 'auto' on each popup.
|
|
7763
|
+
* 'none' on the node itself also keeps it from
|
|
7764
|
+
* focus and keyboard, as before.
|
|
7713
7765
|
* hitTestable — false skips only the node itself; children are
|
|
7714
7766
|
* still tested. Use it for decorative containers
|
|
7715
7767
|
* that must not swallow clicks.
|
|
@@ -7721,13 +7773,29 @@ function linkRunAtPointIn(geometry, x, y) {
|
|
|
7721
7773
|
*/
|
|
7722
7774
|
/** The node and its whole subtree are excluded from pointer input. */
|
|
7723
7775
|
function isNodeInert(node) {
|
|
7724
|
-
if (node.properties.get("disabled") === true) return true;
|
|
7725
7776
|
if (node.properties.get("pointerEvents") === "none") return true;
|
|
7777
|
+
return isSubtreeInert(node);
|
|
7778
|
+
}
|
|
7779
|
+
/**
|
|
7780
|
+
* Disabled or hidden: the node and everything under it, with no way
|
|
7781
|
+
* back for a descendant. `pointerEvents: 'none'` is not this, since a
|
|
7782
|
+
* descendant can set 'auto'; the hit tester follows that itself.
|
|
7783
|
+
*/
|
|
7784
|
+
function isSubtreeInert(node) {
|
|
7785
|
+
if (node.properties.get("disabled") === true) return true;
|
|
7726
7786
|
if (node.properties.get("visible") === false) return true;
|
|
7727
7787
|
const opacity = node.properties.get("opacity");
|
|
7728
7788
|
if (typeof opacity === "number" && Number.isFinite(opacity) && opacity <= 0) return true;
|
|
7729
7789
|
return false;
|
|
7730
7790
|
}
|
|
7791
|
+
/** `pointerEvents` as CSS inherits it: the nearest value set from the node up, 'auto' when none is. */
|
|
7792
|
+
function pointerEventsOf(node) {
|
|
7793
|
+
for (let current = node; current !== null; current = current.parent) {
|
|
7794
|
+
const value = current.properties.get("pointerEvents");
|
|
7795
|
+
if (value === "auto" || value === "none") return value;
|
|
7796
|
+
}
|
|
7797
|
+
return "auto";
|
|
7798
|
+
}
|
|
7731
7799
|
/** The node itself cannot be the target of a hit, but children can. */
|
|
7732
7800
|
function isNodeHitTestable(node) {
|
|
7733
7801
|
return node.properties.get("hitTestable") !== false;
|
|
@@ -9358,6 +9426,7 @@ function scrollbarThumb(rec, axis) {
|
|
|
9358
9426
|
return thumbFor(rec, axis);
|
|
9359
9427
|
}
|
|
9360
9428
|
function thumbFor(rec, axis) {
|
|
9429
|
+
if (rec.hidesScrollbars) return null;
|
|
9361
9430
|
const viewport = axis === "y" ? rec.height : rec.width;
|
|
9362
9431
|
const content = axis === "y" ? rec.contentHeight : rec.contentWidth;
|
|
9363
9432
|
if (!(content > viewport) || viewport <= 0) return null;
|
|
@@ -9473,6 +9542,13 @@ var UiHitTester = class {
|
|
|
9473
9542
|
liftedScratch = [];
|
|
9474
9543
|
/** True while testing inside a lifted subtree, so it is not skipped again. */
|
|
9475
9544
|
inLifted = false;
|
|
9545
|
+
/**
|
|
9546
|
+
* `pointerEvents` as the node being tested has it, inherited: true
|
|
9547
|
+
* under a 'none' that nothing nearer has set back to 'auto'. Such a
|
|
9548
|
+
* node is passed over, but its children are still tested, since one
|
|
9549
|
+
* of them may say 'auto'.
|
|
9550
|
+
*/
|
|
9551
|
+
pointerNone = false;
|
|
9476
9552
|
constructor(layout, root) {
|
|
9477
9553
|
this.layout = layout;
|
|
9478
9554
|
this.root = root;
|
|
@@ -9507,7 +9583,9 @@ var UiHitTester = class {
|
|
|
9507
9583
|
const out = [];
|
|
9508
9584
|
this.forEachLifted(x, y, (node, px, py) => {
|
|
9509
9585
|
this.inLifted = true;
|
|
9586
|
+
this.pointerNone = pointerEventsOf(node.parent) === "none";
|
|
9510
9587
|
this.collectNode(node, px, py, out);
|
|
9588
|
+
this.pointerNone = false;
|
|
9511
9589
|
this.inLifted = false;
|
|
9512
9590
|
return false;
|
|
9513
9591
|
});
|
|
@@ -9515,7 +9593,16 @@ var UiHitTester = class {
|
|
|
9515
9593
|
return out;
|
|
9516
9594
|
}
|
|
9517
9595
|
collectNode(node, x, y, out) {
|
|
9518
|
-
if (
|
|
9596
|
+
if (isSubtreeInert(node)) return;
|
|
9597
|
+
const outer = this.pointerNone;
|
|
9598
|
+
this.pointerNone = this.inheritsNone(node, outer);
|
|
9599
|
+
try {
|
|
9600
|
+
this.collectOwn(node, x, y, out);
|
|
9601
|
+
} finally {
|
|
9602
|
+
this.pointerNone = outer;
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
collectOwn(node, x, y, out) {
|
|
9519
9606
|
const rec = this.layout.recordFor(node);
|
|
9520
9607
|
if (rec === void 0 || !this.invertPoint(node, rec, x, y)) return;
|
|
9521
9608
|
if (rec.lifted && !this.inLifted) return;
|
|
@@ -9526,7 +9613,7 @@ var UiHitTester = class {
|
|
|
9526
9613
|
const shiftX = rec.clips && rec.scrollable ? rec.scrollX : 0;
|
|
9527
9614
|
const shiftY = rec.clips && rec.scrollable ? rec.scrollY : 0;
|
|
9528
9615
|
this.collectChildren(node, px + shiftX, py + shiftY, out);
|
|
9529
|
-
if (inside &&
|
|
9616
|
+
if (inside && this.targetable(node)) out.push(node);
|
|
9530
9617
|
}
|
|
9531
9618
|
collectChildren(parent, x, y, out) {
|
|
9532
9619
|
const order = this.layout.recordFor(parent)?.paintOrder;
|
|
@@ -9609,7 +9696,9 @@ var UiHitTester = class {
|
|
|
9609
9696
|
hitTestLifted(x, y) {
|
|
9610
9697
|
return this.forEachLifted(x, y, (node, px, py) => {
|
|
9611
9698
|
this.inLifted = true;
|
|
9699
|
+
this.pointerNone = pointerEventsOf(node.parent) === "none";
|
|
9612
9700
|
const hit = this.hitTestNode(node, px, py);
|
|
9701
|
+
this.pointerNone = false;
|
|
9613
9702
|
this.inLifted = false;
|
|
9614
9703
|
return hit;
|
|
9615
9704
|
});
|
|
@@ -9675,7 +9764,25 @@ var UiHitTester = class {
|
|
|
9675
9764
|
this.point.y = py;
|
|
9676
9765
|
}
|
|
9677
9766
|
hitTestNode(node, x, y) {
|
|
9678
|
-
if (
|
|
9767
|
+
if (isSubtreeInert(node)) return false;
|
|
9768
|
+
const outer = this.pointerNone;
|
|
9769
|
+
this.pointerNone = this.inheritsNone(node, outer);
|
|
9770
|
+
try {
|
|
9771
|
+
return this.hitTestOwn(node, x, y);
|
|
9772
|
+
} finally {
|
|
9773
|
+
this.pointerNone = outer;
|
|
9774
|
+
}
|
|
9775
|
+
}
|
|
9776
|
+
/** Whether a node is under a 'none': its own value, else its parent's. */
|
|
9777
|
+
inheritsNone(node, parentNone) {
|
|
9778
|
+
const own = node.properties.get("pointerEvents");
|
|
9779
|
+
return own === "none" ? true : own === "auto" ? false : parentNone;
|
|
9780
|
+
}
|
|
9781
|
+
/** Whether a press may land on the node itself. */
|
|
9782
|
+
targetable(node) {
|
|
9783
|
+
return !this.pointerNone && isNodeHitTestable(node);
|
|
9784
|
+
}
|
|
9785
|
+
hitTestOwn(node, x, y) {
|
|
9679
9786
|
const rec = this.layout.recordFor(node);
|
|
9680
9787
|
if (rec === void 0) return false;
|
|
9681
9788
|
if (rec.lifted && !this.inLifted) return false;
|
|
@@ -9684,7 +9791,7 @@ var UiHitTester = class {
|
|
|
9684
9791
|
const py = this.point.y - rec.stickyOffsetY;
|
|
9685
9792
|
if (rec.clips) {
|
|
9686
9793
|
if (px < rec.x || px >= rec.x + rec.width || py < rec.y || py >= rec.y + rec.height) return false;
|
|
9687
|
-
if ((rec.scrollable || rec.textScrollbars) && scrollLeaderOf(node) === null && this.hitScrollbar(node, rec, px, py)) return true;
|
|
9794
|
+
if (!this.pointerNone && (rec.scrollable || rec.textScrollbars) && scrollLeaderOf(node) === null && this.hitScrollbar(node, rec, px, py)) return true;
|
|
9688
9795
|
if (this.zoneOnly) {
|
|
9689
9796
|
const shiftX = rec.scrollX;
|
|
9690
9797
|
const shiftY = rec.scrollY;
|
|
@@ -9693,10 +9800,10 @@ var UiHitTester = class {
|
|
|
9693
9800
|
const shiftX = rec.scrollable ? rec.scrollX : 0;
|
|
9694
9801
|
const shiftY = rec.scrollable ? rec.scrollY : 0;
|
|
9695
9802
|
if (this.hitTestChildren(node, px + shiftX, py + shiftY)) return true;
|
|
9696
|
-
return
|
|
9803
|
+
return this.targetable(node) && this.recordHit(node, rec, px, py);
|
|
9697
9804
|
}
|
|
9698
9805
|
if (this.hitTestChildren(node, px, py)) return true;
|
|
9699
|
-
if (this.zoneOnly || !
|
|
9806
|
+
if (this.zoneOnly || !this.targetable(node)) return false;
|
|
9700
9807
|
if (px < rec.x || px >= rec.x + rec.width || py < rec.y || py >= rec.y + rec.height) return false;
|
|
9701
9808
|
return this.recordHit(node, rec, px, py);
|
|
9702
9809
|
}
|
|
@@ -10871,6 +10978,11 @@ var UiWheelController = class {
|
|
|
10871
10978
|
* wheel of a burst land correctly even though the first could not.
|
|
10872
10979
|
*/
|
|
10873
10980
|
lastWheelTarget = null;
|
|
10981
|
+
/**
|
|
10982
|
+
* The container the wheel last scrolled, for a frame's report of where
|
|
10983
|
+
* scrolling put it. Null until the wheel has scrolled something.
|
|
10984
|
+
*/
|
|
10985
|
+
lastScrolled = null;
|
|
10874
10986
|
wheel(x, y, deltaX, deltaY, modifiers = noKeyModifiers(), deltaMode = 0, wheelDeltaY, at) {
|
|
10875
10987
|
const target = this.hitTester.hitTest(x, y)?.node ?? null;
|
|
10876
10988
|
this.lastWheelTarget = target;
|
|
@@ -11023,7 +11135,8 @@ var UiWheelController = class {
|
|
|
11023
11135
|
dirX: 0,
|
|
11024
11136
|
dirY: 0,
|
|
11025
11137
|
quiet: 0,
|
|
11026
|
-
fresh: false
|
|
11138
|
+
fresh: false,
|
|
11139
|
+
fitted: false
|
|
11027
11140
|
};
|
|
11028
11141
|
this.pacing.set(container, paced);
|
|
11029
11142
|
}
|
|
@@ -11039,9 +11152,11 @@ var UiWheelController = class {
|
|
|
11039
11152
|
});
|
|
11040
11153
|
while (paced.samples.length > 2 && paced.samples[0].t < this.eventTime - VELOCITY_WINDOW_MS) paced.samples.shift();
|
|
11041
11154
|
this.scrollSink.scrollBy(container, 0, 0, "instant");
|
|
11155
|
+
this.lastScrolled = container;
|
|
11042
11156
|
return;
|
|
11043
11157
|
}
|
|
11044
11158
|
this.scrollSink.scrollBy(container, dx, dy, behavior);
|
|
11159
|
+
this.lastScrolled = container;
|
|
11045
11160
|
}
|
|
11046
11161
|
/**
|
|
11047
11162
|
* A container's state as a step should judge it: during a paced gesture,
|
|
@@ -11069,16 +11184,15 @@ var UiWheelController = class {
|
|
|
11069
11184
|
* comes a varying time after the last step: applied as they arrive, a
|
|
11070
11185
|
* steady flick moves the page by uneven amounts, which reads as
|
|
11071
11186
|
* judder. Evening that out by waiting for steps puts the page behind
|
|
11072
|
-
* the hand. So this does what a browser does for its own scrolling:
|
|
11073
|
-
*
|
|
11074
|
-
*
|
|
11075
|
-
*
|
|
11076
|
-
* even, and nothing trails.
|
|
11187
|
+
* the hand. So this does what a browser does for its own scrolling: it
|
|
11188
|
+
* resamples the steps at the frame's time, reading a line fitted through
|
|
11189
|
+
* the last `VELOCITY_WINDOW_MS` of them. Frames come out even, and
|
|
11190
|
+
* nothing trails.
|
|
11077
11191
|
*
|
|
11078
|
-
* A gesture's first step, with no
|
|
11079
|
-
* steps stop, the
|
|
11080
|
-
*
|
|
11081
|
-
*
|
|
11192
|
+
* A gesture's first step, with no line yet, goes as it is. Once the
|
|
11193
|
+
* steps stop, the page eases over a few frames to exactly where they add
|
|
11194
|
+
* up to; a trackpad's momentum slows to nothing first, so there is next
|
|
11195
|
+
* to nothing to take up.
|
|
11082
11196
|
*
|
|
11083
11197
|
* True while a gesture is still being paced, so the host keeps frames
|
|
11084
11198
|
* coming until it has settled.
|
|
@@ -11098,14 +11212,38 @@ var UiWheelController = class {
|
|
|
11098
11212
|
let y = paced.totalY;
|
|
11099
11213
|
const samples = paced.samples;
|
|
11100
11214
|
const last = samples[samples.length - 1];
|
|
11101
|
-
|
|
11102
|
-
for (let k = samples.length - 2; k >= 0 && last !== void 0 && samples[k].t >= last.t - RECENT_MS; k--) first = samples[k];
|
|
11215
|
+
const first = samples[0];
|
|
11103
11216
|
const since = time === void 0 || last === void 0 ? -1 : time - last.t;
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11217
|
+
const at = time === void 0 ? void 0 : time - RESAMPLE_MS;
|
|
11218
|
+
if (at !== void 0 && last !== void 0 && first !== void 0 && since >= -1 && at - last.t < STALE_MS && samples.length >= MIN_FIT_STEPS && last.t - first.t >= 2) {
|
|
11219
|
+
let meanT = 0;
|
|
11220
|
+
let meanX = 0;
|
|
11221
|
+
let meanY = 0;
|
|
11222
|
+
for (const sample of samples) {
|
|
11223
|
+
meanT += sample.t;
|
|
11224
|
+
meanX += sample.x;
|
|
11225
|
+
meanY += sample.y;
|
|
11226
|
+
}
|
|
11227
|
+
meanT /= samples.length;
|
|
11228
|
+
meanX /= samples.length;
|
|
11229
|
+
meanY /= samples.length;
|
|
11230
|
+
let varT = 0;
|
|
11231
|
+
let covX = 0;
|
|
11232
|
+
let covY = 0;
|
|
11233
|
+
for (const sample of samples) {
|
|
11234
|
+
const dt = sample.t - meanT;
|
|
11235
|
+
varT += dt * dt;
|
|
11236
|
+
covX += dt * (sample.x - meanX);
|
|
11237
|
+
covY += dt * (sample.y - meanY);
|
|
11238
|
+
}
|
|
11239
|
+
x = meanX + covX / varT * (at - meanT);
|
|
11240
|
+
y = meanY + covY / varT * (at - meanT);
|
|
11241
|
+
paced.fitted = true;
|
|
11242
|
+
} else if (paced.fitted) {
|
|
11243
|
+
const drawnX = paced.lastX - paced.baseX;
|
|
11244
|
+
const drawnY = paced.lastY - paced.baseY;
|
|
11245
|
+
x = Math.abs(x - drawnX) < SETTLED_PX ? x : drawnX + (x - drawnX) * SETTLE_RATE;
|
|
11246
|
+
y = Math.abs(y - drawnY) < SETTLED_PX ? y : drawnY + (y - drawnY) * SETTLE_RATE;
|
|
11109
11247
|
}
|
|
11110
11248
|
const state = this.scrollSink.containerState(container);
|
|
11111
11249
|
if (state === void 0) {
|
|
@@ -11131,7 +11269,7 @@ var UiWheelController = class {
|
|
|
11131
11269
|
if (dx !== 0 || dy !== 0) this.scrollSink.scrollBy(container, dx, dy, "instant");
|
|
11132
11270
|
paced.lastX = toX;
|
|
11133
11271
|
paced.lastY = toY;
|
|
11134
|
-
if (toX === Math.min(Math.max(paced.baseX + paced.totalX, 0), state.maxScrollX) && toY === Math.min(Math.max(paced.baseY + paced.totalY, 0), state.maxScrollY) && paced.quiet >= QUIET_FRAMES) this.pacing.delete(container);
|
|
11272
|
+
if (toX === Math.min(Math.max(paced.baseX + paced.totalX, 0), state.maxScrollX) && toY === Math.min(Math.max(paced.baseY + paced.totalY, 0), state.maxScrollY) && paced.quiet >= QUIET_FRAMES && (since < 0 || since >= STALE_MS)) this.pacing.delete(container);
|
|
11135
11273
|
}
|
|
11136
11274
|
return this.pacing.size > 0;
|
|
11137
11275
|
}
|
|
@@ -11185,18 +11323,29 @@ function isScrollContainer(node) {
|
|
|
11185
11323
|
* hand from a trackpad to a mouse.
|
|
11186
11324
|
*/
|
|
11187
11325
|
const PRECISE_MEMORY_MS = 400;
|
|
11188
|
-
/** How far back the velocity is read: a few of a trackpad's steps. */
|
|
11189
|
-
const VELOCITY_WINDOW_MS = 40;
|
|
11190
|
-
/** How long after the last step its velocity is still trusted. */
|
|
11191
|
-
const STALE_MS = 40;
|
|
11192
11326
|
/**
|
|
11193
|
-
*
|
|
11194
|
-
*
|
|
11195
|
-
*
|
|
11327
|
+
* How far back the steps are fitted: five or six of a trackpad's. Less, and
|
|
11328
|
+
* the line follows each step's rounding; more, and it lags a flick that is
|
|
11329
|
+
* speeding up or slowing down. Measured on a real flick on a Mac, 48 ms left
|
|
11330
|
+
* a sixth of the frame-to-frame variation of the last-few-steps velocity,
|
|
11331
|
+
* with no frame standing still and the page no further behind the hand.
|
|
11196
11332
|
*/
|
|
11197
|
-
const
|
|
11198
|
-
/** How
|
|
11199
|
-
const
|
|
11333
|
+
const VELOCITY_WINDOW_MS = 48;
|
|
11334
|
+
/** How long after the last step its line is still trusted. */
|
|
11335
|
+
const STALE_MS = 40;
|
|
11336
|
+
/**
|
|
11337
|
+
* How long before the frame the line is read. Each millisecond is one more
|
|
11338
|
+
* of lag and less of a guess: measured on recorded flicks, 12 left the
|
|
11339
|
+
* worst frames a third as uneven as reading at the frame, and the page
|
|
11340
|
+
* about 11 ms behind the hand, against 15 for steps applied as they come.
|
|
11341
|
+
*/
|
|
11342
|
+
const RESAMPLE_MS = 12;
|
|
11343
|
+
/** Steps a line is fitted through: two are a line through their rounding. */
|
|
11344
|
+
const MIN_FIT_STEPS = 3;
|
|
11345
|
+
/** How much of the way to where the steps add up to a frame goes once they stop. */
|
|
11346
|
+
const SETTLE_RATE = .35;
|
|
11347
|
+
/** Close enough to where the steps add up to, to go the rest at once. */
|
|
11348
|
+
const SETTLED_PX = .25;
|
|
11200
11349
|
/** The display's interval before one has been measured. */
|
|
11201
11350
|
const DEFAULT_FRAME_MS = 1e3 / 60;
|
|
11202
11351
|
/** Quiet frames, once settled, after which a gesture is over. */
|
|
@@ -13926,6 +14075,8 @@ var LayoutRecord = class {
|
|
|
13926
14075
|
* multiline, the overlay scrollbars.
|
|
13927
14076
|
*/
|
|
13928
14077
|
scrollsText = false;
|
|
14078
|
+
/** A scroll container set to show no scrollbars (\`scrollbars: 'none'\`). */
|
|
14079
|
+
hidesScrollbars = false;
|
|
13929
14080
|
/**
|
|
13930
14081
|
* A multiline editable, which shows the overlay scrollbars a scroll
|
|
13931
14082
|
* container does over its own text. A single-line field scrolls
|
|
@@ -14188,6 +14339,7 @@ var LayoutRecord = class {
|
|
|
14188
14339
|
this.paintReachBottom = 0;
|
|
14189
14340
|
this.scrollable = false;
|
|
14190
14341
|
this.scrollsText = false;
|
|
14342
|
+
this.hidesScrollbars = false;
|
|
14191
14343
|
this.textScrollbars = false;
|
|
14192
14344
|
this.mirrored = false;
|
|
14193
14345
|
this.sticky = false;
|
|
@@ -18207,6 +18359,7 @@ var LayoutEngine = class {
|
|
|
18207
18359
|
const overflow = props.get("overflow");
|
|
18208
18360
|
rec.scrollable = node.type === "scroll-view" || overflow === "scroll" || overflow === "auto" || overflow === "hidden" && scrollLeaderOf(node) !== null;
|
|
18209
18361
|
rec.scrollsText = node.type === "editable-text";
|
|
18362
|
+
rec.hidesScrollbars = props.get("scrollbars") === "none";
|
|
18210
18363
|
rec.textScrollbars = rec.scrollsText && props.get("multiline") === true;
|
|
18211
18364
|
rec.mirrored = (rec.scrollable || rec.textScrollbars) && this.startEdge(node) === "right";
|
|
18212
18365
|
rec.clips = rec.scrollable || overflow === "hidden" || node.type === "editable-text";
|
|
@@ -20382,15 +20535,10 @@ var ScrollLayerCache = class {
|
|
|
20382
20535
|
* is how every one of those ends.
|
|
20383
20536
|
*/
|
|
20384
20537
|
refused = /* @__PURE__ */ new Set();
|
|
20385
|
-
geometryVersion = NaN;
|
|
20386
20538
|
dpr = 0;
|
|
20387
20539
|
surfaceWidth = 0;
|
|
20388
20540
|
surfaceHeight = 0;
|
|
20389
20541
|
frame = null;
|
|
20390
|
-
/** Whether this frame changed nothing a layer could not absorb: no layout, children, content or environment. */
|
|
20391
|
-
calm = false;
|
|
20392
|
-
/** Nodes this frame dirtied, and every ancestor of each, less a container that only scrolled. */
|
|
20393
|
-
disturbed = /* @__PURE__ */ new Set();
|
|
20394
20542
|
/** Consecutive frames each container without a layer has scrolled quietly. See `SCROLL_LAYER_SETTLE_FRAMES`. */
|
|
20395
20543
|
streaks = /* @__PURE__ */ new WeakMap();
|
|
20396
20544
|
/**
|
|
@@ -20422,46 +20570,26 @@ var ScrollLayerCache = class {
|
|
|
20422
20570
|
/**
|
|
20423
20571
|
* Settles which layers this frame's changes leave standing, before
|
|
20424
20572
|
* anything is drawn. Every rule here drops; none keeps. A frame the
|
|
20425
|
-
* caller could not vouch for drops them all.
|
|
20573
|
+
* caller could not vouch for drops them all. What changed inside a
|
|
20574
|
+
* container is not settled here but drawn over: see \`damage\`.
|
|
20426
20575
|
*/
|
|
20427
20576
|
beginFrame(changes, dpr, surfaceWidth, surfaceHeight) {
|
|
20428
20577
|
const interrupted = this.open;
|
|
20429
20578
|
this.open = true;
|
|
20430
|
-
this.
|
|
20431
|
-
this.calm = changes !== void 0;
|
|
20432
|
-
for (const [node, flags] of changes?.frame.entries() ?? []) {
|
|
20433
|
-
if ((flags & -355) !== 0) {
|
|
20434
|
-
this.calm = false;
|
|
20435
|
-
break;
|
|
20436
|
-
}
|
|
20437
|
-
for (let current = (flags & 32) !== 0 ? node.parent : node; current !== null; current = current.parent) this.disturbed.add(current);
|
|
20438
|
-
}
|
|
20439
|
-
if (interrupted || changes === void 0 || dpr !== this.dpr || surfaceWidth !== this.surfaceWidth || surfaceHeight !== this.surfaceHeight || changes.geometryVersion !== this.geometryVersion) {
|
|
20579
|
+
if (interrupted || changes === void 0 || dpr !== this.dpr || surfaceWidth !== this.surfaceWidth || surfaceHeight !== this.surfaceHeight) {
|
|
20440
20580
|
this.dropAll();
|
|
20441
20581
|
this.dpr = dpr;
|
|
20442
20582
|
this.surfaceWidth = surfaceWidth;
|
|
20443
20583
|
this.surfaceHeight = surfaceHeight;
|
|
20444
|
-
this.geometryVersion = changes?.geometryVersion ?? NaN;
|
|
20445
20584
|
this.frame = changes?.frame ?? null;
|
|
20446
20585
|
return;
|
|
20447
20586
|
}
|
|
20448
20587
|
const frame = changes.frame;
|
|
20449
20588
|
this.frame = frame;
|
|
20450
|
-
|
|
20589
|
+
for (const node of this.layers.keys()) if (dirtyAbove(frame, node)) this.forget(node);
|
|
20451
20590
|
for (const [node, flags] of frame.entries()) {
|
|
20452
|
-
if (
|
|
20453
|
-
|
|
20454
|
-
return;
|
|
20455
|
-
}
|
|
20456
|
-
const scrolledOnly = flags === 32;
|
|
20457
|
-
for (let current = scrolledOnly ? node.parent : node; current !== null; current = current.parent) this.forget(current);
|
|
20458
|
-
}
|
|
20459
|
-
for (const node of [...this.layers.keys(), ...this.refused]) for (let ancestor = node.parent; ancestor !== null; ancestor = ancestor.parent) {
|
|
20460
|
-
const flags = frame.dirtyFlagsFor(ancestor);
|
|
20461
|
-
if (flags !== 0 && flags !== 32) {
|
|
20462
|
-
this.forget(node);
|
|
20463
|
-
break;
|
|
20464
|
-
}
|
|
20591
|
+
if (flags === 32) continue;
|
|
20592
|
+
for (const refused of this.refused) if (node === refused || contains(node, refused) || contains(refused, node)) this.refused.delete(refused);
|
|
20465
20593
|
}
|
|
20466
20594
|
}
|
|
20467
20595
|
/** Drops the layers the frame did not composite: their container was culled, removed, or drawn directly. */
|
|
@@ -20475,14 +20603,16 @@ var ScrollLayerCache = class {
|
|
|
20475
20603
|
}
|
|
20476
20604
|
/**
|
|
20477
20605
|
* Whether a container with no layer should get one now: it has
|
|
20478
|
-
* scrolled on the last few frames running with nothing
|
|
20479
|
-
*
|
|
20480
|
-
*
|
|
20606
|
+
* scrolled on the last few frames running with nothing above it
|
|
20607
|
+
* changing, which is the evidence a layer would be kept, and it has
|
|
20608
|
+
* not just shown it holds something a layer cannot. What changes
|
|
20609
|
+
* inside it is absorbed item by item (see \`damage\`), so a lazy list
|
|
20610
|
+
* mounting rows as it scrolls keeps its layer.
|
|
20481
20611
|
*/
|
|
20482
20612
|
wants(node) {
|
|
20483
20613
|
const frame = this.frame;
|
|
20484
20614
|
if (frame === null || this.layers.size >= MAX_LAYERS || this.refused.has(node)) return false;
|
|
20485
|
-
if (
|
|
20615
|
+
if (dirtyAbove(frame, node)) {
|
|
20486
20616
|
this.streaks.delete(node);
|
|
20487
20617
|
return false;
|
|
20488
20618
|
}
|
|
@@ -20512,9 +20642,10 @@ var ScrollLayerCache = class {
|
|
|
20512
20642
|
offsetX: placement.offsetX,
|
|
20513
20643
|
offsetY: placement.offsetY,
|
|
20514
20644
|
dpr: this.dpr,
|
|
20515
|
-
scrollX: rec.scrollX,
|
|
20516
|
-
scrollY: rec.scrollY,
|
|
20517
|
-
used: true
|
|
20645
|
+
scrollX: snapScroll(rec.scrollX, this.dpr),
|
|
20646
|
+
scrollY: snapScroll(rec.scrollY, this.dpr),
|
|
20647
|
+
used: true,
|
|
20648
|
+
items: /* @__PURE__ */ new Map()
|
|
20518
20649
|
};
|
|
20519
20650
|
this.layers.set(node, layer);
|
|
20520
20651
|
this.stats.built++;
|
|
@@ -20535,8 +20666,8 @@ var ScrollLayerCache = class {
|
|
|
20535
20666
|
* device pixels, which a copy cannot follow without resampling.
|
|
20536
20667
|
*/
|
|
20537
20668
|
shift(layer, rec) {
|
|
20538
|
-
const exactX = (layer.scrollX - rec.scrollX) * layer.dpr;
|
|
20539
|
-
const exactY = (layer.scrollY - rec.scrollY) * layer.dpr;
|
|
20669
|
+
const exactX = (layer.scrollX - snapScroll(rec.scrollX, layer.dpr)) * layer.dpr;
|
|
20670
|
+
const exactY = (layer.scrollY - snapScroll(rec.scrollY, layer.dpr)) * layer.dpr;
|
|
20540
20671
|
const dx = Math.round(exactX);
|
|
20541
20672
|
const dy = Math.round(exactY);
|
|
20542
20673
|
if (Math.abs(exactX - dx) > EPSILON || Math.abs(exactY - dy) > EPSILON) return null;
|
|
@@ -20574,6 +20705,79 @@ var ScrollLayerCache = class {
|
|
|
20574
20705
|
});
|
|
20575
20706
|
return strips;
|
|
20576
20707
|
}
|
|
20708
|
+
/**
|
|
20709
|
+
* The parts of a layer this frame's changes inside the container left
|
|
20710
|
+
* wrong, in the layer's pixels, or \`'all'\` when that is most of it.
|
|
20711
|
+
* Called after \`shift\`, so the layer's offset is the frame's.
|
|
20712
|
+
*
|
|
20713
|
+
* Judged item by item, an item being one of the container's children
|
|
20714
|
+
* (through any fragments): a lazy list's row, say. An item added,
|
|
20715
|
+
* removed or moved is wrong where it was and where it is; an item with
|
|
20716
|
+
* anything changed inside it is wrong where it is. Whatever none of
|
|
20717
|
+
* that touches is right already, which in a lazy list scrolling is
|
|
20718
|
+
* everything on screen: the rows it mounts and unmounts are in its
|
|
20719
|
+
* overscan, and the spacers that stand for the rest only grow and
|
|
20720
|
+
* shrink off the top and bottom.
|
|
20721
|
+
*/
|
|
20722
|
+
damage(layer, container, layout) {
|
|
20723
|
+
const frame = this.frame;
|
|
20724
|
+
if (frame === null) return "all";
|
|
20725
|
+
const boxes = [];
|
|
20726
|
+
for (const [node, flags] of frame.entries()) {
|
|
20727
|
+
if (node === container) {
|
|
20728
|
+
if ((flags & 128) !== 0) return "all";
|
|
20729
|
+
continue;
|
|
20730
|
+
}
|
|
20731
|
+
const item = itemHolding(container, node);
|
|
20732
|
+
if (item === null) continue;
|
|
20733
|
+
const was = layer.items.get(item);
|
|
20734
|
+
const now = boxOf(layout, item);
|
|
20735
|
+
if (was !== void 0) boxes.push(was);
|
|
20736
|
+
if (now !== void 0 && (was === void 0 || !sameBox(was, now))) boxes.push(now);
|
|
20737
|
+
}
|
|
20738
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20739
|
+
for (const item of itemsOf(container)) {
|
|
20740
|
+
seen.add(item);
|
|
20741
|
+
const now = boxOf(layout, item);
|
|
20742
|
+
const was = layer.items.get(item);
|
|
20743
|
+
if (now === void 0) continue;
|
|
20744
|
+
if (was === void 0) boxes.push(now);
|
|
20745
|
+
else if (!sameBox(was, now)) boxes.push(was, now);
|
|
20746
|
+
}
|
|
20747
|
+
for (const [item, was] of layer.items) if (!seen.has(item)) boxes.push(was);
|
|
20748
|
+
const rects = [];
|
|
20749
|
+
let area = 0;
|
|
20750
|
+
for (const box of boxes) {
|
|
20751
|
+
const rect = this.toLayer(layer, box);
|
|
20752
|
+
if (rect !== null && !rects.some((other) => sameBox(other, rect))) {
|
|
20753
|
+
rects.push(rect);
|
|
20754
|
+
area += rect.width * rect.height;
|
|
20755
|
+
}
|
|
20756
|
+
}
|
|
20757
|
+
return area > layer.width * layer.height * MOSTLY ? "all" : rects;
|
|
20758
|
+
}
|
|
20759
|
+
/** Notes where the container's items are, for the next frame's \`damage\`. */
|
|
20760
|
+
remember(layer, container, layout) {
|
|
20761
|
+
layer.items.clear();
|
|
20762
|
+
for (const item of itemsOf(container)) {
|
|
20763
|
+
const box = boxOf(layout, item);
|
|
20764
|
+
if (box !== void 0) layer.items.set(item, box);
|
|
20765
|
+
}
|
|
20766
|
+
}
|
|
20767
|
+
/** An item's box in the layer's pixels, widened for what paints past it, or null off the layer. */
|
|
20768
|
+
toLayer(layer, box) {
|
|
20769
|
+
const dpr = layer.dpr;
|
|
20770
|
+
const left = Math.max(0, Math.floor(layer.offsetX + dpr * (box.x - layer.scrollX - 8)));
|
|
20771
|
+
const top = Math.max(0, Math.floor(layer.offsetY + dpr * (box.y - layer.scrollY - 8)));
|
|
20772
|
+
const right = Math.min(layer.width, Math.ceil(layer.offsetX + dpr * (box.x + box.width - layer.scrollX + 8)));
|
|
20773
|
+
const bottom = Math.min(layer.height, Math.ceil(layer.offsetY + dpr * (box.y + box.height - layer.scrollY + 8)));
|
|
20774
|
+
return right > left && bottom > top ? {
|
|
20775
|
+
x: left,
|
|
20776
|
+
y: top,
|
|
20777
|
+
width: right - left,
|
|
20778
|
+
height: bottom - top
|
|
20779
|
+
} : null;
|
|
20780
|
+
}
|
|
20577
20781
|
/** Stops building layers for a container until its subtree is next dirtied. */
|
|
20578
20782
|
refuse(node) {
|
|
20579
20783
|
this.drop(node);
|
|
@@ -20596,14 +20800,63 @@ var ScrollLayerCache = class {
|
|
|
20596
20800
|
this.refused.delete(node);
|
|
20597
20801
|
}
|
|
20598
20802
|
};
|
|
20599
|
-
/**
|
|
20803
|
+
/**
|
|
20804
|
+
* Whether an ancestor's properties or environment changed. An inherited
|
|
20805
|
+
* value set on an ancestor marks every descendant that reads it as well
|
|
20806
|
+
* (the graph re-provides it), so what it changes inside the container
|
|
20807
|
+
* is damage like any other; this keeps the old caution for the rest.
|
|
20808
|
+
* An ancestor marked for paint alone is the runtime asking for a frame
|
|
20809
|
+
* (a scrollbar fading, an inspector outline), which nothing inside the
|
|
20810
|
+
* container hears; one laid out again either leaves the container where
|
|
20811
|
+
* it was or moves it, which \`fits\` hears about; one whose children
|
|
20812
|
+
* changed has changed nothing inside this one. The last two happen on
|
|
20813
|
+
* every frame a lazy list mounts a row, since a layout need is marked
|
|
20814
|
+
* all the way up.
|
|
20815
|
+
*/
|
|
20600
20816
|
function dirtyAbove(frame, node) {
|
|
20601
|
-
for (let ancestor = node.parent; ancestor !== null; ancestor = ancestor.parent)
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20817
|
+
for (let ancestor = node.parent; ancestor !== null; ancestor = ancestor.parent) if ((frame.dirtyFlagsFor(ancestor) & INHERITED) !== 0) return true;
|
|
20818
|
+
return false;
|
|
20819
|
+
}
|
|
20820
|
+
/** What an ancestor's dirt can say about how its descendants look. */
|
|
20821
|
+
const INHERITED = 192;
|
|
20822
|
+
/** Whether \`ancestor\` is above \`node\` in the tree. */
|
|
20823
|
+
function contains(ancestor, node) {
|
|
20824
|
+
for (let current = node.parent; current !== null; current = current.parent) if (current === ancestor) return true;
|
|
20605
20825
|
return false;
|
|
20606
20826
|
}
|
|
20827
|
+
/** A container's items: its children, and the children of any fragment among them, in order. */
|
|
20828
|
+
function itemsOf(container) {
|
|
20829
|
+
const items = [];
|
|
20830
|
+
const visit = (parent) => {
|
|
20831
|
+
for (let child = parent.firstChild; child !== null; child = child.nextSibling) if (child.type === "fragment") visit(child);
|
|
20832
|
+
else items.push(child);
|
|
20833
|
+
};
|
|
20834
|
+
visit(container);
|
|
20835
|
+
return items;
|
|
20836
|
+
}
|
|
20837
|
+
/** The item of a container that holds a node, the node itself if it is one, or null outside the container or above its items. */
|
|
20838
|
+
function itemHolding(container, node) {
|
|
20839
|
+
let item = null;
|
|
20840
|
+
for (let current = node; current !== null; current = current.parent) {
|
|
20841
|
+
if (current === container) return item;
|
|
20842
|
+
if (current.type !== "fragment") item = current;
|
|
20843
|
+
}
|
|
20844
|
+
return null;
|
|
20845
|
+
}
|
|
20846
|
+
function sameBox(a, b) {
|
|
20847
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
20848
|
+
}
|
|
20849
|
+
function boxOf(layout, node) {
|
|
20850
|
+
const rec = layout.recordFor(node);
|
|
20851
|
+
return rec === void 0 ? void 0 : {
|
|
20852
|
+
x: rec.x,
|
|
20853
|
+
y: rec.y,
|
|
20854
|
+
width: rec.width,
|
|
20855
|
+
height: rec.height
|
|
20856
|
+
};
|
|
20857
|
+
}
|
|
20858
|
+
/** Damage over this share of a layer repaints all of it in one walk. */
|
|
20859
|
+
const MOSTLY = .5;
|
|
20607
20860
|
/**
|
|
20608
20861
|
* Where a scroll container's viewport lands in device pixels, or null
|
|
20609
20862
|
* when a layer could not reproduce the direct draw exactly: no
|
|
@@ -20649,6 +20902,273 @@ function clearLayer(ctx, width, height) {
|
|
|
20649
20902
|
ctx.clearRect(0, 0, width, height);
|
|
20650
20903
|
}
|
|
20651
20904
|
//#endregion
|
|
20905
|
+
//#region src/rendering/canvas2d/TextRasterCache.ts
|
|
20906
|
+
/**
|
|
20907
|
+
* Text kept as pixels, so a frame that only moved it copies it rather
|
|
20908
|
+
* than drawing its glyphs again.
|
|
20909
|
+
*
|
|
20910
|
+
* **Why.** Drawing glyphs is most of what a frame of text costs:
|
|
20911
|
+
* profiled while flicking through a file in Easel, `fillText` was 1,064
|
|
20912
|
+
* of the renderer's 1,985 ms. A scroll moves every line on screen and
|
|
20913
|
+
* changes none of them, so every one of those glyphs was drawn again
|
|
20914
|
+
* only to land a few pixels from where it was. In WKWebView a frame of
|
|
20915
|
+
* that cost 4 to 7 ms, which is more than a 165 Hz refresh holds.
|
|
20916
|
+
*
|
|
20917
|
+
* **What is kept.** What `drawText` draws for one node, drawn once into
|
|
20918
|
+
* a canvas of its own at the device scale and fraction of a pixel it
|
|
20919
|
+
* lands on, and copied onto the frame from then on. The copy lands on
|
|
20920
|
+
* whole device pixels, so the pixels are the ones a direct draw at that
|
|
20921
|
+
* fraction would have made, and a scroll, which moves by whole device
|
|
20922
|
+
* pixels, keeps the fraction.
|
|
20923
|
+
*
|
|
20924
|
+
* **When it is drawn again.** When anything `drawText` reads changes:
|
|
20925
|
+
* the text, its runs, its font, its colour, its box, the scale, or the
|
|
20926
|
+
* fraction of a pixel it sits at. Each is compared every frame, which is
|
|
20927
|
+
* a few comparisons; a run list or a colour that has not changed is the
|
|
20928
|
+
* same object it was.
|
|
20929
|
+
*
|
|
20930
|
+
* **What it is not for.** Text that changes on most frames (a clock, a
|
|
20931
|
+
* counter, an animated colour) would be drawn twice a frame, into the
|
|
20932
|
+
* cache and out of it. A node redrawn on most of its recent frames is
|
|
20933
|
+
* drawn directly instead, until it has been still for a while.
|
|
20934
|
+
*/
|
|
20935
|
+
var TextRasterCache = class {
|
|
20936
|
+
createCanvas;
|
|
20937
|
+
entries = /* @__PURE__ */ new Map();
|
|
20938
|
+
frame = 0;
|
|
20939
|
+
pixels = 0;
|
|
20940
|
+
/** Draws served from the cache and drawn into it, since the last reset. For budget specs. */
|
|
20941
|
+
stats = {
|
|
20942
|
+
copied: 0,
|
|
20943
|
+
drawn: 0,
|
|
20944
|
+
direct: 0
|
|
20945
|
+
};
|
|
20946
|
+
constructor(createCanvas) {
|
|
20947
|
+
this.createCanvas = createCanvas;
|
|
20948
|
+
}
|
|
20949
|
+
beginFrame() {
|
|
20950
|
+
this.frame++;
|
|
20951
|
+
}
|
|
20952
|
+
/** Lets go of text not drawn lately: removed, scrolled far away, or hidden. */
|
|
20953
|
+
endFrame() {
|
|
20954
|
+
for (const [node, entry] of this.entries) if (this.frame - entry.used > IDLE_FRAMES) this.drop(node, entry);
|
|
20955
|
+
}
|
|
20956
|
+
dropAll() {
|
|
20957
|
+
for (const [node, entry] of this.entries) this.drop(node, entry);
|
|
20958
|
+
}
|
|
20959
|
+
resetStats() {
|
|
20960
|
+
this.stats.copied = 0;
|
|
20961
|
+
this.stats.drawn = 0;
|
|
20962
|
+
this.stats.direct = 0;
|
|
20963
|
+
}
|
|
20964
|
+
/**
|
|
20965
|
+
* Draws a node's text from the cache, drawing it into the cache first
|
|
20966
|
+
* when what it holds is out of date. False when the text should be
|
|
20967
|
+
* drawn directly: a context that cannot say where it draws, one that
|
|
20968
|
+
* rotates or skews, text too large to keep, or text that changes too
|
|
20969
|
+
* often to be worth keeping.
|
|
20970
|
+
*/
|
|
20971
|
+
draw(ctx, node, box, paint, measurer) {
|
|
20972
|
+
const m = ctx.getTransform?.();
|
|
20973
|
+
if (m === void 0 || m.b !== 0 || m.c !== 0 || !(m.a > 0) || !(m.d > 0)) return false;
|
|
20974
|
+
let entry = this.entries.get(node);
|
|
20975
|
+
if (entry !== void 0 && entry.directUntil > this.frame) {
|
|
20976
|
+
entry.used = this.frame;
|
|
20977
|
+
this.stats.direct++;
|
|
20978
|
+
return false;
|
|
20979
|
+
}
|
|
20980
|
+
let extent = entry !== void 0 && entry.drawnFrom(paint, box, m.a, m.d) ? entry.extent : null;
|
|
20981
|
+
if (extent === null) {
|
|
20982
|
+
extent = inkExtent(box, paint, measurer);
|
|
20983
|
+
if (extent === null) return false;
|
|
20984
|
+
}
|
|
20985
|
+
const left = m.a * (box.x + extent.left) + m.e;
|
|
20986
|
+
const top = m.d * (box.y + extent.top) + m.f;
|
|
20987
|
+
const x = Math.floor(left);
|
|
20988
|
+
const y = Math.floor(top);
|
|
20989
|
+
const width = Math.ceil(m.a * (extent.right - extent.left) + (left - x)) + 1;
|
|
20990
|
+
const height = Math.ceil(m.d * (extent.bottom - extent.top) + (top - y)) + 1;
|
|
20991
|
+
if (width * height > MAX_ENTRY_PIXELS) return false;
|
|
20992
|
+
const offsetX = m.e - x;
|
|
20993
|
+
const offsetY = m.f - y;
|
|
20994
|
+
let raster = entry ?? null;
|
|
20995
|
+
if (raster === null || !raster.holds(paint, box, m.a, m.d, offsetX, offsetY, width, height)) {
|
|
20996
|
+
raster = this.redraw(node, entry, paint, box, measurer, m.a, m.d, offsetX, offsetY, width, height, extent);
|
|
20997
|
+
if (raster === null) return false;
|
|
20998
|
+
}
|
|
20999
|
+
raster.used = this.frame;
|
|
21000
|
+
ctx.save();
|
|
21001
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
21002
|
+
ctx.drawImage(raster.canvas, x, y, raster.canvasWidth, raster.canvasHeight);
|
|
21003
|
+
ctx.restore();
|
|
21004
|
+
this.stats.copied++;
|
|
21005
|
+
return true;
|
|
21006
|
+
}
|
|
21007
|
+
redraw(node, previous, paint, box, measurer, scaleX, scaleY, offsetX, offsetY, width, height, extent) {
|
|
21008
|
+
let entry = previous;
|
|
21009
|
+
if (entry !== void 0) {
|
|
21010
|
+
entry.churn = this.frame - entry.drawnAt <= CHURN_FRAMES ? entry.churn + 1 : 0;
|
|
21011
|
+
if (entry.churn >= CHURN_LIMIT) {
|
|
21012
|
+
entry.churn = 0;
|
|
21013
|
+
entry.directUntil = this.frame + DIRECT_FRAMES;
|
|
21014
|
+
entry.used = this.frame;
|
|
21015
|
+
this.stats.direct++;
|
|
21016
|
+
return null;
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
21019
|
+
if (entry === void 0 || entry.canvasWidth < width || entry.canvasHeight < height) {
|
|
21020
|
+
const canvasWidth = Math.max(width, entry?.canvasWidth ?? 0);
|
|
21021
|
+
const canvasHeight = Math.max(height, entry?.canvasHeight ?? 0);
|
|
21022
|
+
const canvas = this.createCanvas(canvasWidth, canvasHeight);
|
|
21023
|
+
const context = canvas?.getContext("2d");
|
|
21024
|
+
if (canvas === null || !context) return null;
|
|
21025
|
+
this.make(canvasWidth * canvasHeight);
|
|
21026
|
+
if (entry !== void 0) {
|
|
21027
|
+
this.pixels -= entry.canvasWidth * entry.canvasHeight;
|
|
21028
|
+
entry.canvas = canvas;
|
|
21029
|
+
entry.context = context;
|
|
21030
|
+
entry.canvasWidth = canvasWidth;
|
|
21031
|
+
entry.canvasHeight = canvasHeight;
|
|
21032
|
+
} else {
|
|
21033
|
+
entry = new TextRaster(canvas, context, canvasWidth, canvasHeight);
|
|
21034
|
+
this.entries.set(node, entry);
|
|
21035
|
+
}
|
|
21036
|
+
this.pixels += canvasWidth * canvasHeight;
|
|
21037
|
+
}
|
|
21038
|
+
const context = entry.context;
|
|
21039
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
21040
|
+
context.clearRect(0, 0, entry.canvasWidth, entry.canvasHeight);
|
|
21041
|
+
context.setTransform(scaleX, 0, 0, scaleY, offsetX, offsetY);
|
|
21042
|
+
context.globalAlpha = 1;
|
|
21043
|
+
drawText(context, box, paint, measurer);
|
|
21044
|
+
entry.remember(paint, box, scaleX, scaleY, offsetX, offsetY, width, height);
|
|
21045
|
+
entry.extent = extent;
|
|
21046
|
+
entry.drawnAt = this.frame;
|
|
21047
|
+
this.stats.drawn++;
|
|
21048
|
+
return entry;
|
|
21049
|
+
}
|
|
21050
|
+
/** Makes room for `needed` more pixels, letting go of what was drawn least recently. */
|
|
21051
|
+
make(needed) {
|
|
21052
|
+
if (this.pixels + needed <= MAX_PIXELS) return;
|
|
21053
|
+
const byAge = [...this.entries].sort((a, b) => a[1].used - b[1].used);
|
|
21054
|
+
for (const [node, entry] of byAge) {
|
|
21055
|
+
if (this.pixels + needed <= MAX_PIXELS || entry.used === this.frame) break;
|
|
21056
|
+
this.drop(node, entry);
|
|
21057
|
+
}
|
|
21058
|
+
}
|
|
21059
|
+
drop(node, entry) {
|
|
21060
|
+
this.entries.delete(node);
|
|
21061
|
+
this.pixels -= entry.canvasWidth * entry.canvasHeight;
|
|
21062
|
+
entry.canvas.width = 0;
|
|
21063
|
+
entry.canvas.height = 0;
|
|
21064
|
+
}
|
|
21065
|
+
};
|
|
21066
|
+
/** One node's text as pixels, and what it was drawn from. */
|
|
21067
|
+
var TextRaster = class {
|
|
21068
|
+
canvas;
|
|
21069
|
+
context;
|
|
21070
|
+
canvasWidth;
|
|
21071
|
+
canvasHeight;
|
|
21072
|
+
used = 0;
|
|
21073
|
+
drawnAt = 0;
|
|
21074
|
+
churn = 0;
|
|
21075
|
+
directUntil = 0;
|
|
21076
|
+
/** Where the ink reaches, from the box's corner, in layout pixels. */
|
|
21077
|
+
extent = null;
|
|
21078
|
+
text;
|
|
21079
|
+
spans;
|
|
21080
|
+
font = "";
|
|
21081
|
+
color = "";
|
|
21082
|
+
style = "";
|
|
21083
|
+
linkHover = 0;
|
|
21084
|
+
boxWidth = 0;
|
|
21085
|
+
boxHeight = 0;
|
|
21086
|
+
scaleX = 0;
|
|
21087
|
+
scaleY = 0;
|
|
21088
|
+
offsetX = 0;
|
|
21089
|
+
offsetY = 0;
|
|
21090
|
+
width = 0;
|
|
21091
|
+
height = 0;
|
|
21092
|
+
constructor(canvas, context, canvasWidth, canvasHeight) {
|
|
21093
|
+
this.canvas = canvas;
|
|
21094
|
+
this.context = context;
|
|
21095
|
+
this.canvasWidth = canvasWidth;
|
|
21096
|
+
this.canvasHeight = canvasHeight;
|
|
21097
|
+
}
|
|
21098
|
+
holds(paint, box, scaleX, scaleY, offsetX, offsetY, width, height) {
|
|
21099
|
+
return this.drawnFrom(paint, box, scaleX, scaleY) && Math.abs(this.offsetX - offsetX) < SAME_PLACE && Math.abs(this.offsetY - offsetY) < SAME_PLACE && this.width === width && this.height === height;
|
|
21100
|
+
}
|
|
21101
|
+
/** Whether the pixels are of this text, in this style, at this size and scale, wherever they are. */
|
|
21102
|
+
drawnFrom(paint, box, scaleX, scaleY) {
|
|
21103
|
+
return this.text === paint.text && this.spans === paint.spans && this.linkHover === paint.linkHover && this.boxWidth === box.width && this.boxHeight === box.height && this.scaleX === scaleX && this.scaleY === scaleY && this.font === fontOf(paint) && this.color === colorToCss(paint.textColor) && this.style === styleOf(paint);
|
|
21104
|
+
}
|
|
21105
|
+
remember(paint, box, scaleX, scaleY, offsetX, offsetY, width, height) {
|
|
21106
|
+
this.text = paint.text;
|
|
21107
|
+
this.spans = paint.spans;
|
|
21108
|
+
this.linkHover = paint.linkHover;
|
|
21109
|
+
this.boxWidth = box.width;
|
|
21110
|
+
this.boxHeight = box.height;
|
|
21111
|
+
this.scaleX = scaleX;
|
|
21112
|
+
this.scaleY = scaleY;
|
|
21113
|
+
this.offsetX = offsetX;
|
|
21114
|
+
this.offsetY = offsetY;
|
|
21115
|
+
this.width = width;
|
|
21116
|
+
this.height = height;
|
|
21117
|
+
this.font = fontOf(paint);
|
|
21118
|
+
this.color = colorToCss(paint.textColor);
|
|
21119
|
+
this.style = styleOf(paint);
|
|
21120
|
+
}
|
|
21121
|
+
};
|
|
21122
|
+
/**
|
|
21123
|
+
* The lines' extent, and a margin for what glyphs reach past their line
|
|
21124
|
+
* box (an italic's lean, a descender below a tight line height, an
|
|
21125
|
+
* underline). Null for text that draws nothing.
|
|
21126
|
+
*/
|
|
21127
|
+
function inkExtent(box, paint, measurer) {
|
|
21128
|
+
const placements = layoutTextLines(box, paint, measurer);
|
|
21129
|
+
if (placements.length === 0) return null;
|
|
21130
|
+
let left = Infinity;
|
|
21131
|
+
let top = Infinity;
|
|
21132
|
+
let right = -Infinity;
|
|
21133
|
+
let bottom = -Infinity;
|
|
21134
|
+
for (const line of placements) {
|
|
21135
|
+
left = Math.min(left, line.x);
|
|
21136
|
+
top = Math.min(top, line.y);
|
|
21137
|
+
right = Math.max(right, line.x + line.width);
|
|
21138
|
+
bottom = Math.max(bottom, line.y + line.height);
|
|
21139
|
+
}
|
|
21140
|
+
const margin = Math.ceil(paint.fontSize * INK_MARGIN) + 2;
|
|
21141
|
+
return {
|
|
21142
|
+
left: left - box.x - margin,
|
|
21143
|
+
top: top - box.y - margin,
|
|
21144
|
+
right: right - box.x + margin,
|
|
21145
|
+
bottom: bottom - box.y + margin
|
|
21146
|
+
};
|
|
21147
|
+
}
|
|
21148
|
+
function fontOf(paint) {
|
|
21149
|
+
return `${paint.fontStyle} ${paint.fontVariant} ${paint.fontWeight} ${paint.fontStretch} ${paint.fontSize}/${paint.lineHeight} ${paint.fontFamily}`;
|
|
21150
|
+
}
|
|
21151
|
+
/** Everything else `drawText` reads that places or decorates the glyphs. */
|
|
21152
|
+
function styleOf(paint) {
|
|
21153
|
+
return `${paint.letterSpacing}|${paint.fontKerning}|${paint.textDecoration}|${paint.textAlign}|${paint.verticalAlign}|${paint.textWrap}|${paint.maxLines}|${paint.textOverflow}|${paint.rtl}`;
|
|
21154
|
+
}
|
|
21155
|
+
/** How far past its line box, as a share of the font size, a glyph's ink may reach. */
|
|
21156
|
+
const INK_MARGIN = .5;
|
|
21157
|
+
/** Within this much of a device pixel, text is at the same place. */
|
|
21158
|
+
const SAME_PLACE = 1 / 256;
|
|
21159
|
+
/** The largest single piece of text kept: a few screens of a long paragraph. */
|
|
21160
|
+
const MAX_ENTRY_PIXELS = 4e6;
|
|
21161
|
+
/** Everything kept, at most: about 128 MB. */
|
|
21162
|
+
const MAX_PIXELS = 32e6;
|
|
21163
|
+
/** Frames text is kept for without being drawn: about two seconds at 60 Hz. */
|
|
21164
|
+
const IDLE_FRAMES = 120;
|
|
21165
|
+
/** Drawn again within this many frames of the last time counts toward churn. */
|
|
21166
|
+
const CHURN_FRAMES = 2;
|
|
21167
|
+
/** Times in a row text may churn before it is drawn directly. */
|
|
21168
|
+
const CHURN_LIMIT = 3;
|
|
21169
|
+
/** Frames churning text is drawn directly for before the cache tries it again. */
|
|
21170
|
+
const DIRECT_FRAMES = 60;
|
|
21171
|
+
//#endregion
|
|
20652
21172
|
//#region src/rendering/canvas2d/Canvas2DRenderer.ts
|
|
20653
21173
|
/**
|
|
20654
21174
|
* Canvas2D rendering backend.
|
|
@@ -20760,6 +21280,13 @@ var Canvas2DRenderer = class {
|
|
|
20760
21280
|
constructor(options) {
|
|
20761
21281
|
this.options = options;
|
|
20762
21282
|
this.layers = new ScrollLayerCache(options.createLayerCanvas ?? offscreenLayerCanvas, options.scrollLayerSettleFrames);
|
|
21283
|
+
this.textCache = options.textCache === false ? null : new TextRasterCache(options.createLayerCanvas ?? offscreenLayerCanvas);
|
|
21284
|
+
}
|
|
21285
|
+
/** Text kept as pixels; see `TextRasterCache.ts`. */
|
|
21286
|
+
textCache;
|
|
21287
|
+
/** What the text cache did since the last reset, or null with it off. For budget specs. */
|
|
21288
|
+
get textCacheStats() {
|
|
21289
|
+
return this.textCache?.stats ?? null;
|
|
20763
21290
|
}
|
|
20764
21291
|
/** What the scroll layers did since the last reset. For budget specs. */
|
|
20765
21292
|
get scrollLayerStats() {
|
|
@@ -20785,11 +21312,13 @@ var Canvas2DRenderer = class {
|
|
|
20785
21312
|
/** A restored scroll layer reads as healthy and holds nothing. */
|
|
20786
21313
|
surfaceRestored() {
|
|
20787
21314
|
this.layers.dropAll();
|
|
21315
|
+
this.textCache?.dropAll();
|
|
20788
21316
|
}
|
|
20789
21317
|
dispose() {
|
|
20790
21318
|
this.disposed = true;
|
|
20791
21319
|
this.scaledImages.dispose();
|
|
20792
21320
|
this.layers.dropAll();
|
|
21321
|
+
this.textCache?.dropAll();
|
|
20793
21322
|
}
|
|
20794
21323
|
render(root, context) {
|
|
20795
21324
|
const raw = this.surface.getContext2D();
|
|
@@ -20803,11 +21332,13 @@ var Canvas2DRenderer = class {
|
|
|
20803
21332
|
this.liftedPass.length = 0;
|
|
20804
21333
|
this.paintOwner = null;
|
|
20805
21334
|
this.layerDepth = 0;
|
|
21335
|
+
this.textCache?.beginFrame();
|
|
20806
21336
|
this.layers.beginFrame(this.options.scrollLayers === false ? void 0 : context.changes, this.surface.dpr, this.surface.physicalWidth, this.surface.physicalHeight);
|
|
20807
21337
|
this.renderNode(root, context, ctx, true, false);
|
|
20808
21338
|
this.renderLifted(context, ctx);
|
|
20809
21339
|
if (context.overlay !== void 0 && context.overlay.length > 0) drawOverlayShapes(ctx, context.overlay);
|
|
20810
21340
|
this.layers.endFrame();
|
|
21341
|
+
this.textCache?.endFrame();
|
|
20811
21342
|
}
|
|
20812
21343
|
/**
|
|
20813
21344
|
* Folds a node's style into the shared scratch and records that it
|
|
@@ -20872,7 +21403,7 @@ var Canvas2DRenderer = class {
|
|
|
20872
21403
|
if (rec.clips) this.popCull();
|
|
20873
21404
|
if (hasText) {
|
|
20874
21405
|
if (this.paintOwner !== node) this.resolvePaint(node);
|
|
20875
|
-
this.paintContent(ctx, rec, this.paint, context);
|
|
21406
|
+
this.paintContent(ctx, node, rec, this.paint, context);
|
|
20876
21407
|
}
|
|
20877
21408
|
if (rec.liftBoundary && this.liftedPass.length > liftedBefore) this.renderLifted(context, ctx, liftedBefore, node);
|
|
20878
21409
|
if (rec.clips) ctx.restore();
|
|
@@ -21146,7 +21677,7 @@ var Canvas2DRenderer = class {
|
|
|
21146
21677
|
} else ctx.strokeRect(x, y, width, height);
|
|
21147
21678
|
}
|
|
21148
21679
|
}
|
|
21149
|
-
paintContent(ctx, rec, paint, context) {
|
|
21680
|
+
paintContent(ctx, node, rec, paint, context) {
|
|
21150
21681
|
if (paint.text !== void 0) {
|
|
21151
21682
|
this.contentBox.x = rec.x + rec.paddingLeft - rec.scrollX;
|
|
21152
21683
|
this.contentBox.y = rec.y + rec.paddingTop - rec.scrollY;
|
|
@@ -21160,6 +21691,7 @@ var Canvas2DRenderer = class {
|
|
|
21160
21691
|
this.paintHighlightedText(ctx, paint, context);
|
|
21161
21692
|
return;
|
|
21162
21693
|
}
|
|
21694
|
+
if (this.textCache?.draw(ctx, node, this.contentBox, paint, context.text) === true) return;
|
|
21163
21695
|
drawText(ctx, this.contentBox, paint, context.text);
|
|
21164
21696
|
}
|
|
21165
21697
|
}
|
|
@@ -21261,8 +21793,21 @@ var Canvas2DRenderer = class {
|
|
|
21261
21793
|
layers.drop(node);
|
|
21262
21794
|
return false;
|
|
21263
21795
|
}
|
|
21264
|
-
|
|
21796
|
+
const damage = layers.damage(layer, node, context.layout);
|
|
21797
|
+
const wrong = damage === "all" ? [{
|
|
21798
|
+
x: 0,
|
|
21799
|
+
y: 0,
|
|
21800
|
+
width: layer.width,
|
|
21801
|
+
height: layer.height
|
|
21802
|
+
}] : damage;
|
|
21803
|
+
if (wrong.length > 0) {
|
|
21804
|
+
const front = layer.frontContext;
|
|
21805
|
+
front.setTransform(1, 0, 0, 1, 0, 0);
|
|
21806
|
+
for (const rect of wrong) front.clearRect(rect.x, rect.y, rect.width, rect.height);
|
|
21807
|
+
}
|
|
21808
|
+
if (strips.length > 0 || wrong.length > 0) this.paintLayer(layer, [...strips, ...wrong], node, rec, context);
|
|
21265
21809
|
}
|
|
21810
|
+
layers.remember(layer, node, context.layout);
|
|
21266
21811
|
layer.used = true;
|
|
21267
21812
|
layers.stats.composited++;
|
|
21268
21813
|
ctx.save();
|
|
@@ -21284,13 +21829,13 @@ var Canvas2DRenderer = class {
|
|
|
21284
21829
|
* strip saves is raster, which is the cost it exists for; the walk
|
|
21285
21830
|
* costs what a direct draw's walk would.
|
|
21286
21831
|
*/
|
|
21287
|
-
paintLayer(layer,
|
|
21832
|
+
paintLayer(layer, strips, node, rec, context) {
|
|
21288
21833
|
const lctx = new PreciseContext(layer.frontContext);
|
|
21289
21834
|
lctx.save();
|
|
21290
|
-
if (
|
|
21835
|
+
if (strips !== null) {
|
|
21291
21836
|
lctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
21292
21837
|
lctx.beginPath();
|
|
21293
|
-
lctx.rect(strip.x, strip.y, strip.width, strip.height);
|
|
21838
|
+
for (const strip of strips) lctx.rect(strip.x, strip.y, strip.width, strip.height);
|
|
21294
21839
|
lctx.clip();
|
|
21295
21840
|
}
|
|
21296
21841
|
const dpr = layer.dpr;
|
|
@@ -21304,6 +21849,26 @@ var Canvas2DRenderer = class {
|
|
|
21304
21849
|
this.cullY = rec.y + layer.scrollY;
|
|
21305
21850
|
this.cullWidth = rec.width;
|
|
21306
21851
|
this.cullHeight = rec.height;
|
|
21852
|
+
if (strips !== null && strips.length > 0) {
|
|
21853
|
+
let left = Infinity;
|
|
21854
|
+
let top = Infinity;
|
|
21855
|
+
let right = -Infinity;
|
|
21856
|
+
let bottom = -Infinity;
|
|
21857
|
+
for (const strip of strips) {
|
|
21858
|
+
left = Math.min(left, strip.x);
|
|
21859
|
+
top = Math.min(top, strip.y);
|
|
21860
|
+
right = Math.max(right, strip.x + strip.width);
|
|
21861
|
+
bottom = Math.max(bottom, strip.y + strip.height);
|
|
21862
|
+
}
|
|
21863
|
+
const x0 = Math.max(this.cullX, (left - layer.offsetX) / dpr + layer.scrollX - 8);
|
|
21864
|
+
const y0 = Math.max(this.cullY, (top - layer.offsetY) / dpr + layer.scrollY - 8);
|
|
21865
|
+
const x1 = Math.min(this.cullX + this.cullWidth, (right - layer.offsetX) / dpr + layer.scrollX + 8);
|
|
21866
|
+
const y1 = Math.min(this.cullY + this.cullHeight, (bottom - layer.offsetY) / dpr + layer.scrollY + 8);
|
|
21867
|
+
this.cullX = x0;
|
|
21868
|
+
this.cullY = y0;
|
|
21869
|
+
this.cullWidth = Math.max(0, x1 - x0);
|
|
21870
|
+
this.cullHeight = Math.max(0, y1 - y0);
|
|
21871
|
+
}
|
|
21307
21872
|
this.layerDepth++;
|
|
21308
21873
|
try {
|
|
21309
21874
|
this.renderChildren(node, context, lctx, true);
|
|
@@ -21512,6 +22077,6 @@ function createCanvasSurface(host) {
|
|
|
21512
22077
|
return new CanvasSurface(host);
|
|
21513
22078
|
}
|
|
21514
22079
|
//#endregion
|
|
21515
|
-
export { isImeKey as $,
|
|
22080
|
+
export { isImeKey as $, MOUSE_POINTER as $a, spacingEqual as $i, ELLIPSIS as $n, transformsEqual as $r, registerFontStack as $t, withOverrideSource as A, colorToHex as Aa, observeViewportInsets as Ai, clearLinkHover as An, inheritedPropertyNames as Ar, adjacentField as At, FlexDirection as B, UiEnvironment as Ba, defineThemeExtension as Bi, editorFor as Bn, normalizeStates as Br, createCanvasTextStyle as Bt, SCROLLBAR_LINGER_MS as C, textContentOf as Ca, uniformBorderRadius as Ci, isNodeInert as Cn, resolveProperty as Cr, hasDrawnText as Ct, formatExplanation as D, darkColors as Da, UiInsetRegistry as Di, isSubtreeInert as Dn, findPropertyDefinition as Dr, selectionRectsIn as Dt, formatConstraints as E, colorsEqualPalette as Ea, UiEnvironmentKeys as Ei, isPressable as En, closestPropertyName as Er, paragraphGeometryFrom as Et, clampSize as F, parseColor as Fa, darkTheme as Fi, setLinkHover as Fn, UiProperties as Fr, detectEditingPlatform as Ft, CrossAxisAlignment as G, resetOverrideWarnings as Ga, withThemeExtension as Gi, nextCaretToggle as Gn, validateSubgrid as Gr, runFontString as Gt, placeGridItems as H, DirtyNodeSet as Ha, noThemeExtensions as Hi, isEditableNode as Hn, validateRole as Hr, fillTextRects as Ht, constraintsEqual as I, rgb8 as Ia, lightTheme as Ii, CARET_BLINK_MS as In, UI_ROLES as Ir, isPrintable as It, parseCrossAxisAlignment as J, UiVisualState as Ja, raiseContrast as Ji, isVideoSurface as Jn, pathValuesEqual as Jr, textRunBackgrounds as Jt, MainAxisAlignment as K, writeDeclaredProperty as Ka, contrastRatio as Ki, syncEditorValue as Kn, inputsEqual as Kr, spanOf as Kt, tightenConstraints as L, rgba as La, themesEqual as Li, CARET_WIDTH as Ln, UI_SEMANTIC_STATES as Lr, EditableLayout as Lt, contentOffset as M, colorValuesEqual as Ma, bandOf as Mi, linkHoverOf as Mn, propertyIsInherited as Mr, edgeField as Mt, LayoutRecord as N, colorsEqual as Na, containerBands as Ni, linkOf as Nn, propertyNarrowers as Nr, editingGroupOf as Nt, formatNumber as O, lightColors as Oa, insetsEqual as Oi, pointerEventsOf as On, getPropertyNames as Or, wordRangeIn as Ot, Constraints as P, normalizeColor as Pa, unknownContainerSize as Pi, linkRunAtPointIn as Pn, propertyValuesEqualByName as Pr, commandForKey as Pt, capturePointer as Q, visualStatesEqual as Qa, scaleSpacing as Qi, spannedRunsFor as Qn, transformIsIdentity as Qr, fontStackFor as Qt, MAX_MEASURES_PER_CHILD as R, createEnvironmentKey as Ra, withContrast as Ri, EDITOR_PROP as Rn, isUiRole as Rr, applyCanvasTextStyle as Rt, SCROLLBAR_FADE_MS as S, spansDifferOnlyInPaint as Sa, normalizeBorderRadius as Si, isNodeHitTestable as Sn, resolveNumber as Sr, UiInputDispatcher as St, describeOverrides as T, textStylesEqual as Ta, propertyValuesEqual as Ti, isNodeTabStop as Tn, resolveString as Tr, paragraphGeometry as Tt, sizeGridTracks as U, clearOverrideProperty as Ua, themeExtension as Ui, isMultiline as Un, validateStates as Ur, layoutTextLines as Ut, parseFlexDirection as V, UiNode as Va, hasThemeExtension as Vi, editorOf as Vn, statesEqual as Vr, drawText as Vt, AlignContent as W, overrideSources as Wa, themeExtensionsEqual as Wi, isReadOnly as Wn, UI_SUBGRID_AXES as Wr, runCanvasStyleInto as Wt, CanvasPlatformSurface as X, hasVisualState as Xa, densityFactors as Xi, CharacterCountTextMeasurer as Xn, parseTransform as Xr, bumpFontStack as Xt, parseMainAxisAlignment as Y, defaultVisualState as Ya, relativeLuminance as Yi, videoFrameSize as Yn, UiTransforms as Yr, textRunDecorations as Yt, UiPlatformAdapter as Z, visualState as Za, defaultSpacing as Zi, ParagraphTextMeasurer as Zn, transform as Zr, clearFontStacks as Zt, LABEL_PADDING_X as _, flattenTextSpans as _a, borderRadius as _i, selectableTextNodes as _n, DirtyFlags as _o, previousWordStart as _r, scrollLeaderOf as _t, PaintPictureCache as a, boxShadowArraysEqual as aa, validateGradient as ai, computeObjectFitRect as an, UiInputEvent as ao, lineLimit as ar, UiGestureRecognizer as at, snapScroll as b, spanAtOffset as ba, borderRadiusIsZero as bi, setSelectionRange as bn, DEFAULT_LINE_HEIGHT_FACTOR as br, scrollbarThumbs as bt, EMPTY_RECORDING as c, boxShadowsEqual as ca, isAutoLength as ci, normalizeTextAlign as cn, UiPinchEvent as co, offsetForVerticalMove as cr, isScrollContainer as ct, tracePathData as d, shapesEqual as da, isPercentLength as di, TEXT_MATCHES_PROP as dn, UiTextChangeEvent as do, graphemeBoundaries as dr, UiFocusManager as dt, spacingSteps as ea, MAX_GRADIENT_STOPS as ei, DEFAULT_FONT_FAMILY as en, UiBeforeInputEvent as eo, layoutParagraph as er, pointerDeviceOf as et, ScaledImageCache as f, defaultTypography as fa, minmax as fi, clearMatchRanges as fn, UiWheelDeltaMode as fo, lineEndAt as fr, UiHitTester as ft, paintsAfterChildren as g, editableSpansOf as ga, UiBorderRadiuses as gi, clearSelectionRange as gn, UiNodeType as go, previousGraphemeStart as gr, SCROLLBAR_THICKNESS as gt, hasDecorationPhase as h, defaultTextStyle as ha, resolveLength as hi, TEXT_SELECTION_PROP as hn, wheelDeltaYOf as ho, nextWordEnd as hr, SCROLLBAR_MIN_THUMB as ht, traceRoundedRect as i, boxShadow as ia, radialGradient as ii, colorToCss as in, UiGestureEvent as io, lineIndexForOffset as ir, UiTouchScroller as it, accumulatedOffsetTo as j, colorToRgba as ja, UiContainerSizeSource as ji, hasTextLinks as jn, propertyEffects as jr, comparePositions as jt, labelNode as k, UiBasicColors as ka, noInsets as ki, resolveCursor as kn, inheritedPropertyFlags as kr, textInputOf as kt, PaintRecorder as l, defaultShapes as la, isFrLength as li, normalizeVerticalAlign as ln, UiPointerEvent as lo, selectionRects as lr, UiKeyboardController as lt, decorationRect as m, typographyEqual as ma, repeat as mi, setMatchRanges as mn, noKeyModifiers as mo, nextGraphemeEnd as mr, SCROLLBAR_INSET as mt, createCanvasSurface as n, shadowsEqual as na, gradientsEqual as ni, DEFAULT_FONT_WEIGHT as nn, UiEventType as no, caretRectFor as nr, touchActionFor as nt, paintPictures as o, boxShadowRadius as oa, auto as oi, createPaintState as on, UiKeyboardEvent as oo, offsetAtPoint as or, UiPinchRecognizer as ot, decorationColor as p, isTypographyRole as pa, percent as pi, matchRangesOf as pn, UiWheelEvent as po, lineStartAt as pr, SCROLLBAR_HOVER_ZONE as pt, parseAlignContent as q, writeOverrideProperty as qa, highContrastColors as qi, resolveColorValue as qn, paintValuesEqual as qr, textMeasureRequest as qt, Canvas2DRenderer as r, BOX_SHADOW_BLUR_REACH as ra, linearGradient as ri, DEFAULT_TEXT_COLOR as rn, UiFocusEvent as ro, lineIndexAtY as rr, UiEditingController as rt, PaintTarget as s, boxShadowReach as sa, fr as si, isPaintVisible as sn, UiPasteEvent as so, offsetAtX as sr, UiWheelController as st, CanvasSurface as t, defaultShadows as ta, gradientPaint as ti, DEFAULT_FONT_SIZE as tn, UiCompositionEvent as to, proportionalFontMetrics as tr, prepareInputSurface as tt, replayPaint as u, isShapeName as ua, isMinMaxTrack as ui, resolvePaintState as un, UiSelectionChangeEvent as uo, EditableTextModel as ur, UiPointerController as ut, drawOverlayShapes as v, hiddenRangesOf as va, borderRadiusCorners as vi, selectableTextOf as vn, UiBinding as vo, wordRangeAt as vr, scrollRange as vt, describeLength as w, textSpansEqual as wa, defineProperty as wi, isNodeSelectable as wn, resolvePropertyByName as wr, offsetAtPointIn as wt, LayoutEngine as x, spannedTextOf as xa, borderRadiusValuesEqual as xi, isNodeFocusable as xn, resolveBoolean as xr, scrollbarZoneAt as xt, labelOrigin as y, resolvedSpansOf as ya, borderRadiusEqual as yi, selectionRangeOf as yn, UiGraph as yr, scrollbarThumb as yt, isLayoutProtocol as z, findEnvironmentKey as za, withDensity as zi, caretVisibleAt as zn, isUiSemanticState as zr, buildFontString as zt };
|
|
21516
22081
|
|
|
21517
|
-
//# sourceMappingURL=CanvasSurface-
|
|
22082
|
+
//# sourceMappingURL=CanvasSurface-VUJRrcXl.js.map
|