diff options
Diffstat (limited to 'apps/web/src/services/renderer')
| -rw-r--r-- | apps/web/src/services/renderer/compositor/frame-descriptor.ts | 36 | ||||
| -rw-r--r-- | apps/web/src/services/renderer/nodes/text-node.ts | 89 |
2 files changed, 40 insertions, 85 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, diff --git a/apps/web/src/services/renderer/nodes/text-node.ts b/apps/web/src/services/renderer/nodes/text-node.ts index c9e13261..86384328 100644 --- a/apps/web/src/services/renderer/nodes/text-node.ts +++ b/apps/web/src/services/renderer/nodes/text-node.ts @@ -3,16 +3,9 @@ import type { TextElement } from "@/lib/timeline"; import type { EffectPass } from "@/lib/effects/types"; import type { Transform } from "@/lib/rendering"; import { - CORNER_RADIUS_MAX, - CORNER_RADIUS_MIN, -} from "@/lib/text/background"; -import { - drawTextDecoration, - getTextBackgroundRect, - setCanvasLetterSpacing, -} from "@/lib/text/layout"; + drawMeasuredTextLayout, +} from "@/lib/text/primitives"; import type { MeasuredTextElement } from "@/lib/text/measure-element"; -import { clamp } from "@/utils/math"; export type TextNodeParams = TextElement & { canvasCenter: { x: number; y: number }; @@ -46,22 +39,6 @@ export function renderTextToContext({ const x = resolved.transform.position.x + node.params.canvasCenter.x; const y = resolved.transform.position.y + node.params.canvasCenter.y; const baseline = node.params.textBaseline ?? "middle"; - const { - scaledFontSize, - fontString, - letterSpacing, - lineHeightPx, - lines, - lineMetrics, - block, - fontSizeRatio, - resolvedBackground, - } = resolved.measuredText; - const lineCount = lines.length; - const resolvedBackgroundWithColor = { - ...resolvedBackground, - color: resolved.backgroundColor, - }; ctx.save(); ctx.translate(x, y); @@ -70,60 +47,14 @@ export function renderTextToContext({ ctx.rotate((resolved.transform.rotate * Math.PI) / 180); } - ctx.font = fontString; - ctx.textAlign = node.params.textAlign; - ctx.textBaseline = baseline; - ctx.fillStyle = resolved.textColor; - setCanvasLetterSpacing({ ctx, letterSpacingPx: letterSpacing }); - - if ( - node.params.background.enabled && - node.params.background.color && - node.params.background.color !== "transparent" && - lineCount > 0 - ) { - const backgroundRect = getTextBackgroundRect({ - textAlign: node.params.textAlign, - block, - background: resolvedBackgroundWithColor, - fontSizeRatio, - }); - if (backgroundRect) { - const p = - clamp({ - value: resolvedBackgroundWithColor.cornerRadius, - min: CORNER_RADIUS_MIN, - max: CORNER_RADIUS_MAX, - }) / 100; - const radius = - (Math.min(backgroundRect.width, backgroundRect.height) / 2) * p; - ctx.fillStyle = resolvedBackgroundWithColor.color; - ctx.beginPath(); - ctx.roundRect( - backgroundRect.left, - backgroundRect.top, - backgroundRect.width, - backgroundRect.height, - radius, - ); - ctx.fill(); - ctx.fillStyle = resolved.textColor; - } - } - - for (let index = 0; index < lineCount; index++) { - const lineY = index * lineHeightPx - block.visualCenterOffset; - ctx.fillText(lines[index], 0, lineY); - drawTextDecoration({ - ctx, - textDecoration: node.params.textDecoration ?? "none", - lineWidth: lineMetrics[index].width, - lineY, - metrics: lineMetrics[index], - scaledFontSize, - textAlign: node.params.textAlign, - }); - } + drawMeasuredTextLayout({ + ctx, + layout: resolved.measuredText, + textColor: resolved.textColor, + background: resolved.measuredText.resolvedBackground, + backgroundColor: resolved.backgroundColor, + textBaseline: baseline, + }); ctx.restore(); } |
