mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Implement Iframe rendering
This commit is contained in:
parent
aa47a3a3a6
commit
90a8422938
102
src/Clone.js
102
src/Clone.js
@ -3,27 +3,39 @@
|
|||||||
import type {Bounds} from './Bounds';
|
import type {Bounds} from './Bounds';
|
||||||
import type {Options} from './index';
|
import type {Options} from './index';
|
||||||
import type Logger from './Logger';
|
import type Logger from './Logger';
|
||||||
|
import type {ImageElement} from './ImageLoader';
|
||||||
|
|
||||||
import ImageLoader from './ImageLoader';
|
import ImageLoader from './ImageLoader';
|
||||||
import {copyCSSStyles} from './Util';
|
import {copyCSSStyles} from './Util';
|
||||||
import {parseBackgroundImage} from './parsing/background';
|
import {parseBackgroundImage} from './parsing/background';
|
||||||
|
import CanvasRenderer from './renderer/CanvasRenderer';
|
||||||
|
|
||||||
export class DocumentCloner {
|
export class DocumentCloner {
|
||||||
scrolledElements: Array<[HTMLElement, number, number]>;
|
scrolledElements: Array<[HTMLElement, number, number]>;
|
||||||
referenceElement: HTMLElement;
|
referenceElement: HTMLElement;
|
||||||
clonedReferenceElement: HTMLElement;
|
clonedReferenceElement: HTMLElement;
|
||||||
documentElement: HTMLElement;
|
documentElement: HTMLElement;
|
||||||
imageLoader: ImageLoader<string>;
|
imageLoader: ImageLoader<*>;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
options: Options;
|
||||||
inlineImages: boolean;
|
inlineImages: boolean;
|
||||||
copyStyles: boolean;
|
copyStyles: boolean;
|
||||||
|
renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>;
|
||||||
|
|
||||||
constructor(element: HTMLElement, options: Options, logger: Logger, copyInline: boolean) {
|
constructor(
|
||||||
|
element: HTMLElement,
|
||||||
|
options: Options,
|
||||||
|
logger: Logger,
|
||||||
|
copyInline: boolean,
|
||||||
|
renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>
|
||||||
|
) {
|
||||||
this.referenceElement = element;
|
this.referenceElement = element;
|
||||||
this.scrolledElements = [];
|
this.scrolledElements = [];
|
||||||
this.copyStyles = copyInline;
|
this.copyStyles = copyInline;
|
||||||
this.inlineImages = copyInline;
|
this.inlineImages = copyInline;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
this.options = options;
|
||||||
|
this.renderer = renderer;
|
||||||
this.imageLoader = new ImageLoader(options, logger, window);
|
this.imageLoader = new ImageLoader(options, logger, window);
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
this.documentElement = this.cloneNode(element.ownerDocument.documentElement);
|
this.documentElement = this.cloneNode(element.ownerDocument.documentElement);
|
||||||
@ -90,6 +102,51 @@ export class DocumentCloner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node instanceof HTMLIFrameElement) {
|
||||||
|
const tempIframe = node.cloneNode(false);
|
||||||
|
const iframeKey = generateIframeKey();
|
||||||
|
tempIframe.setAttribute('data-html2canvas-internal-iframe-key', iframeKey);
|
||||||
|
|
||||||
|
this.imageLoader.cache[iframeKey] = getIframeDocumentElement(node, this.options)
|
||||||
|
.then(documentElement => {
|
||||||
|
return this.renderer(
|
||||||
|
documentElement,
|
||||||
|
{
|
||||||
|
async: this.options.async,
|
||||||
|
allowTaint: this.options.allowTaint,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
canvas: null,
|
||||||
|
imageTimeout: this.options.imageTimeout,
|
||||||
|
proxy: this.options.proxy,
|
||||||
|
removeContainer: this.options.removeContainer,
|
||||||
|
scale: this.options.scale,
|
||||||
|
target: new CanvasRenderer(),
|
||||||
|
type: 'view',
|
||||||
|
windowWidth: documentElement.ownerDocument.defaultView.innerWidth,
|
||||||
|
windowHeight: documentElement.ownerDocument.defaultView.innerHeight,
|
||||||
|
offsetX: documentElement.ownerDocument.defaultView.pageXOffset,
|
||||||
|
offsetY: documentElement.ownerDocument.defaultView.pageYOffset
|
||||||
|
},
|
||||||
|
this.logger.child(iframeKey)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then(canvas => {
|
||||||
|
const iframeCanvas = document.createElement('img');
|
||||||
|
iframeCanvas.src = canvas.toDataURL();
|
||||||
|
if (tempIframe.parentNode) {
|
||||||
|
tempIframe.parentNode.replaceChild(
|
||||||
|
copyCSSStyles(
|
||||||
|
node.ownerDocument.defaultView.getComputedStyle(node),
|
||||||
|
iframeCanvas
|
||||||
|
),
|
||||||
|
tempIframe
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return canvas;
|
||||||
|
});
|
||||||
|
return tempIframe;
|
||||||
|
}
|
||||||
|
|
||||||
return node.cloneNode(false);
|
return node.cloneNode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +156,13 @@ export class DocumentCloner {
|
|||||||
? document.createTextNode(node.nodeValue)
|
? document.createTextNode(node.nodeValue)
|
||||||
: this.createElementClone(node);
|
: this.createElementClone(node);
|
||||||
|
|
||||||
if (this.referenceElement === node && clone instanceof HTMLElement) {
|
const window = node.ownerDocument.defaultView;
|
||||||
|
|
||||||
|
if (this.referenceElement === node && clone instanceof window.HTMLElement) {
|
||||||
this.clonedReferenceElement = clone;
|
this.clonedReferenceElement = clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clone instanceof HTMLBodyElement) {
|
if (clone instanceof window.HTMLBodyElement) {
|
||||||
createPseudoHideStyles(clone);
|
createPseudoHideStyles(clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,10 +173,10 @@ export class DocumentCloner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof HTMLElement && clone instanceof HTMLElement) {
|
if (node instanceof window.HTMLElement && clone instanceof window.HTMLElement) {
|
||||||
this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_BEFORE));
|
this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_BEFORE));
|
||||||
this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_AFTER));
|
this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_AFTER));
|
||||||
if (this.copyStyles) {
|
if (this.copyStyles && !(node instanceof HTMLIFrameElement)) {
|
||||||
copyCSSStyles(node.ownerDocument.defaultView.getComputedStyle(node), clone);
|
copyCSSStyles(node.ownerDocument.defaultView.getComputedStyle(node), clone);
|
||||||
}
|
}
|
||||||
this.inlineAllImages(clone);
|
this.inlineAllImages(clone);
|
||||||
@ -127,13 +186,11 @@ export class DocumentCloner {
|
|||||||
switch (node.nodeName) {
|
switch (node.nodeName) {
|
||||||
case 'CANVAS':
|
case 'CANVAS':
|
||||||
if (!this.copyStyles) {
|
if (!this.copyStyles) {
|
||||||
// $FlowFixMe
|
|
||||||
cloneCanvasContents(node, clone);
|
cloneCanvasContents(node, clone);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'TEXTAREA':
|
case 'TEXTAREA':
|
||||||
case 'SELECT':
|
case 'SELECT':
|
||||||
// $FlowFixMe
|
|
||||||
clone.value = node.value;
|
clone.value = node.value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -248,14 +305,29 @@ const initNode = ([element, x, y]: [HTMLElement, number, number]) => {
|
|||||||
element.scrollTop = y;
|
element.scrollTop = y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateIframeKey = (): string =>
|
||||||
|
Math.ceil(Date.now() + Math.random() * 10000000).toString(16);
|
||||||
|
|
||||||
|
const getIframeDocumentElement = (
|
||||||
|
node: HTMLIFrameElement,
|
||||||
|
options: Options
|
||||||
|
): Promise<HTMLElement> => {
|
||||||
|
try {
|
||||||
|
return Promise.resolve(node.contentWindow.document.documentElement);
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const cloneWindow = (
|
export const cloneWindow = (
|
||||||
ownerDocument: Document,
|
ownerDocument: Document,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
referenceElement: HTMLElement,
|
referenceElement: HTMLElement,
|
||||||
options: Options,
|
options: Options,
|
||||||
logger: Logger
|
logger: Logger,
|
||||||
): Promise<[HTMLIFrameElement, HTMLElement]> => {
|
renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>
|
||||||
const cloner = new DocumentCloner(referenceElement, options, logger, false);
|
): Promise<[HTMLIFrameElement, HTMLElement, ImageLoader<ImageElement>]> => {
|
||||||
|
const cloner = new DocumentCloner(referenceElement, options, logger, false, renderer);
|
||||||
const cloneIframeContainer = ownerDocument.createElement('iframe');
|
const cloneIframeContainer = ownerDocument.createElement('iframe');
|
||||||
|
|
||||||
cloneIframeContainer.className = 'html2canvas-container';
|
cloneIframeContainer.className = 'html2canvas-container';
|
||||||
@ -275,7 +347,7 @@ export const cloneWindow = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let cloneWindow = cloneIframeContainer.contentWindow;
|
const cloneWindow = cloneIframeContainer.contentWindow;
|
||||||
const documentClone = cloneWindow.document;
|
const documentClone = cloneWindow.document;
|
||||||
|
|
||||||
/* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
|
/* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
|
||||||
@ -302,7 +374,11 @@ export const cloneWindow = (
|
|||||||
cloner.clonedReferenceElement instanceof cloneWindow.HTMLElement ||
|
cloner.clonedReferenceElement instanceof cloneWindow.HTMLElement ||
|
||||||
cloner.clonedReferenceElement instanceof HTMLElement
|
cloner.clonedReferenceElement instanceof HTMLElement
|
||||||
) {
|
) {
|
||||||
resolve([cloneIframeContainer, cloner.clonedReferenceElement]);
|
resolve([
|
||||||
|
cloneIframeContainer,
|
||||||
|
cloner.clonedReferenceElement,
|
||||||
|
cloner.imageLoader
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
reject(
|
reject(
|
||||||
__DEV__
|
__DEV__
|
||||||
|
@ -3,9 +3,15 @@
|
|||||||
|
|
||||||
export default class Logger {
|
export default class Logger {
|
||||||
start: number;
|
start: number;
|
||||||
|
id: ?string;
|
||||||
|
|
||||||
constructor() {
|
constructor(id: ?string, start: ?number) {
|
||||||
this.start = Date.now();
|
this.start = start ? start : Date.now();
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
child(id: string) {
|
||||||
|
return new Logger(id, this.start);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line flowtype/no-weak-types
|
// eslint-disable-next-line flowtype/no-weak-types
|
||||||
@ -15,7 +21,10 @@ export default class Logger {
|
|||||||
.call(window.console.log, window.console)
|
.call(window.console.log, window.console)
|
||||||
.apply(
|
.apply(
|
||||||
window.console,
|
window.console,
|
||||||
[Date.now() - this.start + 'ms', 'html2canvas:'].concat([].slice.call(args, 0))
|
[
|
||||||
|
Date.now() - this.start + 'ms',
|
||||||
|
this.id ? `html2canvas (${this.id}):` : 'html2canvas:'
|
||||||
|
].concat([].slice.call(args, 0))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,7 +36,10 @@ export default class Logger {
|
|||||||
.call(window.console.error, window.console)
|
.call(window.console.error, window.console)
|
||||||
.apply(
|
.apply(
|
||||||
window.console,
|
window.console,
|
||||||
[Date.now() - this.start + 'ms', 'html2canvas:'].concat([].slice.call(args, 0))
|
[
|
||||||
|
Date.now() - this.start + 'ms',
|
||||||
|
this.id ? `html2canvas (${this.id}):` : 'html2canvas:'
|
||||||
|
].concat([].slice.call(args, 0))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,6 +239,13 @@ const getImage = (
|
|||||||
case 'CANVAS':
|
case 'CANVAS':
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
return imageLoader.loadCanvas(node);
|
return imageLoader.loadCanvas(node);
|
||||||
|
case 'DIV':
|
||||||
|
const iframeKey = node.getAttribute('data-html2canvas-internal-iframe-key');
|
||||||
|
if (iframeKey) {
|
||||||
|
console.log('ok');
|
||||||
|
return iframeKey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
131
src/Window.js
Normal file
131
src/Window.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/* @flow */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import type {Options} from './index';
|
||||||
|
|
||||||
|
import Logger from './Logger';
|
||||||
|
|
||||||
|
import {NodeParser} from './NodeParser';
|
||||||
|
import Renderer from './Renderer';
|
||||||
|
import ForeignObjectRenderer from './renderer/ForeignObjectRenderer';
|
||||||
|
|
||||||
|
import Feature from './Feature';
|
||||||
|
import {Bounds, parseDocumentSize} from './Bounds';
|
||||||
|
import {cloneWindow, DocumentCloner} from './Clone';
|
||||||
|
import {FontMetrics} from './Font';
|
||||||
|
import Color, {TRANSPARENT} from './Color';
|
||||||
|
|
||||||
|
export const renderElement = (
|
||||||
|
element: HTMLElement,
|
||||||
|
options: Options,
|
||||||
|
logger: Logger
|
||||||
|
): Promise<*> => {
|
||||||
|
const ownerDocument = element.ownerDocument;
|
||||||
|
|
||||||
|
const windowBounds = new Bounds(
|
||||||
|
options.offsetX,
|
||||||
|
options.offsetY,
|
||||||
|
options.windowWidth,
|
||||||
|
options.windowHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
const bounds = options.type === 'view' ? windowBounds : parseDocumentSize(ownerDocument);
|
||||||
|
|
||||||
|
// http://www.w3.org/TR/css3-background/#special-backgrounds
|
||||||
|
const documentBackgroundColor = ownerDocument.documentElement
|
||||||
|
? new Color(getComputedStyle(ownerDocument.documentElement).backgroundColor)
|
||||||
|
: TRANSPARENT;
|
||||||
|
const bodyBackgroundColor = ownerDocument.body
|
||||||
|
? new Color(getComputedStyle(ownerDocument.body).backgroundColor)
|
||||||
|
: TRANSPARENT;
|
||||||
|
|
||||||
|
const backgroundColor =
|
||||||
|
element === ownerDocument.documentElement
|
||||||
|
? documentBackgroundColor.isTransparent()
|
||||||
|
? bodyBackgroundColor.isTransparent()
|
||||||
|
? options.backgroundColor ? new Color(options.backgroundColor) : null
|
||||||
|
: bodyBackgroundColor
|
||||||
|
: documentBackgroundColor
|
||||||
|
: options.backgroundColor ? new Color(options.backgroundColor) : null;
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
return Feature.SUPPORT_FOREIGNOBJECT_DRAWING.then(
|
||||||
|
supportForeignObject =>
|
||||||
|
supportForeignObject
|
||||||
|
? (cloner => {
|
||||||
|
if (__DEV__) {
|
||||||
|
logger.log(`Document cloned, using foreignObject rendering`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloner.imageLoader.ready().then(() => {
|
||||||
|
const renderer = new ForeignObjectRenderer(cloner.clonedReferenceElement);
|
||||||
|
return renderer.render({
|
||||||
|
bounds,
|
||||||
|
backgroundColor,
|
||||||
|
logger,
|
||||||
|
scale: options.scale
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})(new DocumentCloner(element, options, logger, true, renderElement))
|
||||||
|
: cloneWindow(
|
||||||
|
ownerDocument,
|
||||||
|
windowBounds,
|
||||||
|
element,
|
||||||
|
options,
|
||||||
|
logger,
|
||||||
|
renderElement
|
||||||
|
).then(([container, clonedElement, imageLoader]) => {
|
||||||
|
if (__DEV__) {
|
||||||
|
logger.log(`Document cloned, using computed rendering`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stack = NodeParser(clonedElement, imageLoader, logger);
|
||||||
|
const clonedDocument = clonedElement.ownerDocument;
|
||||||
|
const width = bounds.width;
|
||||||
|
const height = bounds.height;
|
||||||
|
|
||||||
|
if (backgroundColor === stack.container.style.background.backgroundColor) {
|
||||||
|
stack.container.style.background.backgroundColor = TRANSPARENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageLoader.ready().then(imageStore => {
|
||||||
|
if (options.removeContainer === true) {
|
||||||
|
if (container.parentNode) {
|
||||||
|
container.parentNode.removeChild(container);
|
||||||
|
} else if (__DEV__) {
|
||||||
|
logger.log(
|
||||||
|
`Cannot detach cloned iframe as it is not in the DOM anymore`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fontMetrics = new FontMetrics(clonedDocument);
|
||||||
|
if (__DEV__) {
|
||||||
|
logger.log(`Starting renderer`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderOptions = {
|
||||||
|
backgroundColor,
|
||||||
|
fontMetrics,
|
||||||
|
imageStore,
|
||||||
|
logger,
|
||||||
|
scale: options.scale,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(options.target)) {
|
||||||
|
return Promise.all(
|
||||||
|
options.target.map(target => {
|
||||||
|
const renderer = new Renderer(target, renderOptions);
|
||||||
|
return renderer.render(stack);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const renderer = new Renderer(options.target, renderOptions);
|
||||||
|
return renderer.render(stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
123
src/index.js
123
src/index.js
@ -3,17 +3,9 @@
|
|||||||
|
|
||||||
import type {RenderTarget} from './Renderer';
|
import type {RenderTarget} from './Renderer';
|
||||||
|
|
||||||
import {NodeParser} from './NodeParser';
|
|
||||||
import Renderer from './Renderer';
|
|
||||||
import ForeignObjectRenderer from './renderer/ForeignObjectRenderer';
|
|
||||||
import CanvasRenderer from './renderer/CanvasRenderer';
|
import CanvasRenderer from './renderer/CanvasRenderer';
|
||||||
import Logger from './Logger';
|
import Logger from './Logger';
|
||||||
import ImageLoader from './ImageLoader';
|
import {renderElement} from './Window';
|
||||||
import Feature from './Feature';
|
|
||||||
import {Bounds, parseDocumentSize} from './Bounds';
|
|
||||||
import {cloneWindow, DocumentCloner} from './Clone';
|
|
||||||
import {FontMetrics} from './Font';
|
|
||||||
import Color, {TRANSPARENT} from './Color';
|
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
async: ?boolean,
|
async: ?boolean,
|
||||||
@ -58,118 +50,7 @@ const html2canvas = (element: HTMLElement, conf: ?Options): Promise<*> => {
|
|||||||
offsetY: defaultView.pageYOffset
|
offsetY: defaultView.pageYOffset
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = {...defaultOptions, ...config};
|
const result = renderElement(element, {...defaultOptions, ...config}, logger);
|
||||||
|
|
||||||
const windowBounds = new Bounds(
|
|
||||||
options.offsetX,
|
|
||||||
options.offsetY,
|
|
||||||
options.windowWidth,
|
|
||||||
options.windowHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
const bounds = options.type === 'view' ? windowBounds : parseDocumentSize(ownerDocument);
|
|
||||||
|
|
||||||
// http://www.w3.org/TR/css3-background/#special-backgrounds
|
|
||||||
const documentBackgroundColor = ownerDocument.documentElement
|
|
||||||
? new Color(getComputedStyle(ownerDocument.documentElement).backgroundColor)
|
|
||||||
: TRANSPARENT;
|
|
||||||
const bodyBackgroundColor = ownerDocument.body
|
|
||||||
? new Color(getComputedStyle(ownerDocument.body).backgroundColor)
|
|
||||||
: TRANSPARENT;
|
|
||||||
|
|
||||||
const backgroundColor =
|
|
||||||
element === ownerDocument.documentElement
|
|
||||||
? documentBackgroundColor.isTransparent()
|
|
||||||
? bodyBackgroundColor.isTransparent()
|
|
||||||
? options.backgroundColor ? new Color(options.backgroundColor) : null
|
|
||||||
: bodyBackgroundColor
|
|
||||||
: documentBackgroundColor
|
|
||||||
: options.backgroundColor ? new Color(options.backgroundColor) : null;
|
|
||||||
|
|
||||||
// $FlowFixMe
|
|
||||||
const result = Feature.SUPPORT_FOREIGNOBJECT_DRAWING.then(
|
|
||||||
supportForeignObject =>
|
|
||||||
supportForeignObject
|
|
||||||
? (cloner => {
|
|
||||||
if (__DEV__) {
|
|
||||||
logger.log(`Document cloned, using foreignObject rendering`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cloner.imageLoader.ready().then(() => {
|
|
||||||
const renderer = new ForeignObjectRenderer(cloner.clonedReferenceElement);
|
|
||||||
return renderer.render({
|
|
||||||
bounds,
|
|
||||||
backgroundColor,
|
|
||||||
logger,
|
|
||||||
scale: options.scale
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})(new DocumentCloner(element, options, logger, true))
|
|
||||||
: cloneWindow(
|
|
||||||
ownerDocument,
|
|
||||||
windowBounds,
|
|
||||||
element,
|
|
||||||
options,
|
|
||||||
logger
|
|
||||||
).then(([container, clonedElement]) => {
|
|
||||||
if (__DEV__) {
|
|
||||||
logger.log(`Document cloned, using computed rendering`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const imageLoader = new ImageLoader(
|
|
||||||
options,
|
|
||||||
logger,
|
|
||||||
clonedElement.ownerDocument.defaultView
|
|
||||||
);
|
|
||||||
const stack = NodeParser(clonedElement, imageLoader, logger);
|
|
||||||
const clonedDocument = clonedElement.ownerDocument;
|
|
||||||
const width = bounds.width;
|
|
||||||
const height = bounds.height;
|
|
||||||
|
|
||||||
if (backgroundColor === stack.container.style.background.backgroundColor) {
|
|
||||||
stack.container.style.background.backgroundColor = TRANSPARENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageLoader.ready().then(imageStore => {
|
|
||||||
if (options.removeContainer === true) {
|
|
||||||
if (container.parentNode) {
|
|
||||||
container.parentNode.removeChild(container);
|
|
||||||
} else if (__DEV__) {
|
|
||||||
logger.log(
|
|
||||||
`Cannot detach cloned iframe as it is not in the DOM anymore`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fontMetrics = new FontMetrics(clonedDocument);
|
|
||||||
if (__DEV__) {
|
|
||||||
logger.log(`Starting renderer`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderOptions = {
|
|
||||||
backgroundColor,
|
|
||||||
fontMetrics,
|
|
||||||
imageStore,
|
|
||||||
logger,
|
|
||||||
scale: options.scale,
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Array.isArray(options.target)) {
|
|
||||||
return Promise.all(
|
|
||||||
options.target.map(target => {
|
|
||||||
const renderer = new Renderer(target, renderOptions);
|
|
||||||
return renderer.render(stack);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const renderer = new Renderer(options.target, renderOptions);
|
|
||||||
return renderer.render(stack);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
return result.catch(e => {
|
return result.catch(e => {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<script type="text/javascript" src="../test.js"></script>
|
<script type="text/javascript" src="../test.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="/tests/assets/iframe/frame1.html" width="500" height="500"></iframe>
|
<div style="background: cornflowerblue; padding: 20px; width: 200px;">Parent document content</div>
|
||||||
|
<iframe src="/tests/assets/iframe/frame1.html" width="500" height="500"></iframe>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user