summaryrefslogtreecommitdiff
path: root/apps/web/src/services/renderer/compositor
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-15 15:45:50 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-15 15:45:50 +0200
commitc46d28891fee62ca2d3132da876af6411a41d9da (patch)
treef856f71d04c69628f26b904088d675dd298a5080 /apps/web/src/services/renderer/compositor
parent66e4367bc4727f1d0bcf8f869529c7518812277e (diff)
downloadopencut-c46d28891fee62ca2d3132da876af6411a41d9da.tar.gz
feat: text / custom masks, fix preview pan, refactor selection
Diffstat (limited to 'apps/web/src/services/renderer/compositor')
-rw-r--r--apps/web/src/services/renderer/compositor/frame-descriptor.ts36
1 files changed, 30 insertions, 6 deletions
diff --git a/apps/web/src/services/renderer/compositor/frame-descriptor.ts b/apps/web/src/services/renderer/compositor/frame-descriptor.ts
index 8b8201d5..f93eae27 100644
--- a/apps/web/src/services/renderer/compositor/frame-descriptor.ts
+++ b/apps/web/src/services/renderer/compositor/frame-descriptor.ts
@@ -401,6 +401,11 @@ function buildMaskArtifacts({
}
const definition = masksRegistry.get(mask.type);
+
+ if (definition.isActive?.(mask.params) === false) {
+ return { mask: null, strokeLayer: null };
+ }
+
const elementMaskCanvas = createOffscreenCanvas({
width: Math.round(transform.width),
height: Math.round(transform.height),
@@ -416,7 +421,12 @@ function buildMaskArtifacts({
let strokePath: Path2D | null = null;
let feather = mask.params.feather;
- if (mask.params.feather > 0 && definition.renderer.renderMask) {
+ const canRenderMaskDirectly = Boolean(definition.renderer.renderMask);
+ const shouldRenderMaskDirectly =
+ canRenderMaskDirectly &&
+ (!definition.renderer.buildPath ||
+ (mask.params.feather > 0 && definition.renderer.renderMaskHandlesFeather));
+ if (shouldRenderMaskDirectly && definition.renderer.renderMask) {
definition.renderer.renderMask({
resolvedParams: mask.params,
ctx: elementMaskCtx,
@@ -424,13 +434,18 @@ function buildMaskArtifacts({
height: Math.round(transform.height),
feather: mask.params.feather,
});
- feather = 0;
+ if (definition.renderer.renderMaskHandlesFeather) {
+ feather = 0;
+ }
strokePath = definition.renderer.buildStrokePath?.({
resolvedParams: mask.params,
width: transform.width,
height: transform.height,
}) ?? null;
} else {
+ if (!definition.renderer.buildPath) {
+ return { mask: null, strokeLayer: null };
+ }
const path2d = definition.renderer.buildPath({
resolvedParams: mask.params,
width: transform.width,
@@ -472,7 +487,7 @@ function buildMaskArtifacts({
});
let strokeLayer: FrameItemDescriptor | null = null;
- if (mask.params.strokeWidth > 0 && strokePath) {
+ if (mask.params.strokeWidth > 0 && (strokePath || definition.renderer.renderStroke)) {
const strokeCanvas = createOffscreenCanvas({
width: Math.round(transform.width),
height: Math.round(transform.height),
@@ -482,9 +497,18 @@ function buildMaskArtifacts({
| OffscreenCanvasRenderingContext2D
| null;
if (strokeCtx) {
- strokeCtx.strokeStyle = mask.params.strokeColor;
- strokeCtx.lineWidth = mask.params.strokeWidth;
- strokeCtx.stroke(strokePath);
+ if (definition.renderer.renderStroke) {
+ definition.renderer.renderStroke({
+ resolvedParams: mask.params,
+ ctx: strokeCtx,
+ width: transform.width,
+ height: transform.height,
+ });
+ } else if (strokePath) {
+ strokeCtx.strokeStyle = mask.params.strokeColor;
+ strokeCtx.lineWidth = mask.params.strokeWidth;
+ strokeCtx.stroke(strokePath);
+ }
const fullStrokeCanvas = createOffscreenCanvas({
width: renderer.width,