Skip to content

Commit

Permalink
fix: video clone (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
qq15725 committed Feb 22, 2023
1 parent 4f0e4e9 commit 3c473d5
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 59 deletions.
1 change: 1 addition & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<h1>egami</h1>
<h1>→</h1>
<h1>image</h1>
<video src='/movie.mp4' controls autoPlay></video>
</div>`,
src: null,
}
Expand Down
Binary file added docs/movie.mp4
Binary file not shown.
9 changes: 5 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
</head>
<body>
<div>
<div id="root">
<img src="/test/assets/image.png">
<img src="/test/assets/image.jpeg">
<img src="/test/assets/image.webp">
<div id="root" style="text-align: center;">
<h1>egami</h1>
<h1></h1>
<h1>image</h1>
<video src='/docs/movie.mp4' controls autoPlay></video>
</div>
</div>

Expand Down
4 changes: 1 addition & 3 deletions src/clone-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ export function cloneCanvas<T extends HTMLCanvasElement>(
return createImage(dataURL, canvas.ownerDocument)
}
} catch (error) {
consoleWarn('Failed to clone canvas', error)
//
}
}

const clone = canvas.cloneNode(false) as T
clone.width = canvas.width
clone.height = canvas.height
const ctx = canvas.getContext('2d')
const clonedCtx = clone.getContext('2d')

Expand Down
2 changes: 1 addition & 1 deletion src/clone-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { Context } from './context'
export function cloneElement<T extends HTMLElement | SVGElement>(
node: T,
context: Context,
): HTMLElement | SVGElement {
): (HTMLElement | SVGElement) | Promise<HTMLElement | SVGElement> {
if (isCanvasElement(node)) {
return cloneCanvas(node)
}
Expand Down
4 changes: 2 additions & 2 deletions src/clone-iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import type { Context } from './context'
export function cloneIframe<T extends HTMLIFrameElement>(
iframe: T,
context: Context,
): HTMLIFrameElement | HTMLBodyElement {
): HTMLIFrameElement | Promise<HTMLBodyElement> {
try {
if (iframe?.contentDocument?.body) {
return cloneNode(iframe.contentDocument.body, context) as HTMLBodyElement
return cloneNode(iframe.contentDocument.body, context) as Promise<HTMLBodyElement>
}
} catch (error) {
consoleWarn('Failed to clone iframe', error)
Expand Down
29 changes: 15 additions & 14 deletions src/clone-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ import {
import { cloneElement } from './clone-element'
import type { Context } from './context'

function appendChildNode<T extends Node>(
async function appendChildNode<T extends Node>(
clone: T,
child: ChildNode,
context: Context,
): void {
): Promise<void> {
if (isElementNode(child) && (isStyleElement(child) || isScriptElement(child))) return

if (context.filter && !context.filter(child)) return

clone.appendChild(cloneNode(child, context))
clone.appendChild(await cloneNode(child, context))
}

function cloneChildNodes<T extends Node>(
async function cloneChildNodes<T extends Node>(
node: T,
clone: T,
context: Context,
): void {
): Promise<void> {
const firstChild = (
isElementNode(node)
? node.shadowRoot?.firstChild
Expand All @@ -43,11 +43,12 @@ function cloneChildNodes<T extends Node>(
&& isSlotElement(child)
&& typeof child.assignedNodes === 'function'
) {
child.assignedNodes().forEach(assignedNode => {
appendChildNode(clone, assignedNode as ChildNode, context)
})
const nodes = child.assignedNodes()
for (let i = 0; i < nodes.length; i++) {
await appendChildNode(clone, nodes[i] as ChildNode, context)
}
} else {
appendChildNode(clone, child, context)
await appendChildNode(clone, child, context)
}
}
}
Expand All @@ -64,11 +65,11 @@ function applyCssStyleWithOptions(style: CSSStyleDeclaration, context: Context)
}
}

export function cloneNode<T extends Node>(
export async function cloneNode<T extends Node>(
node: T,
context: Context,
isRoot = false,
): Node {
): Promise<Node> {
const { ownerDocument, ownerWindow, fontFamilies } = context

if (ownerDocument && isTextNode(node)) {
Expand All @@ -85,7 +86,7 @@ export function cloneNode<T extends Node>(
return ownerDocument.createComment(node.tagName.toLowerCase())
}

const clone = cloneElement(node, context)
const clone = await cloneElement(node, context)
const cloneStyle = clone.style

copyCssStyles(node, style, clone, isRoot, context)
Expand All @@ -103,15 +104,15 @@ export function cloneNode<T extends Node>(
copyInputValue(node, clone)

if (!isVideoElement(node)) {
cloneChildNodes(node, clone, context)
await cloneChildNodes(node, clone, context)
}

return clone
}

const clone = node.cloneNode(false)

cloneChildNodes(node, clone, context)
await cloneChildNodes(node, clone, context)

return clone
}
55 changes: 35 additions & 20 deletions src/clone-video.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
import { cloneCanvas } from './clone-canvas'
import { consoleWarn, createImage } from './utils'
import { consoleWarn, createImage, loadMedia } from './utils'

export function cloneVideo<T extends HTMLVideoElement>(
export async function cloneVideo<T extends HTMLVideoElement>(
video: T,
): HTMLCanvasElement | HTMLImageElement | HTMLVideoElement {
if (video.ownerDocument) {
const ownerDocument = video.ownerDocument
): Promise<HTMLCanvasElement | HTMLImageElement | HTMLVideoElement> {
if (
video.ownerDocument
&& !video.currentSrc
&& video.poster
) {
return createImage(video.poster, video.ownerDocument)
}

if (video.currentSrc && video.currentTime) {
const canvas = ownerDocument.createElement('canvas')
canvas.width = video.offsetWidth
canvas.height = video.offsetHeight
try {
const ctx = canvas.getContext('2d')
if (ctx) ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
} catch (error) {
consoleWarn('Failed to clone video', error)
}
return cloneCanvas(canvas)
}
video.currentTime = 3

const clone = video.cloneNode(false) as T
clone.crossOrigin = 'anonymous'
if (video.currentSrc && video.currentSrc !== video.src) {
clone.src = video.currentSrc
}

if (video.poster) {
return createImage(video.poster, ownerDocument, true)
// video to canvas
const ownerDocument = clone.ownerDocument
if (ownerDocument) {
await loadMedia(clone)
clone.currentTime = video.currentTime
await new Promise(resolve => {
clone.addEventListener('seeked', resolve, { once: true })
})
const canvas = ownerDocument.createElement('canvas')
canvas.width = video.offsetWidth
canvas.height = video.offsetHeight
try {
const ctx = canvas.getContext('2d')
if (ctx) ctx.drawImage(clone, 0, 0, canvas.width, canvas.height)
} catch (error) {
consoleWarn('Failed to clone video', error)
}
return cloneCanvas(canvas)
}

return video.cloneNode(false) as T
return clone
}
2 changes: 1 addition & 1 deletion src/converts/dom-to-foreign-object-svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function domToForeignObjectSvg(node: any, options?: any) {
} = context

log.time('clone node')
const clone = cloneNode(context.node, context, true)
const clone = await cloneNode(context.node, context, true)
log.timeEnd('clone node')

onCloneNode?.(clone)
Expand Down
9 changes: 4 additions & 5 deletions src/embed-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import type { Context } from './context'
export function embedNode<T extends Node>(clone: T, context: Context) {
const { tasks } = context

if (
isElementNode(clone)
&& (isImageElement(clone) || isSVGImageElementNode(clone))
) {
tasks.push(...embedImageElement(clone, context))
if (isElementNode(clone)) {
if (isImageElement(clone) || isSVGImageElementNode(clone)) {
tasks.push(...embedImageElement(clone, context))
}
}

if (isHTMLElementNode(clone)) {
Expand Down
17 changes: 8 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,8 @@ export function readBlob(blob: Blob, type: 'dataUrl' | 'arrayBuffer') {
export const blobToDataUrl = (blob: Blob) => readBlob(blob, 'dataUrl')
export const blobToArrayBuffer = (blob: Blob) => readBlob(blob, 'arrayBuffer')

export function createImage(url: string, ownerDocument?: Document | null, useCORS = false): HTMLImageElement {
export function createImage(url: string, ownerDocument?: Document | null): HTMLImageElement {
const img = getDocument(ownerDocument).createElement('img')
if (useCORS) {
img.crossOrigin = 'anonymous'
}
img.decoding = 'sync'
img.loading = 'eager'
img.src = url
Expand Down Expand Up @@ -188,12 +185,14 @@ export function loadMedia(media: any, options?: LoadMediaOptions): Promise<any>
}

if (isVideoElement(node)) {
const poster = node.poster
if (poster) {
return loadMedia(poster, options).then(resolve)
}
const currentSrc = (node.currentSrc || node.src)
if (node.readyState >= 2 || !currentSrc) {
if (!currentSrc) {
if (node.poster) {
return loadMedia(node.poster, options).then(resolve)
}
return onResolve()
}
if (node.readyState >= 2) {
return onResolve()
}
const onLoadeddata = onResolve
Expand Down

0 comments on commit 3c473d5

Please sign in to comment.