ntk 3.5.2 → 3.5.3
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/lib/renderingcontext_2d.js +45 -12
- package/package.json +1 -1
|
@@ -552,6 +552,34 @@ class RenderingContext2d {
|
|
|
552
552
|
* Core fill: rasterize device-space polys into the scratch a8 mask,
|
|
553
553
|
* scale by globalAlpha, intersect with the clip, composite the source.
|
|
554
554
|
*/
|
|
555
|
+
/**
|
|
556
|
+
* Device-space bounding box of flattened polys, with a pixel of slack for
|
|
557
|
+
* the antialiased edge, clamped to the surface. Null when nothing lands
|
|
558
|
+
* on it.
|
|
559
|
+
*/
|
|
560
|
+
_polysBBox(polys) {
|
|
561
|
+
let minX = Infinity;
|
|
562
|
+
let minY = Infinity;
|
|
563
|
+
let maxX = -Infinity;
|
|
564
|
+
let maxY = -Infinity;
|
|
565
|
+
for (const poly of polys) {
|
|
566
|
+
const pts = poly.pts;
|
|
567
|
+
for (let i = 0; i < pts.length; i += 2) {
|
|
568
|
+
if (pts[i] < minX) minX = pts[i];
|
|
569
|
+
if (pts[i] > maxX) maxX = pts[i];
|
|
570
|
+
if (pts[i + 1] < minY) minY = pts[i + 1];
|
|
571
|
+
if (pts[i + 1] > maxY) maxY = pts[i + 1];
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (maxX === -Infinity) return null;
|
|
575
|
+
const x = Math.max(0, Math.floor(minX) - 1);
|
|
576
|
+
const y = Math.max(0, Math.floor(minY) - 1);
|
|
577
|
+
const w = Math.min(this.width, Math.ceil(maxX) + 1) - x;
|
|
578
|
+
const h = Math.min(this.height, Math.ceil(maxY) + 1) - y;
|
|
579
|
+
if (w <= 0 || h <= 0) return null;
|
|
580
|
+
return { x, y, w, h };
|
|
581
|
+
}
|
|
582
|
+
|
|
555
583
|
_fillPolys(polys, rule, { src = null, op = null, alpha = null } = {}) {
|
|
556
584
|
if (!polys.length) return;
|
|
557
585
|
src = src ?? this._backgroundPicture;
|
|
@@ -559,26 +587,31 @@ class RenderingContext2d {
|
|
|
559
587
|
alpha = alpha ?? this.globalAlpha;
|
|
560
588
|
if (alpha <= 0) return;
|
|
561
589
|
|
|
590
|
+
// Everything below is bounded to the shape's bounding box rather than
|
|
591
|
+
// the whole surface. On the wire it makes no difference — a Composite
|
|
592
|
+
// request is the same size either way — but it is the difference
|
|
593
|
+
// between the server touching a 34x34 box and a 400x400 one per fill.
|
|
594
|
+
// Stale mask content outside the box is never composited, so clearing
|
|
595
|
+
// only the box is safe.
|
|
596
|
+
const b = this._polysBBox(polys);
|
|
597
|
+
if (!b) return;
|
|
598
|
+
const R = this.Render;
|
|
599
|
+
|
|
562
600
|
this._ensureFillMask();
|
|
563
|
-
|
|
601
|
+
R.FillRectangles(R.PictOp.Src, this.fillMask.id, [0, 0, 0, 0], [b.x, b.y, b.w, b.h]);
|
|
564
602
|
this._rasterizePolys(this.fillMask, polys, rule);
|
|
565
603
|
|
|
566
604
|
if (alpha < 1) {
|
|
567
605
|
// In with a constant color scales the a8 coverage by that alpha
|
|
568
|
-
|
|
606
|
+
R.FillRectangles(R.PictOp.In, this.fillMask.id, [0, 0, 0, alpha], [b.x, b.y, b.w, b.h]);
|
|
569
607
|
}
|
|
570
608
|
if (this.clipMask) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
this.clipMask.id,
|
|
574
|
-
0,
|
|
575
|
-
this.fillMask.id,
|
|
576
|
-
0, 0, 0, 0, 0, 0,
|
|
577
|
-
this.width,
|
|
578
|
-
this.height
|
|
579
|
-
);
|
|
609
|
+
// clipMask is surface-aligned, so it is sampled at the same offset
|
|
610
|
+
R.Composite(R.PictOp.In, this.clipMask.id, 0, this.fillMask.id, b.x, b.y, 0, 0, b.x, b.y, b.w, b.h);
|
|
580
611
|
}
|
|
581
|
-
|
|
612
|
+
// src is either a 1x1 repeating solid (offset irrelevant) or a
|
|
613
|
+
// surface-aligned gradient, so it is sampled at the same offset too
|
|
614
|
+
R.Composite(op, src.id, this.fillMask.id, this.picture.id, b.x, b.y, b.x, b.y, b.x, b.y, b.w, b.h);
|
|
582
615
|
this._markDirty();
|
|
583
616
|
}
|
|
584
617
|
|