supervision 0.2.0-next.0 → 0.2.0-next.2
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/constants/media-renderer.d.ts +3 -0
- package/dist/constants/media-renderer.d.ts.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1722 -1395
- package/dist/index.js.map +1 -1
- package/dist/mask-preparation.worker.js +109 -31
- package/dist/mask-preparation.worker.js.map +1 -1
- package/dist/media/media-frame-clock.d.ts +4 -0
- package/dist/media/media-frame-clock.d.ts.map +1 -0
- package/dist/media/media-source-state.d.ts.map +1 -1
- package/dist/media/media-source.d.ts +6 -0
- package/dist/media/media-source.d.ts.map +1 -1
- package/dist/media/video-engine-media-source.d.ts +17 -7
- package/dist/media/video-engine-media-source.d.ts.map +1 -1
- package/dist/media/video-engine-media-source.js +3 -0
- package/dist/media/video-engine-media-source.js.map +1 -0
- package/dist/playback/media-playback-controller.d.ts +7 -1
- package/dist/playback/media-playback-controller.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-artifact.d.ts +2 -0
- package/dist/render-preparation/mask-frame-artifact.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-compositor.d.ts +7 -0
- package/dist/render-preparation/mask-frame-compositor.d.ts.map +1 -1
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts +1 -0
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts.map +1 -1
- package/dist/render-preparation/prepared-render-window.d.ts +21 -2
- package/dist/render-preparation/prepared-render-window.d.ts.map +1 -1
- package/dist/render-preparation/prepared-window-timeline.d.ts +1 -0
- package/dist/render-preparation/prepared-window-timeline.d.ts.map +1 -1
- package/dist/renderers/injected-pixi.d.ts +38 -0
- package/dist/renderers/injected-pixi.d.ts.map +1 -0
- package/dist/renderers/media-frame-navigation.d.ts +17 -0
- package/dist/renderers/media-frame-navigation.d.ts.map +1 -0
- package/dist/renderers/media-renderer-core.d.ts +9 -0
- package/dist/renderers/media-renderer-core.d.ts.map +1 -1
- package/dist/renderers/media-renderer-scene.d.ts +17 -5
- package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
- package/dist/renderers/media-renderer-state.d.ts +9 -0
- package/dist/renderers/media-renderer-state.d.ts.map +1 -1
- package/dist/renderers/media-renderer-transport.d.ts +19 -3
- package/dist/renderers/media-renderer-transport.d.ts.map +1 -1
- package/dist/renderers/pixi-focus-layer.d.ts +1 -0
- package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-frame-present.d.ts +1 -1
- package/dist/renderers/pixi-frame-present.d.ts.map +1 -1
- package/dist/renderers/pixi-id-mask-shader.d.ts +4 -33
- package/dist/renderers/pixi-id-mask-shader.d.ts.map +1 -1
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts +0 -1
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-halo.d.ts +4 -33
- package/dist/renderers/pixi-mask-halo.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-layer.d.ts +28 -29
- package/dist/renderers/pixi-mask-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
- package/dist/renderers/pixi-polygon-layer.d.ts +2 -0
- package/dist/renderers/pixi-polygon-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-region-coverage-mask.d.ts +4 -33
- package/dist/renderers/pixi-region-coverage-mask.d.ts.map +1 -1
- package/dist/renderers/pixi-region-layer.d.ts +6 -31
- package/dist/renderers/pixi-region-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-shader-lifecycle.d.ts +14 -0
- package/dist/renderers/pixi-shader-lifecycle.d.ts.map +1 -0
- package/dist/renderers/prepared-annotation-window.d.ts.map +1 -1
- package/dist/renderers/presented-frame-channel.d.ts +34 -1
- package/dist/renderers/presented-frame-channel.d.ts.map +1 -1
- package/dist/sessions/media-session-defaults.d.ts.map +1 -1
- package/dist/sessions/media-session-detections.d.ts.map +1 -1
- package/dist/sessions/media-session-state.d.ts.map +1 -1
- package/dist/sessions/media-session.d.ts.map +1 -1
- package/dist/tracking.worker.js +19 -5
- package/dist/tracking.worker.js.map +1 -1
- package/dist/types/media-frame-clock.d.ts +16 -0
- package/dist/types/media-frame-clock.d.ts.map +1 -0
- package/dist/types/media-frame-navigation.d.ts +28 -0
- package/dist/types/media-frame-navigation.d.ts.map +1 -0
- package/dist/types/media-renderer-display.d.ts +12 -0
- package/dist/types/media-renderer-display.d.ts.map +1 -0
- package/dist/types/media-renderer.d.ts +13 -0
- package/dist/types/media-renderer.d.ts.map +1 -1
- package/dist/types/media-session.d.ts +35 -32
- package/dist/types/media-session.d.ts.map +1 -1
- package/dist/types/render-preparation.d.ts +78 -28
- package/dist/types/render-preparation.d.ts.map +1 -1
- package/dist/video-engine-media-source-DR-x1UfK.js +483 -0
- package/dist/video-engine-media-source-DR-x1UfK.js.map +1 -0
- package/dist/web-video-engine/analysis-session.d.ts +0 -1
- package/dist/web-video-engine/analysis.d.ts +0 -1
- package/dist/web-video-engine/analysis.js +211 -23
- package/dist/web-video-engine/cache-budget.d.ts +0 -1
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts +6 -2
- package/dist/web-video-engine/clock.d.ts +0 -1
- package/dist/web-video-engine/constants.d.ts +9 -1
- package/dist/web-video-engine/create-scrub-cursor.d.ts +6 -3
- package/dist/web-video-engine/decode-resolution.d.ts +0 -1
- package/dist/web-video-engine/decode-scheduler.d.ts +26 -5
- package/dist/web-video-engine/decode-session.d.ts +11 -1
- package/dist/web-video-engine/decode-source.d.ts +11 -1
- package/dist/web-video-engine/diagnostics-store.d.ts +0 -1
- package/dist/web-video-engine/diagnostics.d.ts +19 -19
- package/dist/web-video-engine/embedded-engine-worker.d.ts +0 -1
- package/dist/web-video-engine/engine-core.d.ts +31 -11
- package/dist/web-video-engine/engine.d.ts +3 -4
- package/dist/web-video-engine/engine.js +175 -44
- package/dist/web-video-engine/engine.worker.d.ts +0 -1
- package/dist/web-video-engine/engine.worker.js +5712 -2947
- package/dist/web-video-engine/frame-cache.d.ts +121 -12
- package/dist/web-video-engine/frame-extractor.d.ts +0 -1
- package/dist/web-video-engine/{frame-timeline-GINI8Gum.js → frame-timeline-DreEwsRY.js} +83 -27
- package/dist/web-video-engine/frame-timeline.d.ts +10 -1
- package/dist/web-video-engine/frame-walker.d.ts +0 -1
- package/dist/web-video-engine/index.d.ts +12 -2
- package/dist/web-video-engine/index.d.ts.map +1 -1
- package/dist/web-video-engine/index.js +2 -2
- package/dist/web-video-engine/key-packet.d.ts +0 -1
- package/dist/web-video-engine/keyframe-index.d.ts +0 -1
- package/dist/web-video-engine/mirror-store.d.ts +0 -1
- package/dist/web-video-engine/pausable-deadline.d.ts +11 -0
- package/dist/web-video-engine/renderer.d.ts +0 -1
- package/dist/web-video-engine/rotation.d.ts +0 -1
- package/dist/web-video-engine/scrub-controller.d.ts +8 -5
- package/dist/web-video-engine/scrub-cursor.d.ts +15 -7
- package/dist/web-video-engine/scrub-trajectory.d.ts +0 -1
- package/dist/web-video-engine/source-residency.d.ts +35 -1
- package/dist/web-video-engine/trace-recorder.d.ts +0 -1
- package/dist/web-video-engine/types.d.ts +18 -22
- package/dist/web-video-engine/video-engine.d.ts +39 -17
- package/dist/web-video-engine/webgpu-renderer.d.ts +0 -1
- package/dist/web-video-engine/worker-bridge.d.ts +0 -1
- package/dist/web-video-engine/worker-dispatch.d.ts +0 -1
- package/dist/web-video-engine/worker-protocol.d.ts +38 -15
- package/node_modules/supervision-js-core/dist/detections/buffered-detection-timeline.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.d.ts +2 -2
- package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.js +182 -68
- package/node_modules/supervision-js-core/dist/index.js.map +1 -1
- package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts +20 -3
- package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts +28 -26
- package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts +16 -0
- package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts +19 -0
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/media/media-condition-probe.d.ts +0 -51
- package/dist/media/media-condition-probe.d.ts.map +0 -1
- package/dist/media/media-conditions.d.ts +0 -28
- package/dist/media/media-conditions.d.ts.map +0 -1
- package/dist/types/media-conditions.d.ts +0 -149
- package/dist/types/media-conditions.d.ts.map +0 -1
- package/dist/web-video-engine/analysis-session.d.ts.map +0 -1
- package/dist/web-video-engine/analysis.d.ts.map +0 -1
- package/dist/web-video-engine/analysis.js.map +0 -1
- package/dist/web-video-engine/cache-budget.d.ts.map +0 -1
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/clock.d.ts.map +0 -1
- package/dist/web-video-engine/constants.d.ts.map +0 -1
- package/dist/web-video-engine/create-scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/decode-resolution.d.ts.map +0 -1
- package/dist/web-video-engine/decode-scheduler.d.ts.map +0 -1
- package/dist/web-video-engine/decode-session.d.ts.map +0 -1
- package/dist/web-video-engine/decode-source.d.ts.map +0 -1
- package/dist/web-video-engine/diagnostics-store.d.ts.map +0 -1
- package/dist/web-video-engine/diagnostics.d.ts.map +0 -1
- package/dist/web-video-engine/embedded-engine-worker.d.ts.map +0 -1
- package/dist/web-video-engine/engine-core.d.ts.map +0 -1
- package/dist/web-video-engine/engine.d.ts.map +0 -1
- package/dist/web-video-engine/engine.js.map +0 -1
- package/dist/web-video-engine/engine.worker.d.ts.map +0 -1
- package/dist/web-video-engine/engine.worker.js.map +0 -1
- package/dist/web-video-engine/frame-cache.d.ts.map +0 -1
- package/dist/web-video-engine/frame-extractor.d.ts.map +0 -1
- package/dist/web-video-engine/frame-timeline-GINI8Gum.js.map +0 -1
- package/dist/web-video-engine/frame-timeline.d.ts.map +0 -1
- package/dist/web-video-engine/frame-walker.d.ts.map +0 -1
- package/dist/web-video-engine/key-packet.d.ts.map +0 -1
- package/dist/web-video-engine/keyframe-index.d.ts.map +0 -1
- package/dist/web-video-engine/mirror-store.d.ts.map +0 -1
- package/dist/web-video-engine/renderer.d.ts.map +0 -1
- package/dist/web-video-engine/rotation.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-controller.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-trajectory.d.ts.map +0 -1
- package/dist/web-video-engine/source-residency.d.ts.map +0 -1
- package/dist/web-video-engine/trace-recorder.d.ts.map +0 -1
- package/dist/web-video-engine/types.d.ts.map +0 -1
- package/dist/web-video-engine/video-engine.d.ts.map +0 -1
- package/dist/web-video-engine/webgpu-renderer.d.ts.map +0 -1
- package/dist/web-video-engine/worker-bridge.d.ts.map +0 -1
- package/dist/web-video-engine/worker-dispatch.d.ts.map +0 -1
- package/dist/web-video-engine/worker-protocol.d.ts.map +0 -1
|
@@ -426,7 +426,6 @@
|
|
|
426
426
|
const height = width === maskWidth
|
|
427
427
|
? maskHeight
|
|
428
428
|
: Math.max(1, Math.round((width * maskHeight) / maskWidth));
|
|
429
|
-
const strokeScale = width / maskWidth;
|
|
430
429
|
const scaledAxes = width === maskWidth
|
|
431
430
|
? undefined
|
|
432
431
|
: createScaledMaskAxes({ height, maskHeight, maskWidth, width });
|
|
@@ -437,18 +436,17 @@
|
|
|
437
436
|
let hasStroke = false;
|
|
438
437
|
let maxStrokeWidth = 0;
|
|
439
438
|
for (const instruction of instructions) {
|
|
440
|
-
const detectionMaskId = instruction.detectionIndex
|
|
441
|
-
if (detectionMaskId
|
|
442
|
-
detectionMaskId >= MAX_ID_MASK_PALETTE_ENTRIES) {
|
|
439
|
+
const detectionMaskId = resolveIdMaskPaletteId(instruction.detectionIndex);
|
|
440
|
+
if (detectionMaskId === undefined) {
|
|
443
441
|
return undefined;
|
|
444
442
|
}
|
|
445
|
-
|
|
443
|
+
writeIdMaskPaletteEntry(fillPalette, detectionMaskId, instruction.color, instruction.alpha);
|
|
446
444
|
if (instruction.stroke && instruction.stroke.width > 0) {
|
|
447
|
-
const strokeWidth =
|
|
445
|
+
const strokeWidth = resolveIdMaskStrokeTexels(instruction.stroke.width, maskWidth, width);
|
|
448
446
|
hasStroke = true;
|
|
449
447
|
strokeWidths[detectionMaskId] = strokeWidth;
|
|
450
448
|
maxStrokeWidth = Math.max(maxStrokeWidth, strokeWidth);
|
|
451
|
-
|
|
449
|
+
writeIdMaskPaletteEntry(strokePalette, detectionMaskId, instruction.stroke.color, instruction.stroke.alpha);
|
|
452
450
|
}
|
|
453
451
|
if (scaledAxes) {
|
|
454
452
|
writeScaledMaskRuns(data, scaledAxes, instruction.mask, detectionMaskId);
|
|
@@ -463,6 +461,7 @@
|
|
|
463
461
|
hasStroke,
|
|
464
462
|
height,
|
|
465
463
|
maxStrokeWidth,
|
|
464
|
+
sourceWidth: maskWidth,
|
|
466
465
|
strokePalette,
|
|
467
466
|
strokeWidths,
|
|
468
467
|
width,
|
|
@@ -545,10 +544,14 @@
|
|
|
545
544
|
* A stroke is measured in texels of the raster it is drawn on, so a coarser
|
|
546
545
|
* raster measures it in coarser texels. A stroke of a texel or more keeps at
|
|
547
546
|
* least one, the thinnest line the shader can draw; a narrower one keeps its
|
|
548
|
-
* own width, which the shader draws as an inner boundary at any scale.
|
|
547
|
+
* own width, which the shader draws as an inner boundary at any scale. The
|
|
548
|
+
* ceiling is the widest neighbourhood the shaders scan, so a wider stroke would
|
|
549
|
+
* be drawn at the ceiling anyway and every layer drawing the same annotation
|
|
550
|
+
* has to arrive at the same width.
|
|
549
551
|
*/
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
+
function resolveIdMaskStrokeTexels(strokeWidth, maskWidth, rasterWidth) {
|
|
553
|
+
const scale = maskWidth > 0 ? rasterWidth / maskWidth : 1;
|
|
554
|
+
return Math.min(Math.max(strokeWidth * scale, Math.min(strokeWidth, 1)), MAX_ID_MASK_STROKE_WIDTH);
|
|
552
555
|
}
|
|
553
556
|
function createScaledMaskAxes(frame) {
|
|
554
557
|
return {
|
|
@@ -565,8 +568,19 @@
|
|
|
565
568
|
}
|
|
566
569
|
return map;
|
|
567
570
|
}
|
|
568
|
-
|
|
569
|
-
|
|
571
|
+
/**
|
|
572
|
+
* The palette slot a detection index names, or undefined when the palette has
|
|
573
|
+
* no slot for it. Slot zero is the background, so the ids start at one and the
|
|
574
|
+
* last detection the palette can name sits one index below the last slot.
|
|
575
|
+
*/
|
|
576
|
+
function resolveIdMaskPaletteId(detectionIndex) {
|
|
577
|
+
const detectionMaskId = detectionIndex + 1;
|
|
578
|
+
return detectionMaskId > 0 && detectionMaskId < MAX_ID_MASK_PALETTE_ENTRIES
|
|
579
|
+
? detectionMaskId
|
|
580
|
+
: undefined;
|
|
581
|
+
}
|
|
582
|
+
function writeIdMaskPaletteEntry(palette, detectionMaskId, color, alpha) {
|
|
583
|
+
const offset = detectionMaskId * 4;
|
|
570
584
|
palette[offset] = ((color >> 16) & 0xff) / 255;
|
|
571
585
|
palette[offset + 1] = ((color >> 8) & 0xff) / 255;
|
|
572
586
|
palette[offset + 2] = (color & 0xff) / 255;
|
|
@@ -606,7 +620,7 @@
|
|
|
606
620
|
*/
|
|
607
621
|
var MediaErrorKind;
|
|
608
622
|
(function (MediaErrorKind) {
|
|
609
|
-
/** The media could not be opened or read
|
|
623
|
+
/** The media could not be opened or read, or was refused before any read. */
|
|
610
624
|
MediaErrorKind["Unreadable"] = "unreadable";
|
|
611
625
|
/** The container or codec is not supported by this platform. */
|
|
612
626
|
MediaErrorKind["UnsupportedFormat"] = "unsupportedFormat";
|
|
@@ -640,8 +654,8 @@
|
|
|
640
654
|
* A source the renderer pulls samples from can be held between any two frames,
|
|
641
655
|
* because the renderer decides when each one is drawn. A source that presents
|
|
642
656
|
* its own frames owns the playhead, so holding it means stopping the producer
|
|
643
|
-
* and starting it again,
|
|
644
|
-
*
|
|
657
|
+
* and starting it again, and a gate that stops one has to bound its own wait
|
|
658
|
+
* or a producer nothing answers for never runs again.
|
|
645
659
|
*/
|
|
646
660
|
var PlaybackGateReach;
|
|
647
661
|
(function (PlaybackGateReach) {
|
|
@@ -652,8 +666,6 @@
|
|
|
652
666
|
* missing, until they arrive or the gate's own wait bound gives up on them.
|
|
653
667
|
*/
|
|
654
668
|
PlaybackGateReach["EveryFrame"] = "everyFrame";
|
|
655
|
-
/** Playback waits to begin; frames after that are not held. */
|
|
656
|
-
PlaybackGateReach["StartOfPlayback"] = "startOfPlayback";
|
|
657
669
|
})(PlaybackGateReach || (PlaybackGateReach = {}));
|
|
658
670
|
|
|
659
671
|
/**
|
|
@@ -707,7 +719,23 @@
|
|
|
707
719
|
MediaSessionActivityKind["Error"] = "error";
|
|
708
720
|
MediaSessionActivityKind["MediaNormalizing"] = "mediaNormalizing";
|
|
709
721
|
MediaSessionActivityKind["MediaOpening"] = "mediaOpening";
|
|
722
|
+
/**
|
|
723
|
+
* The picture is waiting on media the source has not handed over yet, which
|
|
724
|
+
* is the bytes and their decode rather than anything downstream of them.
|
|
725
|
+
* `PlaybackBuffering` is what a transport reports once it has already
|
|
726
|
+
* stopped; this is reported from the read itself, including the reads a seek
|
|
727
|
+
* makes while the transport still reads as paused.
|
|
728
|
+
*/
|
|
729
|
+
MediaSessionActivityKind["MediaSourceReading"] = "mediaSourceReading";
|
|
710
730
|
MediaSessionActivityKind["PlaybackBuffering"] = "playbackBuffering";
|
|
731
|
+
/**
|
|
732
|
+
* The render-preparation gate held the picture for artifacts that never
|
|
733
|
+
* arrived and let it go. Nothing is blocked: the frames reaching the screen
|
|
734
|
+
* are the ones whose artifacts were given up on. What is waited on is
|
|
735
|
+
* preparation finishing another frame, which is what lets the gate hold the
|
|
736
|
+
* picture again; `RenderPreparing` covers the holds that are running.
|
|
737
|
+
*/
|
|
738
|
+
MediaSessionActivityKind["RenderPreparationAbandoned"] = "renderPreparationAbandoned";
|
|
711
739
|
MediaSessionActivityKind["RenderPreparing"] = "renderPreparing";
|
|
712
740
|
})(MediaSessionActivityKind || (MediaSessionActivityKind = {}));
|
|
713
741
|
/**
|
|
@@ -791,18 +819,33 @@
|
|
|
791
819
|
return undefined;
|
|
792
820
|
}
|
|
793
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Whether the palette has a slot for every detection this frame masks. An id
|
|
824
|
+
* names a detection by its index in the frame, so one masked detection past the
|
|
825
|
+
* last slot leaves the whole frame without an id raster however few masks it
|
|
826
|
+
* carries.
|
|
827
|
+
*/
|
|
828
|
+
function canIdMaskPaletteNameFrame(instructions) {
|
|
829
|
+
return instructions.every((instruction) => instruction.visible === false ||
|
|
830
|
+
resolveIdMaskPaletteId(instruction.detectionIndex) !== undefined);
|
|
831
|
+
}
|
|
794
832
|
function createIdMaskPlane(instructions, maxRasterWidth) {
|
|
833
|
+
// The plane carries the ids a failed cook could not. A frame the palette
|
|
834
|
+
// cannot name has none to carry, and cooking it again reaches the same
|
|
835
|
+
// refusal after rasterizing every mask a second time.
|
|
836
|
+
if (!canIdMaskPaletteNameFrame(instructions)) {
|
|
837
|
+
return undefined;
|
|
838
|
+
}
|
|
795
839
|
const frame = createIdMaskRasterFrame(instructions, maxRasterWidth);
|
|
796
840
|
return frame
|
|
797
841
|
? { data: frame.data, height: frame.height, width: frame.width }
|
|
798
842
|
: undefined;
|
|
799
843
|
}
|
|
800
844
|
function compositeInstruction(rgba, canvasWidth, instruction) {
|
|
801
|
-
const decodedMask = decodeCompressedRleMask(instruction.mask);
|
|
802
845
|
const fill = resolveRgbaColor(instruction.color, instruction.alpha);
|
|
803
|
-
compositeMaskFill(rgba, canvasWidth,
|
|
804
|
-
if (instruction.stroke) {
|
|
805
|
-
compositeMaskStroke(rgba, canvasWidth,
|
|
846
|
+
const bounds = compositeMaskFill(rgba, canvasWidth, instruction.mask, fill);
|
|
847
|
+
if (instruction.stroke && bounds) {
|
|
848
|
+
compositeMaskStroke(rgba, canvasWidth, decodeCompressedRleMask(instruction.mask), bounds, instruction.stroke);
|
|
806
849
|
}
|
|
807
850
|
}
|
|
808
851
|
function materializeMaskInstructions(instructions) {
|
|
@@ -822,25 +865,59 @@
|
|
|
822
865
|
};
|
|
823
866
|
});
|
|
824
867
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
868
|
+
/**
|
|
869
|
+
* Compressed RLE counts runs down each column in turn, so a foreground run is
|
|
870
|
+
* a contiguous walk down one column that wraps into the next.
|
|
871
|
+
*/
|
|
872
|
+
function compositeMaskFill(rgba, canvasWidth, mask, fill) {
|
|
873
|
+
const counts = decodeCompressedRleCounts(mask.counts);
|
|
874
|
+
const maskWidth = mask.width;
|
|
875
|
+
const maskHeight = mask.height;
|
|
876
|
+
const maskArea = maskWidth * maskHeight;
|
|
877
|
+
let maskOffset = 0;
|
|
878
|
+
let minX = maskWidth;
|
|
879
|
+
let minY = maskHeight;
|
|
880
|
+
let maxX = -1;
|
|
881
|
+
let maxY = -1;
|
|
882
|
+
for (let index = 0; index < counts.length; index += 1) {
|
|
883
|
+
const runLength = counts[index] ?? 0;
|
|
884
|
+
if (index % 2 === 0 || runLength <= 0) {
|
|
885
|
+
maskOffset += runLength;
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
let columnX = Math.floor(maskOffset / maskHeight);
|
|
889
|
+
let columnY = maskOffset - columnX * maskHeight;
|
|
890
|
+
for (let step = 0; step < runLength; step += 1) {
|
|
891
|
+
// A run can outlast the columns the mask has; the pixel it then names
|
|
892
|
+
// is wherever that column-major offset lands when read back row-major.
|
|
893
|
+
const rowMajorOffset = columnY * maskWidth + columnX;
|
|
894
|
+
if (rowMajorOffset < maskArea) {
|
|
895
|
+
const x = rowMajorOffset % maskWidth;
|
|
896
|
+
const y = (rowMajorOffset - x) / maskWidth;
|
|
897
|
+
writePixel(rgba, canvasWidth, x, y, fill);
|
|
898
|
+
minX = Math.min(minX, x);
|
|
899
|
+
minY = Math.min(minY, y);
|
|
900
|
+
maxX = Math.max(maxX, x);
|
|
901
|
+
maxY = Math.max(maxY, y);
|
|
902
|
+
}
|
|
903
|
+
columnY += 1;
|
|
904
|
+
if (columnY === maskHeight) {
|
|
905
|
+
columnY = 0;
|
|
906
|
+
columnX += 1;
|
|
831
907
|
}
|
|
832
|
-
writePixel(rgba, canvasWidth, x, y, fill);
|
|
833
908
|
}
|
|
909
|
+
maskOffset += runLength;
|
|
834
910
|
}
|
|
911
|
+
return maxX < minX || maxY < minY ? undefined : { maxX, maxY, minX, minY };
|
|
835
912
|
}
|
|
836
|
-
function compositeMaskStroke(rgba, canvasWidth, decodedMask, stroke) {
|
|
913
|
+
function compositeMaskStroke(rgba, canvasWidth, decodedMask, bounds, stroke) {
|
|
837
914
|
const width = Math.round(stroke.width);
|
|
838
915
|
if (width <= 0) {
|
|
839
916
|
return;
|
|
840
917
|
}
|
|
841
918
|
const strokeColor = resolveRgbaColor(stroke.color, stroke.alpha);
|
|
842
|
-
for (let y =
|
|
843
|
-
for (let x =
|
|
919
|
+
for (let y = bounds.minY; y <= bounds.maxY; y += 1) {
|
|
920
|
+
for (let x = bounds.minX; x <= bounds.maxX; x += 1) {
|
|
844
921
|
if (!isMaskPixel(decodedMask, x, y) ||
|
|
845
922
|
!isBoundaryPixel(decodedMask, x, y)) {
|
|
846
923
|
continue;
|
|
@@ -946,6 +1023,7 @@
|
|
|
946
1023
|
raster: idMaskFrame.data,
|
|
947
1024
|
regionMaskCoverage,
|
|
948
1025
|
requestId: message.requestId,
|
|
1026
|
+
sourceWidth: idMaskFrame.sourceWidth,
|
|
949
1027
|
strokePalette: idMaskFrame.strokePalette,
|
|
950
1028
|
strokeWidths: idMaskFrame.strokeWidths,
|
|
951
1029
|
type: MaskPreparationWorkerMessageType.Complete,
|