@editframe/elements 0.32.0-beta.1 → 0.34.5-beta
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/EF_FRAMEGEN.js +5 -3
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.94.0 → _@oxc-project_runtime@0.95.0}/helpers/decorate.js +1 -1
- package/dist/canvas/EFCanvas.d.ts +7 -4
- package/dist/canvas/EFCanvas.js +1 -1
- package/dist/canvas/EFCanvasItem.d.ts +4 -4
- package/dist/canvas/EFCanvasItem.js +1 -1
- package/dist/canvas/overlays/SelectionOverlay.d.ts +95 -0
- package/dist/canvas/overlays/SelectionOverlay.js +1 -1
- package/dist/canvas/selection/SelectionController.js +7 -11
- package/dist/canvas/selection/SelectionController.js.map +1 -1
- package/dist/elements/EFAudio.d.ts +29 -11
- package/dist/elements/EFAudio.js +31 -61
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +69 -56
- package/dist/elements/EFCaptions.js +186 -400
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +41 -13
- package/dist/elements/EFImage.js +114 -79
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +17 -17
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +41 -25
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +4 -4
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +31 -17
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +17 -9
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +68 -22
- package/dist/elements/EFMedia.js +412 -30
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +4 -4
- package/dist/elements/EFPanZoom.js +1 -1
- package/dist/elements/EFSourceMixin.js +43 -15
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +25 -12
- package/dist/elements/EFSurface.js +64 -22
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +8 -2
- package/dist/elements/EFTemporal.js +42 -31
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +5 -4
- package/dist/elements/EFText.js +11 -2
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.d.ts +4 -4
- package/dist/elements/EFTextSegment.js +1 -1
- package/dist/elements/EFThumbnailStrip.d.ts +6 -6
- package/dist/elements/EFThumbnailStrip.js +1 -1
- package/dist/elements/EFTimegroup.d.ts +26 -12
- package/dist/elements/EFTimegroup.js +203 -115
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +63 -26
- package/dist/elements/EFVideo.js +324 -72
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +33 -7
- package/dist/elements/EFWaveform.js +103 -59
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/renderTemporalAudio.js +14 -3
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/gui/ContextMixin.js +1 -1
- package/dist/gui/Controllable.d.ts +2 -0
- package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
- package/dist/gui/EFActiveRootTemporal.js +1 -1
- package/dist/gui/EFConfiguration.d.ts +4 -4
- package/dist/gui/EFConfiguration.js +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +1 -1
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFDial.js +1 -1
- package/dist/gui/EFFilmstrip.d.ts +5 -4
- package/dist/gui/EFFilmstrip.js +1 -1
- package/dist/gui/EFFitScale.d.ts +3 -3
- package/dist/gui/EFFitScale.js +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +6 -6
- package/dist/gui/EFFocusOverlay.js +1 -1
- package/dist/gui/EFOverlayItem.d.ts +4 -4
- package/dist/gui/EFOverlayItem.js +1 -1
- package/dist/gui/EFOverlayLayer.d.ts +4 -4
- package/dist/gui/EFOverlayLayer.js +1 -1
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPause.js +1 -1
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPlay.js +1 -1
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFPreview.js +1 -1
- package/dist/gui/EFResizableBox.d.ts +4 -4
- package/dist/gui/EFResizableBox.js +1 -1
- package/dist/gui/EFScrubber.d.ts +4 -4
- package/dist/gui/EFScrubber.js +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFTimeDisplay.js +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +4 -4
- package/dist/gui/EFTimelineRuler.js +1 -1
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFToggleLoop.js +1 -1
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFTogglePlay.js +1 -1
- package/dist/gui/EFTransformHandles.d.ts +4 -4
- package/dist/gui/EFTransformHandles.js +1 -1
- package/dist/gui/EFWorkbench.d.ts +7 -6
- package/dist/gui/EFWorkbench.js +1 -1
- package/dist/gui/PlaybackController.d.ts +10 -2
- package/dist/gui/PlaybackController.js +52 -30
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/TargetOrContextMixin.js +1 -1
- package/dist/gui/hierarchy/EFHierarchy.d.ts +4 -4
- package/dist/gui/hierarchy/EFHierarchy.js +1 -1
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
- package/dist/gui/hierarchy/EFHierarchyItem.js +1 -1
- package/dist/gui/timeline/EFTimeline.d.ts +6 -2
- package/dist/gui/timeline/EFTimeline.js +1 -1
- package/dist/gui/timeline/EFTimelineRow.d.ts +57 -0
- package/dist/gui/timeline/EFTimelineRow.js +1 -1
- package/dist/gui/timeline/TrimHandles.d.ts +4 -4
- package/dist/gui/timeline/TrimHandles.js +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.d.ts +2 -0
- package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
- package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +58 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js +1 -1
- package/dist/gui/timeline/tracks/HTMLTrack.d.ts +13 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js +1 -1
- package/dist/gui/timeline/tracks/ImageTrack.d.ts +14 -0
- package/dist/gui/timeline/tracks/ImageTrack.js +1 -1
- package/dist/gui/timeline/tracks/TextTrack.d.ts +26 -0
- package/dist/gui/timeline/tracks/TextTrack.js +1 -1
- package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +47 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js +4 -12
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TrackItem.d.ts +81 -0
- package/dist/gui/timeline/tracks/TrackItem.js +1 -1
- package/dist/gui/timeline/tracks/VideoTrack.d.ts +25 -0
- package/dist/gui/timeline/tracks/VideoTrack.js +1 -1
- package/dist/gui/timeline/tracks/WaveformTrack.d.ts +14 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js +1 -1
- package/dist/gui/timeline/tracks/ensureTrackItemInit.d.ts +1 -0
- package/dist/gui/timeline/tracks/preloadTracks.d.ts +9 -0
- package/dist/gui/tree/EFTree.d.ts +5 -4
- package/dist/gui/tree/EFTree.js +1 -1
- package/dist/gui/tree/EFTreeItem.d.ts +4 -4
- package/dist/gui/tree/EFTreeItem.js +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/preview/AdaptiveResolutionTracker.js +6 -14
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
- package/dist/preview/FrameController.d.ts +123 -0
- package/dist/preview/FrameController.js +216 -0
- package/dist/preview/FrameController.js.map +1 -0
- package/dist/preview/RenderContext.d.ts +1 -0
- package/dist/preview/RenderContext.js +193 -0
- package/dist/preview/RenderContext.js.map +1 -0
- package/dist/preview/encoding/canvasEncoder.js +166 -0
- package/dist/preview/encoding/canvasEncoder.js.map +1 -0
- package/dist/preview/encoding/mainThreadEncoder.js +39 -0
- package/dist/preview/encoding/mainThreadEncoder.js.map +1 -0
- package/dist/preview/encoding/types.d.ts +1 -0
- package/dist/preview/encoding/workerEncoder.js +58 -0
- package/dist/preview/encoding/workerEncoder.js.map +1 -0
- package/dist/preview/logger.js +41 -0
- package/dist/preview/logger.js.map +1 -0
- package/dist/preview/previewSettings.js +5 -0
- package/dist/preview/previewSettings.js.map +1 -1
- package/dist/preview/previewTypes.js +11 -10
- package/dist/preview/previewTypes.js.map +1 -1
- package/dist/preview/renderTimegroupPreview.js +259 -236
- package/dist/preview/renderTimegroupPreview.js.map +1 -1
- package/dist/preview/renderTimegroupToCanvas.d.ts +5 -0
- package/dist/preview/renderTimegroupToCanvas.js +99 -489
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
- package/dist/preview/renderTimegroupToVideo.d.ts +1 -0
- package/dist/preview/renderTimegroupToVideo.js +80 -22
- package/dist/preview/renderTimegroupToVideo.js.map +1 -1
- package/dist/preview/renderers.js.map +1 -1
- package/dist/preview/rendering/inlineImages.js +56 -0
- package/dist/preview/rendering/inlineImages.js.map +1 -0
- package/dist/preview/rendering/renderToImage.d.ts +1 -0
- package/dist/preview/rendering/renderToImage.js +120 -0
- package/dist/preview/rendering/renderToImage.js.map +1 -0
- package/dist/preview/rendering/renderToImageForeignObject.js +135 -0
- package/dist/preview/rendering/renderToImageForeignObject.js.map +1 -0
- package/dist/preview/rendering/renderToImageNative.d.ts +1 -0
- package/dist/preview/rendering/renderToImageNative.js +129 -0
- package/dist/preview/rendering/renderToImageNative.js.map +1 -0
- package/dist/preview/rendering/svgSerializer.js +43 -0
- package/dist/preview/rendering/svgSerializer.js.map +1 -0
- package/dist/preview/rendering/types.d.ts +2 -0
- package/dist/preview/statsTrackingStrategy.js +3 -1
- package/dist/preview/statsTrackingStrategy.js.map +1 -1
- package/dist/preview/workers/WorkerPool.js +8 -57
- package/dist/preview/workers/WorkerPool.js.map +1 -1
- package/dist/render/EFRenderAPI.d.ts +35 -0
- package/dist/render/EFRenderAPI.js +1 -0
- package/dist/render/EFRenderAPI.js.map +1 -1
- package/dist/sandbox/PlaybackControls.d.ts +1 -0
- package/dist/sandbox/ScenarioRunner.d.ts +1 -0
- package/dist/sandbox/defineSandbox.d.ts +1 -0
- package/dist/sandbox/index.d.ts +3 -0
- package/dist/style.css +3 -0
- package/dist/transcoding/types/index.d.ts +6 -3
- package/package.json +2 -3
- package/test/EFVideo.framegen.browsertest.ts +8 -1
- package/test/profilingPlugin.ts +1 -3
- package/test/setup.ts +23 -1
- package/dist/EF_INTERACTIVE.js +0 -7
- package/dist/EF_INTERACTIVE.js.map +0 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +0 -50
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +0 -12
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +0 -104
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +0 -168
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +0 -46
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +0 -49
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +0 -30
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +0 -49
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +0 -47
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +0 -140
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +0 -1
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +0 -13
- package/dist/elements/EFMedia/shared/BufferUtils.js +0 -86
- package/dist/elements/EFMedia/shared/BufferUtils.js.map +0 -1
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +0 -17
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +0 -90
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +0 -80
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +0 -49
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +0 -58
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +0 -71
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +0 -52
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +0 -50
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +0 -109
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +0 -12
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +0 -97
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +0 -1
- package/dist/elements/SampleBuffer.d.ts +0 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvasEncoder.js","names":["_workerPool: WorkerPool | null","dataUrl: string"],"sources":["../../../src/preview/encoding/canvasEncoder.ts"],"sourcesContent":["/**\n * Canvas encoding orchestration with worker pool support.\n * \n * Supports caching via RenderContext:\n * - For ef-image/ef-waveform: caches by element + renderVersion\n * - For ef-video: uses direct capture API with source timestamp caching\n */\n\nimport { logger } from \"../logger.js\";\nimport { WorkerPool } from \"../workers/WorkerPool.js\";\nimport { getEncoderWorkerUrl } from \"../workers/encoderWorkerInline.js\";\nimport { encodeCanvasOnMainThread } from \"./mainThreadEncoder.js\";\nimport { encodeCanvasInWorker } from \"./workerEncoder.js\";\nimport type { CanvasEncodeResult, CanvasEncodeOptions } from \"./types.js\";\nimport type { EFVideo } from \"../../elements/EFVideo.js\";\nimport type { EFSurface } from \"../../elements/EFSurface.js\";\n\n// Module-level worker pool state\nlet _workerPool: WorkerPool | null = null;\nlet _workerPoolWarningLogged = false;\n\n/**\n * Get or create the worker pool for canvas encoding.\n * Returns null if workers are not available.\n */\nfunction getWorkerPool(): WorkerPool | null {\n if (_workerPool) {\n return _workerPool;\n }\n\n // Check if workers are available\n if (\n typeof Worker === \"undefined\" ||\n typeof OffscreenCanvas === \"undefined\" ||\n typeof createImageBitmap === \"undefined\"\n ) {\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n logger.warn(\n \"[canvasEncoder] Web Workers or OffscreenCanvas not available, using main thread fallback\",\n );\n }\n return null;\n }\n\n try {\n // Use inline worker URL - this works in any bundler environment\n // because the worker code is embedded in the bundle as a blob URL\n const workerUrl = getEncoderWorkerUrl();\n \n _workerPool = new WorkerPool(workerUrl);\n \n // Check if workers were actually created\n if (!_workerPool.isAvailable()) {\n const reason = _workerPool.workerCount === 0 \n ? \"no workers created (check console for errors)\" \n : \"workers not available\";\n _workerPool = null;\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n logger.warn(\n `[canvasEncoder] Worker pool initialization failed (${reason}), using main thread fallback`,\n );\n }\n }\n } catch (error) {\n _workerPool = null;\n if (!_workerPoolWarningLogged) {\n _workerPoolWarningLogged = true;\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.warn(\n `[canvasEncoder] Failed to create worker pool: ${errorMessage} - using main thread fallback`,\n );\n }\n }\n\n return _workerPool;\n}\n\n/**\n * Check if an element is an EFVideo.\n */\nfunction isEFVideo(element: Element): element is EFVideo {\n return element.tagName === \"EF-VIDEO\";\n}\n\n/**\n * Check if an element is an EFSurface.\n */\nfunction isEFSurface(element: Element): element is EFSurface {\n return element.tagName === \"EF-SURFACE\";\n}\n\n/**\n * Encode canvases to data URLs in parallel using worker pool.\n * Falls back to main thread encoding if workers are unavailable.\n * \n * When RenderContext and sourceMap are provided:\n * - Checks cache for static elements (ef-image, ef-waveform)\n * - Uses direct capture API for ef-video elements\n * - Shares cached frames for ef-surface elements targeting ef-video\n * \n * @param canvases - Array of canvases to encode\n * @param options - Encoding options including optional renderContext and sourceMap\n * @returns Promise resolving to array of encoded results\n */\nexport async function encodeCanvasesInParallel(\n canvases: HTMLCanvasElement[],\n options: CanvasEncodeOptions = {},\n): Promise<CanvasEncodeResult[]> {\n const { scale: canvasScale = 1, renderContext, sourceMap } = options;\n const workerPool = getWorkerPool();\n\n // Helper to encode a single canvas (with caching)\n const encodeCanvas = async (canvas: HTMLCanvasElement): Promise<CanvasEncodeResult | null> => {\n try {\n if (canvas.width === 0 || canvas.height === 0) {\n return null;\n }\n\n const preserveAlpha = canvas.dataset.preserveAlpha === \"true\";\n const sourceElement = sourceMap?.get(canvas);\n\n // OPTIMIZATION: Check RenderContext cache for static elements\n if (renderContext && sourceElement) {\n // For ef-video, use direct capture API\n if (isEFVideo(sourceElement)) {\n const sourceTimeMs = sourceElement.currentSourceTimeMs;\n \n // Use direct capture API (bypasses frameTask)\n // Always use \"main\" quality for export - scrub track is only for preview scrubbing\n try {\n const frame = await sourceElement.captureFrameAtSourceTime(sourceTimeMs, { quality: \"main\" });\n return { canvas, dataUrl: frame.dataUrl, preserveAlpha: false };\n } catch (e) {\n // Fall back to normal encoding if direct capture fails\n logger.warn(\"[canvasEncoder] Direct capture failed, falling back to canvas encoding:\", e);\n }\n }\n \n // For ef-surface targeting ef-video, share the video's cached frame\n if (isEFSurface(sourceElement)) {\n const target = sourceElement.targetElement;\n if (target && isEFVideo(target as Element)) {\n const videoTarget = target as unknown as EFVideo;\n const sourceTimeMs = videoTarget.currentSourceTimeMs;\n const cached = renderContext.getCachedVideoFrame(videoTarget, sourceTimeMs);\n if (cached) {\n return { canvas, dataUrl: cached.dataUrl, preserveAlpha: false };\n }\n \n // Capture from the target video\n // Always use \"main\" quality for export\n try {\n const frame = await videoTarget.captureFrameAtSourceTime(sourceTimeMs, { quality: \"main\" });\n renderContext.setCachedVideoFrame(videoTarget, sourceTimeMs, frame);\n return { canvas, dataUrl: frame.dataUrl, preserveAlpha: false };\n } catch (e) {\n logger.warn(\"[canvasEncoder] Direct capture for surface target failed:\", e);\n }\n }\n }\n \n // For static elements (ef-image, ef-waveform), check version-based cache\n const cachedDataUrl = renderContext.getCachedCanvasDataUrl(sourceElement);\n if (cachedDataUrl) {\n return { canvas, dataUrl: cachedDataUrl, preserveAlpha };\n }\n }\n\n // Standard encoding path (fallback when no RenderContext cache)\n let sourceCanvas = canvas;\n\n // Handle canvas scaling on main thread before encoding\n if (canvasScale < 1) {\n const scaledWidth = Math.floor(canvas.width * canvasScale);\n const scaledHeight = Math.floor(canvas.height * canvasScale);\n const scaledCanvas = document.createElement(\"canvas\");\n scaledCanvas.width = scaledWidth;\n scaledCanvas.height = scaledHeight;\n const scaledCtx = scaledCanvas.getContext(\"2d\");\n if (scaledCtx) {\n scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);\n sourceCanvas = scaledCanvas;\n }\n }\n\n let dataUrl: string;\n \n if (workerPool) {\n // Encode in worker\n dataUrl = await workerPool.execute((worker) =>\n encodeCanvasInWorker(worker, sourceCanvas, preserveAlpha),\n );\n } else {\n // Main thread fallback - warning already logged once in getWorkerPool()\n const encoded = encodeCanvasOnMainThread(sourceCanvas, canvasScale);\n if (!encoded) return null;\n dataUrl = encoded.dataUrl;\n }\n\n // Cache the result for static elements\n if (renderContext && sourceElement) {\n renderContext.setCachedCanvasDataUrl(sourceElement, dataUrl);\n }\n\n return { canvas, dataUrl, preserveAlpha };\n } catch (error) {\n // Fallback to main thread if worker encoding fails\n logger.warn(\"[canvasEncoder] Worker encoding failed, using main thread fallback:\", error);\n const encoded = encodeCanvasOnMainThread(canvas, canvasScale);\n if (encoded) {\n logger.warn(\"[canvasEncoder] Main thread fallback succeeded\");\n return { canvas, ...encoded };\n }\n \n // Cross-origin canvas or other error - skip\n logger.warn(\"[canvasEncoder] Main thread encoding also failed, skipping canvas:\", error);\n return null;\n }\n };\n\n // Encode all canvases in parallel\n const encodingTasks = canvases.map(encodeCanvas);\n const encodedResults = await Promise.all(encodingTasks);\n const validResults = encodedResults.filter(\n (r): r is CanvasEncodeResult => r !== null,\n );\n return validResults;\n}\n\n/**\n * Reset the worker pool state (for testing).\n */\nexport function resetWorkerPool(): void {\n if (_workerPool) {\n _workerPool.terminate();\n _workerPool = null;\n }\n _workerPoolWarningLogged = false;\n}\n"],"mappings":";;;;;;;AAkBA,IAAIA,cAAiC;AACrC,IAAI,2BAA2B;;;;;AAM/B,SAAS,gBAAmC;AAC1C,KAAI,YACF,QAAO;AAIT,KACE,OAAO,WAAW,eAClB,OAAO,oBAAoB,eAC3B,OAAO,sBAAsB,aAC7B;AACA,MAAI,CAAC,0BAA0B;AAC7B,8BAA2B;AAC3B,UAAO,KACL,2FACD;;AAEH,SAAO;;AAGT,KAAI;AAKF,gBAAc,IAAI,WAFA,qBAAqB,CAEA;AAGvC,MAAI,CAAC,YAAY,aAAa,EAAE;GAC9B,MAAM,SAAS,YAAY,gBAAgB,IACvC,kDACA;AACJ,iBAAc;AACd,OAAI,CAAC,0BAA0B;AAC7B,+BAA2B;AAC3B,WAAO,KACL,sDAAsD,OAAO,+BAC9D;;;UAGE,OAAO;AACd,gBAAc;AACd,MAAI,CAAC,0BAA0B;AAC7B,8BAA2B;GAC3B,MAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAC3E,UAAO,KACL,iDAAiD,aAAa,+BAC/D;;;AAIL,QAAO;;;;;AAMT,SAAS,UAAU,SAAsC;AACvD,QAAO,QAAQ,YAAY;;;;;AAM7B,SAAS,YAAY,SAAwC;AAC3D,QAAO,QAAQ,YAAY;;;;;;;;;;;;;;;AAgB7B,eAAsB,yBACpB,UACA,UAA+B,EAAE,EACF;CAC/B,MAAM,EAAE,OAAO,cAAc,GAAG,eAAe,cAAc;CAC7D,MAAM,aAAa,eAAe;CAGlC,MAAM,eAAe,OAAO,WAAkE;AAC5F,MAAI;AACF,OAAI,OAAO,UAAU,KAAK,OAAO,WAAW,EAC1C,QAAO;GAGT,MAAM,gBAAgB,OAAO,QAAQ,kBAAkB;GACvD,MAAM,gBAAgB,WAAW,IAAI,OAAO;AAG5C,OAAI,iBAAiB,eAAe;AAElC,QAAI,UAAU,cAAc,EAAE;KAC5B,MAAM,eAAe,cAAc;AAInC,SAAI;AAEF,aAAO;OAAE;OAAQ,UADH,MAAM,cAAc,yBAAyB,cAAc,EAAE,SAAS,QAAQ,CAAC,EAC7D;OAAS,eAAe;OAAO;cACxD,GAAG;AAEV,aAAO,KAAK,2EAA2E,EAAE;;;AAK7F,QAAI,YAAY,cAAc,EAAE;KAC9B,MAAM,SAAS,cAAc;AAC7B,SAAI,UAAU,UAAU,OAAkB,EAAE;MAC1C,MAAM,cAAc;MACpB,MAAM,eAAe,YAAY;MACjC,MAAM,SAAS,cAAc,oBAAoB,aAAa,aAAa;AAC3E,UAAI,OACF,QAAO;OAAE;OAAQ,SAAS,OAAO;OAAS,eAAe;OAAO;AAKlE,UAAI;OACF,MAAM,QAAQ,MAAM,YAAY,yBAAyB,cAAc,EAAE,SAAS,QAAQ,CAAC;AAC3F,qBAAc,oBAAoB,aAAa,cAAc,MAAM;AACnE,cAAO;QAAE;QAAQ,SAAS,MAAM;QAAS,eAAe;QAAO;eACxD,GAAG;AACV,cAAO,KAAK,6DAA6D,EAAE;;;;IAMjF,MAAM,gBAAgB,cAAc,uBAAuB,cAAc;AACzE,QAAI,cACF,QAAO;KAAE;KAAQ,SAAS;KAAe;KAAe;;GAK5D,IAAI,eAAe;AAGnB,OAAI,cAAc,GAAG;IACnB,MAAM,cAAc,KAAK,MAAM,OAAO,QAAQ,YAAY;IAC1D,MAAM,eAAe,KAAK,MAAM,OAAO,SAAS,YAAY;IAC5D,MAAM,eAAe,SAAS,cAAc,SAAS;AACrD,iBAAa,QAAQ;AACrB,iBAAa,SAAS;IACtB,MAAM,YAAY,aAAa,WAAW,KAAK;AAC/C,QAAI,WAAW;AACb,eAAU,UAAU,QAAQ,GAAG,GAAG,aAAa,aAAa;AAC5D,oBAAe;;;GAInB,IAAIC;AAEJ,OAAI,WAEF,WAAU,MAAM,WAAW,SAAS,WAClC,qBAAqB,QAAQ,cAAc,cAAc,CAC1D;QACI;IAEL,MAAM,UAAU,yBAAyB,cAAc,YAAY;AACnE,QAAI,CAAC,QAAS,QAAO;AACrB,cAAU,QAAQ;;AAIpB,OAAI,iBAAiB,cACnB,eAAc,uBAAuB,eAAe,QAAQ;AAG9D,UAAO;IAAE;IAAQ;IAAS;IAAe;WAClC,OAAO;AAEd,UAAO,KAAK,uEAAuE,MAAM;GACzF,MAAM,UAAU,yBAAyB,QAAQ,YAAY;AAC7D,OAAI,SAAS;AACX,WAAO,KAAK,iDAAiD;AAC7D,WAAO;KAAE;KAAQ,GAAG;KAAS;;AAI/B,UAAO,KAAK,sEAAsE,MAAM;AACxF,UAAO;;;CAKX,MAAM,gBAAgB,SAAS,IAAI,aAAa;AAKhD,SAJuB,MAAM,QAAQ,IAAI,cAAc,EACnB,QACjC,MAA+B,MAAM,KACvC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/preview/encoding/mainThreadEncoder.ts
|
|
2
|
+
const JPEG_QUALITY_HIGH = .92;
|
|
3
|
+
const JPEG_QUALITY_MEDIUM = .85;
|
|
4
|
+
/**
|
|
5
|
+
* Encode a single canvas to a data URL on the main thread (fallback).
|
|
6
|
+
* @param canvas - The canvas to encode
|
|
7
|
+
* @param canvasScale - Scale factor for encoding (default: 1)
|
|
8
|
+
* @returns Encoded result or null if encoding fails
|
|
9
|
+
*/
|
|
10
|
+
function encodeCanvasOnMainThread(canvas, canvasScale) {
|
|
11
|
+
try {
|
|
12
|
+
if (canvas.width === 0 || canvas.height === 0) return null;
|
|
13
|
+
const preserveAlpha = canvas.dataset.preserveAlpha === "true";
|
|
14
|
+
let dataUrl;
|
|
15
|
+
if (canvasScale < 1) {
|
|
16
|
+
const scaledWidth = Math.floor(canvas.width * canvasScale);
|
|
17
|
+
const scaledHeight = Math.floor(canvas.height * canvasScale);
|
|
18
|
+
const scaledCanvas = document.createElement("canvas");
|
|
19
|
+
scaledCanvas.width = scaledWidth;
|
|
20
|
+
scaledCanvas.height = scaledHeight;
|
|
21
|
+
const scaledCtx = scaledCanvas.getContext("2d");
|
|
22
|
+
if (scaledCtx) {
|
|
23
|
+
scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);
|
|
24
|
+
const quality = canvasScale < .5 ? JPEG_QUALITY_MEDIUM : JPEG_QUALITY_HIGH;
|
|
25
|
+
dataUrl = preserveAlpha ? scaledCanvas.toDataURL("image/png") : scaledCanvas.toDataURL("image/jpeg", quality);
|
|
26
|
+
} else dataUrl = preserveAlpha ? canvas.toDataURL("image/png") : canvas.toDataURL("image/jpeg", JPEG_QUALITY_HIGH);
|
|
27
|
+
} else dataUrl = preserveAlpha ? canvas.toDataURL("image/png") : canvas.toDataURL("image/jpeg", JPEG_QUALITY_HIGH);
|
|
28
|
+
return {
|
|
29
|
+
dataUrl,
|
|
30
|
+
preserveAlpha
|
|
31
|
+
};
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { encodeCanvasOnMainThread };
|
|
39
|
+
//# sourceMappingURL=mainThreadEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mainThreadEncoder.js","names":["dataUrl: string"],"sources":["../../../src/preview/encoding/mainThreadEncoder.ts"],"sourcesContent":["/**\n * Main thread canvas encoding (fallback implementation).\n */\n\nimport type { CanvasEncodeResult } from \"./types.js\";\n\n// JPEG quality constants\nexport const JPEG_QUALITY_HIGH = 0.92;\nexport const JPEG_QUALITY_MEDIUM = 0.85;\n\n/**\n * Encode a single canvas to a data URL on the main thread (fallback).\n * @param canvas - The canvas to encode\n * @param canvasScale - Scale factor for encoding (default: 1)\n * @returns Encoded result or null if encoding fails\n */\nexport function encodeCanvasOnMainThread(\n canvas: HTMLCanvasElement,\n canvasScale: number,\n): { dataUrl: string; preserveAlpha: boolean } | null {\n try {\n if (canvas.width === 0 || canvas.height === 0) {\n return null;\n }\n\n const preserveAlpha = canvas.dataset.preserveAlpha === \"true\";\n let dataUrl: string;\n\n if (canvasScale < 1) {\n // Scale down canvas before encoding\n const scaledWidth = Math.floor(canvas.width * canvasScale);\n const scaledHeight = Math.floor(canvas.height * canvasScale);\n const scaledCanvas = document.createElement(\"canvas\");\n scaledCanvas.width = scaledWidth;\n scaledCanvas.height = scaledHeight;\n const scaledCtx = scaledCanvas.getContext(\"2d\");\n if (scaledCtx) {\n scaledCtx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);\n const quality = canvasScale < 0.5 ? JPEG_QUALITY_MEDIUM : JPEG_QUALITY_HIGH;\n dataUrl = preserveAlpha\n ? scaledCanvas.toDataURL(\"image/png\")\n : scaledCanvas.toDataURL(\"image/jpeg\", quality);\n } else {\n dataUrl = preserveAlpha\n ? canvas.toDataURL(\"image/png\")\n : canvas.toDataURL(\"image/jpeg\", JPEG_QUALITY_HIGH);\n }\n } else {\n dataUrl = preserveAlpha\n ? canvas.toDataURL(\"image/png\")\n : canvas.toDataURL(\"image/jpeg\", JPEG_QUALITY_HIGH);\n }\n\n return { dataUrl, preserveAlpha };\n } catch (e) {\n // Cross-origin canvas or other error - skip\n return null;\n }\n}\n"],"mappings":";AAOA,MAAa,oBAAoB;AACjC,MAAa,sBAAsB;;;;;;;AAQnC,SAAgB,yBACd,QACA,aACoD;AACpD,KAAI;AACF,MAAI,OAAO,UAAU,KAAK,OAAO,WAAW,EAC1C,QAAO;EAGT,MAAM,gBAAgB,OAAO,QAAQ,kBAAkB;EACvD,IAAIA;AAEJ,MAAI,cAAc,GAAG;GAEnB,MAAM,cAAc,KAAK,MAAM,OAAO,QAAQ,YAAY;GAC1D,MAAM,eAAe,KAAK,MAAM,OAAO,SAAS,YAAY;GAC5D,MAAM,eAAe,SAAS,cAAc,SAAS;AACrD,gBAAa,QAAQ;AACrB,gBAAa,SAAS;GACtB,MAAM,YAAY,aAAa,WAAW,KAAK;AAC/C,OAAI,WAAW;AACb,cAAU,UAAU,QAAQ,GAAG,GAAG,aAAa,aAAa;IAC5D,MAAM,UAAU,cAAc,KAAM,sBAAsB;AAC1D,cAAU,gBACN,aAAa,UAAU,YAAY,GACnC,aAAa,UAAU,cAAc,QAAQ;SAEjD,WAAU,gBACN,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,kBAAkB;QAGvD,WAAU,gBACN,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,kBAAkB;AAGvD,SAAO;GAAE;GAAS;GAAe;UAC1B,GAAG;AAEV,SAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../RenderContext.js";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/preview/encoding/workerEncoder.ts
|
|
2
|
+
/**
|
|
3
|
+
* Worker-based canvas encoding.
|
|
4
|
+
*/
|
|
5
|
+
const WORKER_TASK_TIMEOUT_MS = 3e4;
|
|
6
|
+
/**
|
|
7
|
+
* Encode a canvas using a worker.
|
|
8
|
+
* @param worker - The worker to use for encoding
|
|
9
|
+
* @param canvas - The canvas to encode
|
|
10
|
+
* @param preserveAlpha - Whether to preserve alpha channel (PNG vs JPEG)
|
|
11
|
+
* @returns Promise resolving to the encoded data URL
|
|
12
|
+
*/
|
|
13
|
+
async function encodeCanvasInWorker(worker, canvas, preserveAlpha) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const taskId = `task-${Date.now()}-${Math.random()}-${performance.now()}`;
|
|
16
|
+
let timeoutId = null;
|
|
17
|
+
const cleanup = () => {
|
|
18
|
+
if (timeoutId !== null) {
|
|
19
|
+
clearTimeout(timeoutId);
|
|
20
|
+
timeoutId = null;
|
|
21
|
+
}
|
|
22
|
+
worker.removeEventListener("message", messageHandler);
|
|
23
|
+
worker.removeEventListener("messageerror", messageErrorHandler);
|
|
24
|
+
};
|
|
25
|
+
const messageHandler = (event) => {
|
|
26
|
+
const result = event.data;
|
|
27
|
+
if (result.taskId === taskId) {
|
|
28
|
+
cleanup();
|
|
29
|
+
if (result.error) reject(/* @__PURE__ */ new Error(`Worker encoding failed: ${result.error}`));
|
|
30
|
+
else resolve(result.dataUrl);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const messageErrorHandler = () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
reject(/* @__PURE__ */ new Error("Worker message error"));
|
|
36
|
+
};
|
|
37
|
+
worker.addEventListener("message", messageHandler);
|
|
38
|
+
worker.addEventListener("messageerror", messageErrorHandler);
|
|
39
|
+
timeoutId = window.setTimeout(() => {
|
|
40
|
+
cleanup();
|
|
41
|
+
reject(/* @__PURE__ */ new Error("Worker task timed out"));
|
|
42
|
+
}, WORKER_TASK_TIMEOUT_MS);
|
|
43
|
+
createImageBitmap(canvas).then((bitmap) => {
|
|
44
|
+
worker.postMessage({
|
|
45
|
+
taskId,
|
|
46
|
+
bitmap,
|
|
47
|
+
preserveAlpha
|
|
48
|
+
}, [bitmap]);
|
|
49
|
+
}).catch((error) => {
|
|
50
|
+
cleanup();
|
|
51
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { encodeCanvasInWorker };
|
|
58
|
+
//# sourceMappingURL=workerEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerEncoder.js","names":["timeoutId: number | null"],"sources":["../../../src/preview/encoding/workerEncoder.ts"],"sourcesContent":["/**\n * Worker-based canvas encoding.\n */\n\nconst WORKER_TASK_TIMEOUT_MS = 30000;\n\n/**\n * Encode a canvas using a worker.\n * @param worker - The worker to use for encoding\n * @param canvas - The canvas to encode\n * @param preserveAlpha - Whether to preserve alpha channel (PNG vs JPEG)\n * @returns Promise resolving to the encoded data URL\n */\nexport async function encodeCanvasInWorker(\n worker: Worker,\n canvas: HTMLCanvasElement,\n preserveAlpha: boolean,\n): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const taskId = `task-${Date.now()}-${Math.random()}-${performance.now()}`;\n let timeoutId: number | null = null;\n\n const cleanup = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n worker.removeEventListener(\"message\", messageHandler);\n worker.removeEventListener(\"messageerror\", messageErrorHandler);\n };\n\n const messageHandler = (event: MessageEvent) => {\n const result = event.data as { taskId: string; dataUrl: string; error?: string };\n if (result.taskId === taskId) {\n cleanup();\n if (result.error) {\n reject(new Error(`Worker encoding failed: ${result.error}`));\n } else {\n resolve(result.dataUrl);\n }\n }\n };\n\n const messageErrorHandler = () => {\n cleanup();\n reject(new Error(\"Worker message error\"));\n };\n\n worker.addEventListener(\"message\", messageHandler);\n worker.addEventListener(\"messageerror\", messageErrorHandler);\n\n // Set timeout to detect if worker never responds\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"Worker task timed out\"));\n }, WORKER_TASK_TIMEOUT_MS);\n\n // Create ImageBitmap from canvas\n createImageBitmap(canvas)\n .then((bitmap) => {\n // Transfer bitmap to worker (zero-copy)\n worker.postMessage(\n {\n taskId,\n bitmap,\n preserveAlpha,\n },\n [bitmap],\n );\n })\n .catch((error) => {\n cleanup();\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n });\n}\n"],"mappings":";;;;AAIA,MAAM,yBAAyB;;;;;;;;AAS/B,eAAsB,qBACpB,QACA,QACA,eACiB;AACjB,QAAO,IAAI,SAAiB,SAAS,WAAW;EAC9C,MAAM,SAAS,QAAQ,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,YAAY,KAAK;EACvE,IAAIA,YAA2B;EAE/B,MAAM,gBAAgB;AACpB,OAAI,cAAc,MAAM;AACtB,iBAAa,UAAU;AACvB,gBAAY;;AAEd,UAAO,oBAAoB,WAAW,eAAe;AACrD,UAAO,oBAAoB,gBAAgB,oBAAoB;;EAGjE,MAAM,kBAAkB,UAAwB;GAC9C,MAAM,SAAS,MAAM;AACrB,OAAI,OAAO,WAAW,QAAQ;AAC5B,aAAS;AACT,QAAI,OAAO,MACT,wBAAO,IAAI,MAAM,2BAA2B,OAAO,QAAQ,CAAC;QAE5D,SAAQ,OAAO,QAAQ;;;EAK7B,MAAM,4BAA4B;AAChC,YAAS;AACT,0BAAO,IAAI,MAAM,uBAAuB,CAAC;;AAG3C,SAAO,iBAAiB,WAAW,eAAe;AAClD,SAAO,iBAAiB,gBAAgB,oBAAoB;AAG5D,cAAY,OAAO,iBAAiB;AAClC,YAAS;AACT,0BAAO,IAAI,MAAM,wBAAwB,CAAC;KACzC,uBAAuB;AAG1B,oBAAkB,OAAO,CACtB,MAAM,WAAW;AAEhB,UAAO,YACL;IACE;IACA;IACA;IACD,EACD,CAAC,OAAO,CACT;IACD,CACD,OAAO,UAAU;AAChB,YAAS;AACT,UAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;IACjE;GACJ"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/preview/logger.ts
|
|
2
|
+
const LOG_LEVELS = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
error: 3,
|
|
7
|
+
silent: 4
|
|
8
|
+
};
|
|
9
|
+
function getLogLevel() {
|
|
10
|
+
if (typeof globalThis !== "undefined" && "EF_LOG_LEVEL" in globalThis) {
|
|
11
|
+
const level = globalThis.EF_LOG_LEVEL;
|
|
12
|
+
if (level && level in LOG_LEVELS) return level;
|
|
13
|
+
}
|
|
14
|
+
if (typeof process !== "undefined" && process.env?.EF_LOG_LEVEL) {
|
|
15
|
+
const level = process.env.EF_LOG_LEVEL;
|
|
16
|
+
if (level in LOG_LEVELS) return level;
|
|
17
|
+
}
|
|
18
|
+
return "silent";
|
|
19
|
+
}
|
|
20
|
+
function shouldLog(level) {
|
|
21
|
+
const currentLevel = getLogLevel();
|
|
22
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
|
|
23
|
+
}
|
|
24
|
+
const logger = {
|
|
25
|
+
debug: (...args) => {
|
|
26
|
+
if (shouldLog("debug")) console.log(...args);
|
|
27
|
+
},
|
|
28
|
+
info: (...args) => {
|
|
29
|
+
if (shouldLog("info")) console.log(...args);
|
|
30
|
+
},
|
|
31
|
+
warn: (...args) => {
|
|
32
|
+
if (shouldLog("warn")) console.warn(...args);
|
|
33
|
+
},
|
|
34
|
+
error: (...args) => {
|
|
35
|
+
if (shouldLog("error")) console.error(...args);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { logger };
|
|
41
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","names":["LOG_LEVELS: Record<LogLevel, number>"],"sources":["../../src/preview/logger.ts"],"sourcesContent":["/**\n * Centralized logging utility for the preview module.\n * \n * Logging is disabled by default. To enable logging, set:\n * - Environment variable: EF_LOG_LEVEL=debug (or info, warn, error)\n * - Global flag: globalThis.EF_LOG_LEVEL = 'debug'\n * \n * Log levels (in order of verbosity):\n * - debug: All logs including performance metrics\n * - info: Informational messages\n * - warn: Warnings\n * - error: Errors only\n * - silent: No logging (default)\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\nfunction getLogLevel(): LogLevel {\n // Check global flag first\n if (typeof globalThis !== 'undefined' && 'EF_LOG_LEVEL' in globalThis) {\n const level = (globalThis as { EF_LOG_LEVEL?: string }).EF_LOG_LEVEL;\n if (level && level in LOG_LEVELS) {\n return level as LogLevel;\n }\n }\n \n // Check environment variable (works in Node.js and some bundlers)\n if (typeof process !== 'undefined' && process.env?.EF_LOG_LEVEL) {\n const level = process.env.EF_LOG_LEVEL;\n if (level in LOG_LEVELS) {\n return level as LogLevel;\n }\n }\n \n // Default to silent\n return 'silent';\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n const currentLevel = getLogLevel();\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\nexport const logger = {\n debug: (...args: unknown[]): void => {\n if (shouldLog('debug')) {\n console.log(...args);\n }\n },\n \n info: (...args: unknown[]): void => {\n if (shouldLog('info')) {\n console.log(...args);\n }\n },\n \n warn: (...args: unknown[]): void => {\n if (shouldLog('warn')) {\n console.warn(...args);\n }\n },\n \n error: (...args: unknown[]): void => {\n if (shouldLog('error')) {\n console.error(...args);\n }\n },\n};\n"],"mappings":";AAiBA,MAAMA,aAAuC;CAC3C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,QAAQ;CACT;AAED,SAAS,cAAwB;AAE/B,KAAI,OAAO,eAAe,eAAe,kBAAkB,YAAY;EACrE,MAAM,QAAS,WAAyC;AACxD,MAAI,SAAS,SAAS,WACpB,QAAO;;AAKX,KAAI,OAAO,YAAY,eAAe,QAAQ,KAAK,cAAc;EAC/D,MAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,SAAS,WACX,QAAO;;AAKX,QAAO;;AAGT,SAAS,UAAU,OAA0B;CAC3C,MAAM,eAAe,aAAa;AAClC,QAAO,WAAW,UAAU,WAAW;;AAGzC,MAAa,SAAS;CACpB,QAAQ,GAAG,SAA0B;AACnC,MAAI,UAAU,QAAQ,CACpB,SAAQ,IAAI,GAAG,KAAK;;CAIxB,OAAO,GAAG,SAA0B;AAClC,MAAI,UAAU,OAAO,CACnB,SAAQ,IAAI,GAAG,KAAK;;CAIxB,OAAO,GAAG,SAA0B;AAClC,MAAI,UAAU,OAAO,CACnB,SAAQ,KAAK,GAAG,KAAK;;CAIzB,QAAQ,GAAG,SAA0B;AACnC,MAAI,UAAU,QAAQ,CACpB,SAAQ,MAAM,GAAG,KAAK;;CAG3B"}
|
|
@@ -48,8 +48,13 @@ function setPreviewPresentationMode(mode) {
|
|
|
48
48
|
/**
|
|
49
49
|
* Get the current render mode for HTML-to-canvas capture.
|
|
50
50
|
* Defaults to "native" if available, otherwise "foreignObject".
|
|
51
|
+
*
|
|
52
|
+
* Checks EF_NATIVE_RENDER URL parameter to force native mode when set.
|
|
51
53
|
*/
|
|
52
54
|
function getRenderMode() {
|
|
55
|
+
try {
|
|
56
|
+
if (new URLSearchParams(window.location.search).get("EF_NATIVE_RENDER") === "1") return isNativeCanvasApiAvailable() ? "native" : "foreignObject";
|
|
57
|
+
} catch {}
|
|
53
58
|
try {
|
|
54
59
|
const stored = localStorage.getItem(STORAGE_KEY_RENDER_MODE);
|
|
55
60
|
if (stored === "foreignObject" || stored === "native") return stored;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"previewSettings.js","names":["_nativeApiAvailable: boolean | null","VALID_NUMERIC_SCALES: number[]"],"sources":["../../src/preview/previewSettings.ts"],"sourcesContent":["/**\n * Preview settings module with localStorage persistence.\n * Manages configuration for the preview rendering system.\n */\n\nconst STORAGE_KEY_NATIVE_CANVAS_API = \"ef-preview-native-canvas-api-enabled\";\nconst STORAGE_KEY_PRESENTATION_MODE = \"ef-preview-presentation-mode\";\nconst STORAGE_KEY_RENDER_MODE = \"ef-preview-render-mode\";\nconst STORAGE_KEY_RESOLUTION_SCALE = \"ef-preview-resolution-scale\";\nconst STORAGE_KEY_SHOW_STATS = \"ef-preview-show-stats\";\n\n/**\n * Render mode for HTML-to-canvas capture operations.\n * - \"foreignObject\": SVG foreignObject serialization (fallback, works everywhere)\n * - \"native\": Chrome's experimental drawElementImage API (fastest when available)\n */\nexport type RenderMode = \"foreignObject\" | \"native\";\n\n/**\n * Preview resolution scale factor.\n * Controls how much to reduce the preview render resolution for better performance.\n * - 1: Full resolution (default)\n * - 0.75: 3/4 resolution\n * - 0.5: Half resolution\n * - 0.25: Quarter resolution\n * - \"auto\": Adaptive resolution that scales down during motion to prevent dropped frames,\n * and renders at full resolution when at rest\n */\nexport type PreviewResolutionScale = 1 | 0.75 | 0.5 | 0.25 | \"auto\";\n\n/**\n * Preview presentation mode determines how content is rendered in the workbench.\n * - \"clone\": Show a clone with computed styles applied (alias for \"computed\")\n * - \"dom\": Show the original DOM content directly (alias for \"original\")\n * - \"original\": Show the original DOM content directly\n * - \"computed\": Show a clone with computed styles applied\n * - \"canvas\": Render to canvas using the active rendering path\n */\nexport type PreviewPresentationMode = \"original\" | \"computed\" | \"canvas\" | \"clone\" | \"dom\";\n\n/**\n * Cached detection result for native HTML-in-Canvas API availability.\n * This is separate from the user preference - it detects browser capability.\n */\nlet _nativeApiAvailable: boolean | null = null;\n\n/**\n * Detect if the native HTML-in-Canvas API (drawElementImage) is available in this browser.\n * This checks browser capability, not user preference.\n * \n * The API is available in Chrome Canary with chrome://flags/#canvas-draw-element\n * @see https://github.com/WICG/html-in-canvas\n */\nexport function isNativeCanvasApiAvailable(): boolean {\n if (_nativeApiAvailable === null) {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n _nativeApiAvailable = ctx !== null && \"drawElementImage\" in ctx;\n }\n return _nativeApiAvailable;\n}\n\n/**\n * Check if the native Canvas API is enabled by the user.\n * Returns true only if:\n * 1. The API is available in the browser\n * 2. The user has not explicitly disabled it\n * \n * Default is enabled when available (opt-out model).\n */\nexport function isNativeCanvasApiEnabled(): boolean {\n if (!isNativeCanvasApiAvailable()) {\n return false;\n }\n \n try {\n const stored = localStorage.getItem(STORAGE_KEY_NATIVE_CANVAS_API);\n // Default to true (enabled) when available, unless explicitly disabled\n if (stored === null) {\n return true;\n }\n return stored === \"true\";\n } catch {\n // localStorage not available (e.g., private browsing)\n return true;\n }\n}\n\n/**\n * Set whether the native Canvas API should be used (when available).\n * Persists to localStorage and dispatches a change event.\n */\nexport function setNativeCanvasApiEnabled(enabled: boolean): void {\n try {\n localStorage.setItem(STORAGE_KEY_NATIVE_CANVAS_API, String(enabled));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { nativeCanvasApiEnabled: enabled }\n }));\n}\n\n/**\n * Get the current raw user preference (ignoring availability).\n * Returns null if no preference is set.\n */\nexport function getNativeCanvasApiPreference(): boolean | null {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_NATIVE_CANVAS_API);\n if (stored === null) {\n return null;\n }\n return stored === \"true\";\n } catch {\n return null;\n }\n}\n\n/**\n * Subscribe to preview settings changes.\n * @returns Unsubscribe function\n */\nexport function onPreviewSettingsChanged(\n callback: (detail: PreviewSettingsChangedDetail) => void\n): () => void {\n const handler = (event: Event) => {\n callback((event as CustomEvent).detail);\n };\n window.addEventListener(\"ef-preview-settings-changed\", handler);\n return () => window.removeEventListener(\"ef-preview-settings-changed\", handler);\n}\n\n/**\n * Detail object for preview settings change events.\n */\nexport interface PreviewSettingsChangedDetail {\n nativeCanvasApiEnabled?: boolean;\n presentationMode?: PreviewPresentationMode;\n renderMode?: RenderMode;\n resolutionScale?: PreviewResolutionScale;\n showStats?: boolean;\n}\n\n/**\n * Get the current preview presentation mode.\n * Defaults to \"original\" if not set.\n */\nexport function getPreviewPresentationMode(): PreviewPresentationMode {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_PRESENTATION_MODE);\n if (stored === \"original\" || stored === \"computed\" || stored === \"canvas\") {\n return stored;\n }\n return \"original\";\n } catch {\n return \"original\";\n }\n}\n\n/**\n * Set the preview presentation mode.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setPreviewPresentationMode(mode: PreviewPresentationMode): void {\n try {\n localStorage.setItem(STORAGE_KEY_PRESENTATION_MODE, mode);\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { presentationMode: mode }\n }));\n}\n\n/**\n * Get the current render mode for HTML-to-canvas capture.\n * Defaults to \"native\" if available, otherwise \"foreignObject\".\n */\nexport function getRenderMode(): RenderMode {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_RENDER_MODE);\n if (stored === \"foreignObject\" || stored === \"native\") {\n return stored;\n }\n // Default: prefer native if available, otherwise foreignObject\n return isNativeCanvasApiAvailable() ? \"native\" : \"foreignObject\";\n } catch {\n return isNativeCanvasApiAvailable() ? \"native\" : \"foreignObject\";\n }\n}\n\n/**\n * Set the render mode for HTML-to-canvas capture.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setRenderMode(mode: RenderMode): void {\n try {\n localStorage.setItem(STORAGE_KEY_RENDER_MODE, mode);\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { renderMode: mode }\n }));\n}\n\n/**\n * Valid numeric resolution scale values.\n */\nconst VALID_NUMERIC_SCALES: number[] = [1, 0.75, 0.5, 0.25];\n\n/**\n * Get the current preview resolution scale.\n * Defaults to 1 (full resolution) if not set.\n */\nexport function getPreviewResolutionScale(): PreviewResolutionScale {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_RESOLUTION_SCALE);\n if (stored !== null) {\n // Check for \"auto\" string first\n if (stored === \"auto\") {\n return \"auto\";\n }\n // Then check numeric values\n const parsed = parseFloat(stored);\n if (VALID_NUMERIC_SCALES.includes(parsed)) {\n return parsed as PreviewResolutionScale;\n }\n }\n return 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Set the preview resolution scale.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setPreviewResolutionScale(scale: PreviewResolutionScale): void {\n try {\n localStorage.setItem(STORAGE_KEY_RESOLUTION_SCALE, String(scale));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { resolutionScale: scale }\n }));\n}\n\n/**\n * Get whether performance stats should be shown.\n * Defaults to false (stats hidden by default).\n */\nexport function getShowStats(): boolean {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_SHOW_STATS);\n return stored === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Set whether performance stats should be shown.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setShowStats(enabled: boolean): void {\n try {\n localStorage.setItem(STORAGE_KEY_SHOW_STATS, String(enabled));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { showStats: enabled }\n }));\n}\n\n"],"mappings":";AAMA,MAAM,gCAAgC;AACtC,MAAM,0BAA0B;AAChC,MAAM,+BAA+B;AACrC,MAAM,yBAAyB;;;;;AAmC/B,IAAIA,sBAAsC;;;;;;;;AAS1C,SAAgB,6BAAsC;AACpD,KAAI,wBAAwB,MAAM;EAEhC,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,wBAAsB,QAAQ,QAAQ,sBAAsB;;AAE9D,QAAO;;;;;;AA2FT,SAAgB,6BAAsD;AACpE,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,8BAA8B;AAClE,MAAI,WAAW,cAAc,WAAW,cAAc,WAAW,SAC/D,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;;;;;AAQX,SAAgB,2BAA2B,MAAqC;AAC9E,KAAI;AACF,eAAa,QAAQ,+BAA+B,KAAK;SACnD;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,kBAAkB,MAAM,EACnC,CAAC,CAAC;;;;;;AAOL,SAAgB,gBAA4B;AAC1C,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,wBAAwB;AAC5D,MAAI,WAAW,mBAAmB,WAAW,SAC3C,QAAO;AAGT,SAAO,4BAA4B,GAAG,WAAW;SAC3C;AACN,SAAO,4BAA4B,GAAG,WAAW;;;;;;;AAQrD,SAAgB,cAAc,MAAwB;AACpD,KAAI;AACF,eAAa,QAAQ,yBAAyB,KAAK;SAC7C;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,YAAY,MAAM,EAC7B,CAAC,CAAC;;;;;AAML,MAAMC,uBAAiC;CAAC;CAAG;CAAM;CAAK;CAAK;;;;;AAM3D,SAAgB,4BAAoD;AAClE,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,6BAA6B;AACjE,MAAI,WAAW,MAAM;AAEnB,OAAI,WAAW,OACb,QAAO;GAGT,MAAM,SAAS,WAAW,OAAO;AACjC,OAAI,qBAAqB,SAAS,OAAO,CACvC,QAAO;;AAGX,SAAO;SACD;AACN,SAAO;;;;;;;AAQX,SAAgB,0BAA0B,OAAqC;AAC7E,KAAI;AACF,eAAa,QAAQ,8BAA8B,OAAO,MAAM,CAAC;SAC3D;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,iBAAiB,OAAO,EACnC,CAAC,CAAC;;;;;;AAOL,SAAgB,eAAwB;AACtC,KAAI;AAEF,SADe,aAAa,QAAQ,uBAAuB,KACzC;SACZ;AACN,SAAO;;;;;;;AAQX,SAAgB,aAAa,SAAwB;AACnD,KAAI;AACF,eAAa,QAAQ,wBAAwB,OAAO,QAAQ,CAAC;SACvD;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,WAAW,SAAS,EAC/B,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"previewSettings.js","names":["_nativeApiAvailable: boolean | null","VALID_NUMERIC_SCALES: number[]"],"sources":["../../src/preview/previewSettings.ts"],"sourcesContent":["/**\n * Preview settings module with localStorage persistence.\n * Manages configuration for the preview rendering system.\n */\n\nconst STORAGE_KEY_NATIVE_CANVAS_API = \"ef-preview-native-canvas-api-enabled\";\nconst STORAGE_KEY_PRESENTATION_MODE = \"ef-preview-presentation-mode\";\nconst STORAGE_KEY_RENDER_MODE = \"ef-preview-render-mode\";\nconst STORAGE_KEY_RESOLUTION_SCALE = \"ef-preview-resolution-scale\";\nconst STORAGE_KEY_SHOW_STATS = \"ef-preview-show-stats\";\n\n/**\n * Render mode for HTML-to-canvas capture operations.\n * - \"foreignObject\": SVG foreignObject serialization (fallback, works everywhere)\n * - \"native\": Chrome's experimental drawElementImage API (fastest when available)\n */\nexport type RenderMode = \"foreignObject\" | \"native\";\n\n/**\n * Preview resolution scale factor.\n * Controls how much to reduce the preview render resolution for better performance.\n * - 1: Full resolution (default)\n * - 0.75: 3/4 resolution\n * - 0.5: Half resolution\n * - 0.25: Quarter resolution\n * - \"auto\": Adaptive resolution that scales down during motion to prevent dropped frames,\n * and renders at full resolution when at rest\n */\nexport type PreviewResolutionScale = 1 | 0.75 | 0.5 | 0.25 | \"auto\";\n\n/**\n * Preview presentation mode determines how content is rendered in the workbench.\n * - \"clone\": Show a clone with computed styles applied (alias for \"computed\")\n * - \"dom\": Show the original DOM content directly (alias for \"original\")\n * - \"original\": Show the original DOM content directly\n * - \"computed\": Show a clone with computed styles applied\n * - \"canvas\": Render to canvas using the active rendering path\n */\nexport type PreviewPresentationMode = \"original\" | \"computed\" | \"canvas\" | \"clone\" | \"dom\";\n\n/**\n * Cached detection result for native HTML-in-Canvas API availability.\n * This is separate from the user preference - it detects browser capability.\n */\nlet _nativeApiAvailable: boolean | null = null;\n\n/**\n * Detect if the native HTML-in-Canvas API (drawElementImage) is available in this browser.\n * This checks browser capability, not user preference.\n * \n * The API is available in Chrome Canary with chrome://flags/#canvas-draw-element\n * @see https://github.com/WICG/html-in-canvas\n */\nexport function isNativeCanvasApiAvailable(): boolean {\n if (_nativeApiAvailable === null) {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n _nativeApiAvailable = ctx !== null && \"drawElementImage\" in ctx;\n }\n return _nativeApiAvailable;\n}\n\n/**\n * Check if the native Canvas API is enabled by the user.\n * Returns true only if:\n * 1. The API is available in the browser\n * 2. The user has not explicitly disabled it\n * \n * Default is enabled when available (opt-out model).\n */\nexport function isNativeCanvasApiEnabled(): boolean {\n if (!isNativeCanvasApiAvailable()) {\n return false;\n }\n \n try {\n const stored = localStorage.getItem(STORAGE_KEY_NATIVE_CANVAS_API);\n // Default to true (enabled) when available, unless explicitly disabled\n if (stored === null) {\n return true;\n }\n return stored === \"true\";\n } catch {\n // localStorage not available (e.g., private browsing)\n return true;\n }\n}\n\n/**\n * Set whether the native Canvas API should be used (when available).\n * Persists to localStorage and dispatches a change event.\n */\nexport function setNativeCanvasApiEnabled(enabled: boolean): void {\n try {\n localStorage.setItem(STORAGE_KEY_NATIVE_CANVAS_API, String(enabled));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { nativeCanvasApiEnabled: enabled }\n }));\n}\n\n/**\n * Get the current raw user preference (ignoring availability).\n * Returns null if no preference is set.\n */\nexport function getNativeCanvasApiPreference(): boolean | null {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_NATIVE_CANVAS_API);\n if (stored === null) {\n return null;\n }\n return stored === \"true\";\n } catch {\n return null;\n }\n}\n\n/**\n * Subscribe to preview settings changes.\n * @returns Unsubscribe function\n */\nexport function onPreviewSettingsChanged(\n callback: (detail: PreviewSettingsChangedDetail) => void\n): () => void {\n const handler = (event: Event) => {\n callback((event as CustomEvent).detail);\n };\n window.addEventListener(\"ef-preview-settings-changed\", handler);\n return () => window.removeEventListener(\"ef-preview-settings-changed\", handler);\n}\n\n/**\n * Detail object for preview settings change events.\n */\nexport interface PreviewSettingsChangedDetail {\n nativeCanvasApiEnabled?: boolean;\n presentationMode?: PreviewPresentationMode;\n renderMode?: RenderMode;\n resolutionScale?: PreviewResolutionScale;\n showStats?: boolean;\n}\n\n/**\n * Get the current preview presentation mode.\n * Defaults to \"original\" if not set.\n */\nexport function getPreviewPresentationMode(): PreviewPresentationMode {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_PRESENTATION_MODE);\n if (stored === \"original\" || stored === \"computed\" || stored === \"canvas\") {\n return stored;\n }\n return \"original\";\n } catch {\n return \"original\";\n }\n}\n\n/**\n * Set the preview presentation mode.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setPreviewPresentationMode(mode: PreviewPresentationMode): void {\n try {\n localStorage.setItem(STORAGE_KEY_PRESENTATION_MODE, mode);\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { presentationMode: mode }\n }));\n}\n\n/**\n * Get the current render mode for HTML-to-canvas capture.\n * Defaults to \"native\" if available, otherwise \"foreignObject\".\n * \n * Checks EF_NATIVE_RENDER URL parameter to force native mode when set.\n */\nexport function getRenderMode(): RenderMode {\n // Check URL parameter first (CLI flag override)\n try {\n const urlParams = new URLSearchParams(window.location.search);\n if (urlParams.get(\"EF_NATIVE_RENDER\") === \"1\") {\n // Force native mode if available, otherwise fall back to foreignObject\n return isNativeCanvasApiAvailable() ? \"native\" : \"foreignObject\";\n }\n } catch {\n // URL parsing failed, continue with normal logic\n }\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY_RENDER_MODE);\n if (stored === \"foreignObject\" || stored === \"native\") {\n return stored;\n }\n // Default: prefer native if available, otherwise foreignObject\n return isNativeCanvasApiAvailable() ? \"native\" : \"foreignObject\";\n } catch {\n return isNativeCanvasApiAvailable() ? \"native\" : \"foreignObject\";\n }\n}\n\n/**\n * Set the render mode for HTML-to-canvas capture.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setRenderMode(mode: RenderMode): void {\n try {\n localStorage.setItem(STORAGE_KEY_RENDER_MODE, mode);\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { renderMode: mode }\n }));\n}\n\n/**\n * Valid numeric resolution scale values.\n */\nconst VALID_NUMERIC_SCALES: number[] = [1, 0.75, 0.5, 0.25];\n\n/**\n * Get the current preview resolution scale.\n * Defaults to 1 (full resolution) if not set.\n */\nexport function getPreviewResolutionScale(): PreviewResolutionScale {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_RESOLUTION_SCALE);\n if (stored !== null) {\n // Check for \"auto\" string first\n if (stored === \"auto\") {\n return \"auto\";\n }\n // Then check numeric values\n const parsed = parseFloat(stored);\n if (VALID_NUMERIC_SCALES.includes(parsed)) {\n return parsed as PreviewResolutionScale;\n }\n }\n return 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Set the preview resolution scale.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setPreviewResolutionScale(scale: PreviewResolutionScale): void {\n try {\n localStorage.setItem(STORAGE_KEY_RESOLUTION_SCALE, String(scale));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { resolutionScale: scale }\n }));\n}\n\n/**\n * Get whether performance stats should be shown.\n * Defaults to false (stats hidden by default).\n */\nexport function getShowStats(): boolean {\n try {\n const stored = localStorage.getItem(STORAGE_KEY_SHOW_STATS);\n return stored === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Set whether performance stats should be shown.\n * Persists to localStorage and dispatches a change event.\n */\nexport function setShowStats(enabled: boolean): void {\n try {\n localStorage.setItem(STORAGE_KEY_SHOW_STATS, String(enabled));\n } catch {\n // localStorage not available\n }\n \n // Dispatch event so components can react to the change\n window.dispatchEvent(new CustomEvent(\"ef-preview-settings-changed\", {\n detail: { showStats: enabled }\n }));\n}\n\n"],"mappings":";AAMA,MAAM,gCAAgC;AACtC,MAAM,0BAA0B;AAChC,MAAM,+BAA+B;AACrC,MAAM,yBAAyB;;;;;AAmC/B,IAAIA,sBAAsC;;;;;;;;AAS1C,SAAgB,6BAAsC;AACpD,KAAI,wBAAwB,MAAM;EAEhC,MAAM,MADS,SAAS,cAAc,SAAS,CAC5B,WAAW,KAAK;AACnC,wBAAsB,QAAQ,QAAQ,sBAAsB;;AAE9D,QAAO;;;;;;AA2FT,SAAgB,6BAAsD;AACpE,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,8BAA8B;AAClE,MAAI,WAAW,cAAc,WAAW,cAAc,WAAW,SAC/D,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;;;;;AAQX,SAAgB,2BAA2B,MAAqC;AAC9E,KAAI;AACF,eAAa,QAAQ,+BAA+B,KAAK;SACnD;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,kBAAkB,MAAM,EACnC,CAAC,CAAC;;;;;;;;AASL,SAAgB,gBAA4B;AAE1C,KAAI;AAEF,MADkB,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC/C,IAAI,mBAAmB,KAAK,IAExC,QAAO,4BAA4B,GAAG,WAAW;SAE7C;AAIR,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,wBAAwB;AAC5D,MAAI,WAAW,mBAAmB,WAAW,SAC3C,QAAO;AAGT,SAAO,4BAA4B,GAAG,WAAW;SAC3C;AACN,SAAO,4BAA4B,GAAG,WAAW;;;;;;;AAQrD,SAAgB,cAAc,MAAwB;AACpD,KAAI;AACF,eAAa,QAAQ,yBAAyB,KAAK;SAC7C;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,YAAY,MAAM,EAC7B,CAAC,CAAC;;;;;AAML,MAAMC,uBAAiC;CAAC;CAAG;CAAM;CAAK;CAAK;;;;;AAM3D,SAAgB,4BAAoD;AAClE,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,6BAA6B;AACjE,MAAI,WAAW,MAAM;AAEnB,OAAI,WAAW,OACb,QAAO;GAGT,MAAM,SAAS,WAAW,OAAO;AACjC,OAAI,qBAAqB,SAAS,OAAO,CACvC,QAAO;;AAGX,SAAO;SACD;AACN,SAAO;;;;;;;AAQX,SAAgB,0BAA0B,OAAqC;AAC7E,KAAI;AACF,eAAa,QAAQ,8BAA8B,OAAO,MAAM,CAAC;SAC3D;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,iBAAiB,OAAO,EACnC,CAAC,CAAC;;;;;;AAOL,SAAgB,eAAwB;AACtC,KAAI;AAEF,SADe,aAAa,QAAQ,uBAAuB,KACzC;SACZ;AACN,SAAO;;;;;;;AAQX,SAAgB,aAAa,SAAwB;AACnD,KAAI;AACF,eAAa,QAAQ,wBAAwB,OAAO,QAAQ,CAAC;SACvD;AAKR,QAAO,cAAc,IAAI,YAAY,+BAA+B,EAClE,QAAQ,EAAE,WAAW,SAAS,EAC/B,CAAC,CAAC"}
|
|
@@ -8,18 +8,22 @@ function isTemporal(el) {
|
|
|
8
8
|
/**
|
|
9
9
|
* Get temporal bounds for an element, treating invalid ranges as unbounded.
|
|
10
10
|
* Invalid range (end <= start) means element hasn't computed its duration yet.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: No caching - bounds are computed dynamically by timegroups based on
|
|
13
|
+
* composition mode (sequence/contain/fit) and may change between frames.
|
|
11
14
|
*/
|
|
12
15
|
function getTemporalBounds(el) {
|
|
13
16
|
if (!isTemporal(el)) return {
|
|
14
17
|
startMs: -Infinity,
|
|
15
18
|
endMs: Infinity
|
|
16
19
|
};
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const temporal = el;
|
|
21
|
+
let startMs = temporal.startTimeMs ?? -Infinity;
|
|
22
|
+
let endMs = temporal.endTimeMs ?? Infinity;
|
|
23
|
+
if (endMs <= startMs) {
|
|
24
|
+
startMs = -Infinity;
|
|
25
|
+
endMs = Infinity;
|
|
26
|
+
}
|
|
23
27
|
return {
|
|
24
28
|
startMs,
|
|
25
29
|
endMs
|
|
@@ -39,9 +43,6 @@ const DEFAULT_HEIGHT = 1080;
|
|
|
39
43
|
const DEFAULT_THUMBNAIL_SCALE = .25;
|
|
40
44
|
/** Default timeout for blocking content readiness mode (ms) */
|
|
41
45
|
const DEFAULT_BLOCKING_TIMEOUT_MS = 5e3;
|
|
42
|
-
/** JPEG quality settings for different canvas scales */
|
|
43
|
-
const JPEG_QUALITY_HIGH = .95;
|
|
44
|
-
const JPEG_QUALITY_MEDIUM = .85;
|
|
45
46
|
/**
|
|
46
47
|
* Create a preview container with standard styling.
|
|
47
48
|
* Consolidates the repeated container creation pattern across preview functions.
|
|
@@ -60,5 +61,5 @@ function createPreviewContainer(options) {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
//#endregion
|
|
63
|
-
export { DEFAULT_BLOCKING_TIMEOUT_MS, DEFAULT_HEIGHT, DEFAULT_THUMBNAIL_SCALE, DEFAULT_WIDTH,
|
|
64
|
+
export { DEFAULT_BLOCKING_TIMEOUT_MS, DEFAULT_HEIGHT, DEFAULT_THUMBNAIL_SCALE, DEFAULT_WIDTH, createPreviewContainer, getTemporalBounds, isTemporal, isVisibleAtTime };
|
|
64
65
|
//# sourceMappingURL=previewTypes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"previewTypes.js","names":[],"sources":["../../src/preview/previewTypes.ts"],"sourcesContent":["/**\n * Shared types and constants for preview rendering.\n * \n * Consolidates duplicate definitions from renderTimegroupToCanvas.ts and\n * renderTimegroupPreview.ts into a single source of truth.\n */\n\n// ============================================================================\n// Temporal Types\n// ============================================================================\n\n/**\n * Element with temporal properties (startTimeMs, endTimeMs).\n * Used for temporal visibility checks during preview rendering.\n */\nexport interface TemporalElement extends Element {\n startTimeMs?: number;\n endTimeMs?: number;\n src?: string;\n}\n\n/**\n * Type guard to check if an element has temporal properties.\n */\nexport function isTemporal(el: Element): el is TemporalElement {\n return \"startTimeMs\" in el && \"endTimeMs\" in el;\n}\n\n/**\n * Get temporal bounds for an element, treating invalid ranges as unbounded.\n * Invalid range (end <= start) means element hasn't computed its duration yet.\n */\nexport function getTemporalBounds(el: Element): { startMs: number; endMs: number } {\n if (!isTemporal(el)) return { startMs: -Infinity, endMs: Infinity };\n\n const startMs =
|
|
1
|
+
{"version":3,"file":"previewTypes.js","names":[],"sources":["../../src/preview/previewTypes.ts"],"sourcesContent":["/**\n * Shared types and constants for preview rendering.\n * \n * Consolidates duplicate definitions from renderTimegroupToCanvas.ts and\n * renderTimegroupPreview.ts into a single source of truth.\n */\n\n// ============================================================================\n// Temporal Types\n// ============================================================================\n\n/**\n * Element with temporal properties (startTimeMs, endTimeMs).\n * Used for temporal visibility checks during preview rendering.\n */\nexport interface TemporalElement extends Element {\n startTimeMs?: number;\n endTimeMs?: number;\n src?: string;\n}\n\n/**\n * Type guard to check if an element has temporal properties.\n */\nexport function isTemporal(el: Element): el is TemporalElement {\n return \"startTimeMs\" in el && \"endTimeMs\" in el;\n}\n\n/**\n * Get temporal bounds for an element, treating invalid ranges as unbounded.\n * Invalid range (end <= start) means element hasn't computed its duration yet.\n * \n * NOTE: No caching - bounds are computed dynamically by timegroups based on\n * composition mode (sequence/contain/fit) and may change between frames.\n */\nexport function getTemporalBounds(el: Element): { startMs: number; endMs: number } {\n // Non-temporal elements are always visible\n if (!isTemporal(el)) {\n return { startMs: -Infinity, endMs: Infinity };\n }\n\n // Compute bounds fresh each time\n const temporal = el as TemporalElement;\n let startMs = temporal.startTimeMs ?? -Infinity;\n let endMs = temporal.endTimeMs ?? Infinity;\n\n // If end <= start, treat as always visible (element hasn't computed duration yet)\n if (endMs <= startMs) {\n startMs = -Infinity;\n endMs = Infinity;\n }\n\n return { startMs, endMs };\n}\n\n/**\n * Check if an element is temporally visible at the given time.\n */\nexport function isVisibleAtTime(element: Element, timeMs: number): boolean {\n const { startMs, endMs } = getTemporalBounds(element);\n return timeMs >= startMs && timeMs <= endMs;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default timegroup dimensions when not measurable */\nexport const DEFAULT_WIDTH = 1920;\nexport const DEFAULT_HEIGHT = 1080;\n\n/** Default scale for thumbnail captures */\nexport const DEFAULT_THUMBNAIL_SCALE = 0.25;\n\n/** Default timeout for blocking content readiness mode (ms) */\nexport const DEFAULT_BLOCKING_TIMEOUT_MS = 5000;\n\n// ============================================================================\n// Container Creation\n// ============================================================================\n\n/**\n * Options for creating a preview container.\n */\nexport interface PreviewContainerOptions {\n width: number;\n height: number;\n background?: string;\n position?: \"relative\" | \"absolute\" | \"fixed\";\n}\n\n/**\n * Create a preview container with standard styling.\n * Consolidates the repeated container creation pattern across preview functions.\n */\nexport function createPreviewContainer(options: PreviewContainerOptions): HTMLDivElement {\n const { width, height, background = \"#000\", position = \"relative\" } = options;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n width: ${width}px;\n height: ${height}px;\n position: ${position};\n overflow: hidden;\n background: ${background};\n `;\n return container;\n}\n\n// ============================================================================\n// Style Injection\n// ============================================================================\n\n/**\n * Inject document styles into a container for foreignObject rendering.\n * SVG foreignObject needs all CSS rules inlined since it can't access\n * the document's stylesheets.\n */\nexport function injectDocumentStyles(\n container: HTMLElement,\n collectStyles: () => string,\n): HTMLStyleElement {\n const styleEl = document.createElement(\"style\");\n styleEl.textContent = collectStyles();\n container.appendChild(styleEl);\n return styleEl;\n}\n"],"mappings":";;;;AAwBA,SAAgB,WAAW,IAAoC;AAC7D,QAAO,iBAAiB,MAAM,eAAe;;;;;;;;;AAU/C,SAAgB,kBAAkB,IAAiD;AAEjF,KAAI,CAAC,WAAW,GAAG,CACjB,QAAO;EAAE,SAAS;EAAW,OAAO;EAAU;CAIhD,MAAM,WAAW;CACjB,IAAI,UAAU,SAAS,eAAe;CACtC,IAAI,QAAQ,SAAS,aAAa;AAGlC,KAAI,SAAS,SAAS;AACpB,YAAU;AACV,UAAQ;;AAGV,QAAO;EAAE;EAAS;EAAO;;;;;AAM3B,SAAgB,gBAAgB,SAAkB,QAAyB;CACzE,MAAM,EAAE,SAAS,UAAU,kBAAkB,QAAQ;AACrD,QAAO,UAAU,WAAW,UAAU;;;AAQxC,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;;AAG9B,MAAa,0BAA0B;;AAGvC,MAAa,8BAA8B;;;;;AAoB3C,SAAgB,uBAAuB,SAAkD;CACvF,MAAM,EAAE,OAAO,QAAQ,aAAa,QAAQ,WAAW,eAAe;CAEtE,MAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,WAAU,MAAM,UAAU;aACf,MAAM;cACL,OAAO;gBACL,SAAS;;kBAEP,WAAW;;AAE3B,QAAO"}
|