mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Fix pseudoelement rendering (with nth-child selectors etc.)
This commit is contained in:
parent
b80eaf15cd
commit
587e8a73ef
@ -14,6 +14,6 @@
|
|||||||
"globals": {
|
"globals": {
|
||||||
"jQuery": true
|
"jQuery": true
|
||||||
},
|
},
|
||||||
"predef": ["NodeParser", "NodeContainer", "StackingContext", "TextContainer", "ImageLoader", "CanvasRenderer", "Renderer", "Support", "bind", "Promise", "getBounds", "offsetBounds", "XHR",
|
"predef": ["NodeParser", "NodeContainer", "StackingContext", "TextContainer", "PseudoElementContainer", "ImageLoader", "CanvasRenderer", "Renderer", "Support", "bind", "Promise", "getBounds", "offsetBounds", "XHR",
|
||||||
"ImageContainer", "ProxyImageContainer", "DummyImageContainer", "Font", "FontMetrics", "GradientContainer", "LinearGradientContainer", "WebkitGradientContainer", "SVGContainer", "SVGNodeContainer", "FrameContainer", "html2canvas", "log", "smallImage", "parseBackgrounds", "loadUrlDocument", "decode64", "Proxy", "ProxyURL"]
|
"ImageContainer", "ProxyImageContainer", "DummyImageContainer", "Font", "FontMetrics", "GradientContainer", "LinearGradientContainer", "WebkitGradientContainer", "SVGContainer", "SVGNodeContainer", "FrameContainer", "html2canvas", "log", "smallImage", "parseBackgrounds", "loadUrlDocument", "decode64", "Proxy", "ProxyURL"]
|
||||||
}
|
}
|
||||||
|
109
dist/html2canvas.js
vendored
109
dist/html2canvas.js
vendored
@ -5,7 +5,7 @@
|
|||||||
Released under MIT License
|
Released under MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function(window, document, module, exports, undefined){
|
(function(window, document, module, exports, global, define, undefined){
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2013 Yehuda Katz, Tom Dale, and contributors
|
Copyright (c) 2013 Yehuda Katz, Tom Dale, and contributors
|
||||||
@ -1164,8 +1164,26 @@ function NodeContainer(node, parent) {
|
|||||||
this.backgroundImages = null;
|
this.backgroundImages = null;
|
||||||
this.transformData = null;
|
this.transformData = null;
|
||||||
this.transformMatrix = null;
|
this.transformMatrix = null;
|
||||||
|
this.isPseudoElement = false;
|
||||||
|
this.opacity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeContainer.prototype.cloneTo = function(stack) {
|
||||||
|
stack.visible = this.visible;
|
||||||
|
stack.borders = this.borders;
|
||||||
|
stack.bounds = this.bounds;
|
||||||
|
stack.clip = this.clip;
|
||||||
|
stack.backgroundClip = this.backgroundClip;
|
||||||
|
stack.computedStyles = this.computedStyles;
|
||||||
|
stack.styles = this.styles;
|
||||||
|
stack.backgroundImages = this.backgroundImages;
|
||||||
|
stack.opacity = this.opacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeContainer.prototype.getOpacity = function() {
|
||||||
|
return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;
|
||||||
|
};
|
||||||
|
|
||||||
NodeContainer.prototype.assignStack = function(stack) {
|
NodeContainer.prototype.assignStack = function(stack) {
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
stack.children.push(this);
|
stack.children.push(this);
|
||||||
@ -1182,7 +1200,7 @@ NodeContainer.prototype.isElementVisible = function() {
|
|||||||
|
|
||||||
NodeContainer.prototype.css = function(attribute) {
|
NodeContainer.prototype.css = function(attribute) {
|
||||||
if (!this.computedStyles) {
|
if (!this.computedStyles) {
|
||||||
this.computedStyles = this.computedStyle(null);
|
this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
|
return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
|
||||||
@ -1538,11 +1556,12 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
|||||||
}).map(this.getPseudoElements, this));
|
}).map(this.getPseudoElements, this));
|
||||||
this.fontMetrics = new FontMetrics();
|
this.fontMetrics = new FontMetrics();
|
||||||
log("Fetched nodes, total:", this.nodes.length);
|
log("Fetched nodes, total:", this.nodes.length);
|
||||||
|
log("Calculate overflow clips");
|
||||||
|
this.calculateOverflowClips();
|
||||||
|
log("Start fetching images");
|
||||||
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
||||||
this.ready = this.images.ready.then(bind(function() {
|
this.ready = this.images.ready.then(bind(function() {
|
||||||
log("Images loaded, starting parsing");
|
log("Images loaded, starting parsing");
|
||||||
log("Calculate overflow clips");
|
|
||||||
this.calculateOverflowClips();
|
|
||||||
log("Creating stacking contexts");
|
log("Creating stacking contexts");
|
||||||
this.createStackingContexts();
|
this.createStackingContexts();
|
||||||
log("Sorting stacking contexts");
|
log("Sorting stacking contexts");
|
||||||
@ -1566,14 +1585,22 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
|||||||
NodeParser.prototype.calculateOverflowClips = function() {
|
NodeParser.prototype.calculateOverflowClips = function() {
|
||||||
this.nodes.forEach(function(container) {
|
this.nodes.forEach(function(container) {
|
||||||
if (isElement(container)) {
|
if (isElement(container)) {
|
||||||
|
if (isPseudoElement(container)) {
|
||||||
|
container.appendToDOM();
|
||||||
|
}
|
||||||
container.borders = this.parseBorders(container);
|
container.borders = this.parseBorders(container);
|
||||||
var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
|
var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
|
||||||
container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
|
container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
|
||||||
container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;
|
container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;
|
||||||
|
if (isPseudoElement(container)) {
|
||||||
|
container.cleanDOM();
|
||||||
|
}
|
||||||
} else if (isTextNode(container)) {
|
} else if (isTextNode(container)) {
|
||||||
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
||||||
}
|
}
|
||||||
container.bounds = null;
|
if (!isPseudoElement(container)) {
|
||||||
|
container.bounds = null;
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1597,8 +1624,8 @@ NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
|
|||||||
|
|
||||||
NodeParser.prototype.createPseudoHideStyles = function(document) {
|
NodeParser.prototype.createPseudoHideStyles = function(document) {
|
||||||
var hidePseudoElements = document.createElement('style');
|
var hidePseudoElements = document.createElement('style');
|
||||||
hidePseudoElements.innerHTML = '.' + this.pseudoHideClass + ':before { content: "" !important; display: none !important; }' +
|
hidePseudoElements.innerHTML = '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +
|
||||||
'.' + this.pseudoHideClass + ':after { content: "" !important; display: none !important; }';
|
'.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }';
|
||||||
document.body.appendChild(hidePseudoElements);
|
document.body.appendChild(hidePseudoElements);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1609,18 +1636,12 @@ NodeParser.prototype.getPseudoElements = function(container) {
|
|||||||
var after = this.getPseudoElement(container, ":after");
|
var after = this.getPseudoElement(container, ":after");
|
||||||
|
|
||||||
if (before) {
|
if (before) {
|
||||||
container.node.insertBefore(before[0].node, container.node.firstChild);
|
|
||||||
nodes.push(before);
|
nodes.push(before);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (after) {
|
if (after) {
|
||||||
container.node.appendChild(after[0].node);
|
|
||||||
nodes.push(after);
|
nodes.push(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (before || after) {
|
|
||||||
container.node.className += " " + this.pseudoHideClass;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return flatten(nodes);
|
return flatten(nodes);
|
||||||
};
|
};
|
||||||
@ -1640,14 +1661,14 @@ NodeParser.prototype.getPseudoElement = function(container, type) {
|
|||||||
var content = stripQuotes(style.content);
|
var content = stripQuotes(style.content);
|
||||||
var isImage = content.substr(0, 3) === 'url';
|
var isImage = content.substr(0, 3) === 'url';
|
||||||
var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
|
var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
|
||||||
var pseudoContainer = new NodeContainer(pseudoNode, container);
|
var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);
|
||||||
|
|
||||||
for (var i = style.length-1; i >= 0; i--) {
|
for (var i = style.length-1; i >= 0; i--) {
|
||||||
var property = toCamelCase(style.item(i));
|
var property = toCamelCase(style.item(i));
|
||||||
pseudoNode.style[property] = style[property];
|
pseudoNode.style[property] = style[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudoNode.className = this.pseudoHideClass;
|
pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;
|
||||||
|
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
pseudoNode.src = parseBackgrounds(content)[0].args[0];
|
pseudoNode.src = parseBackgrounds(content)[0].args[0];
|
||||||
@ -1668,12 +1689,8 @@ NodeParser.prototype.getChildren = function(parentContainer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
||||||
var stack = new StackingContext(hasOwnStacking, container.cssFloat('opacity'), container.node, container.parent);
|
var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);
|
||||||
stack.visible = container.visible;
|
container.cloneTo(stack);
|
||||||
stack.borders = container.borders;
|
|
||||||
stack.bounds = container.bounds;
|
|
||||||
stack.clip = container.clip;
|
|
||||||
stack.backgroundClip = container.backgroundClip;
|
|
||||||
var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
|
var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
|
||||||
parentStack.contexts.push(stack);
|
parentStack.contexts.push(stack);
|
||||||
container.stack = stack;
|
container.stack = stack;
|
||||||
@ -1770,7 +1787,13 @@ NodeParser.prototype.paint = function(container) {
|
|||||||
if (container instanceof ClearTransform) {
|
if (container instanceof ClearTransform) {
|
||||||
this.renderer.ctx.restore();
|
this.renderer.ctx.restore();
|
||||||
} else if (isTextNode(container)) {
|
} else if (isTextNode(container)) {
|
||||||
|
if (isPseudoElement(container.parent)) {
|
||||||
|
container.parent.appendToDOM();
|
||||||
|
}
|
||||||
this.paintText(container);
|
this.paintText(container);
|
||||||
|
if (isPseudoElement(container.parent)) {
|
||||||
|
container.parent.cleanDOM();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.paintNode(container);
|
this.paintNode(container);
|
||||||
}
|
}
|
||||||
@ -1787,6 +1810,7 @@ NodeParser.prototype.paintNode = function(container) {
|
|||||||
this.renderer.setTransform(container.parseTransform());
|
this.renderer.setTransform(container.parseTransform());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = container.parseBounds();
|
var bounds = container.parseBounds();
|
||||||
this.renderer.clip(container.backgroundClip, function() {
|
this.renderer.clip(container.backgroundClip, function() {
|
||||||
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
||||||
@ -2000,8 +2024,6 @@ NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, bor
|
|||||||
return borderArgs;
|
return borderArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeParser.prototype.pseudoHideClass = "___html2canvas___pseudoelement";
|
|
||||||
|
|
||||||
function getCurvePoints(x, y, r1, r2) {
|
function getCurvePoints(x, y, r1, r2) {
|
||||||
var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
|
var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
|
||||||
var ox = (r1) * kappa, // control point offset horizontal
|
var ox = (r1) * kappa, // control point offset horizontal
|
||||||
@ -2195,6 +2217,10 @@ function isElement(container) {
|
|||||||
return container.node.nodeType === Node.ELEMENT_NODE;
|
return container.node.nodeType === Node.ELEMENT_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPseudoElement(container) {
|
||||||
|
return container.isPseudoElement === true;
|
||||||
|
}
|
||||||
|
|
||||||
function isTextNode(container) {
|
function isTextNode(container) {
|
||||||
return container.node.nodeType === Node.TEXT_NODE;
|
return container.node.nodeType === Node.TEXT_NODE;
|
||||||
}
|
}
|
||||||
@ -2204,7 +2230,7 @@ function zIndexSort(a, b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasOpacity(container) {
|
function hasOpacity(container) {
|
||||||
return container.css("opacity") < 1;
|
return container.getOpacity() < 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind(callback, context) {
|
function bind(callback, context) {
|
||||||
@ -2340,6 +2366,41 @@ function ProxyImageContainer(src, proxy) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function PseudoElementContainer(node, parent, type) {
|
||||||
|
NodeContainer.call(this, node, parent);
|
||||||
|
this.isPseudoElement = true;
|
||||||
|
this.before = type === ":before";
|
||||||
|
}
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.cloneTo = function(stack) {
|
||||||
|
PseudoElementContainer.prototype.cloneTo.call(this, stack);
|
||||||
|
stack.isPseudoElement = true;
|
||||||
|
stack.before = this.before;
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.appendToDOM = function() {
|
||||||
|
if (this.before) {
|
||||||
|
this.parent.node.insertBefore(this.node, this.parent.node.firstChild);
|
||||||
|
} else {
|
||||||
|
this.parent.node.appendChild(this.node);
|
||||||
|
}
|
||||||
|
this.parent.node.className += " " + this.getHideClass();
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.cleanDOM = function() {
|
||||||
|
this.node.parentNode.removeChild(this.node);
|
||||||
|
this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), "");
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.getHideClass = function() {
|
||||||
|
return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")];
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";
|
||||||
|
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";
|
||||||
|
|
||||||
function Renderer(width, height, images, options, document) {
|
function Renderer(width, height, images, options, document) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
4
dist/html2canvas.min.js
vendored
4
dist/html2canvas.min.js
vendored
File diff suppressed because one or more lines are too long
@ -13,8 +13,26 @@ function NodeContainer(node, parent) {
|
|||||||
this.backgroundImages = null;
|
this.backgroundImages = null;
|
||||||
this.transformData = null;
|
this.transformData = null;
|
||||||
this.transformMatrix = null;
|
this.transformMatrix = null;
|
||||||
|
this.isPseudoElement = false;
|
||||||
|
this.opacity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeContainer.prototype.cloneTo = function(stack) {
|
||||||
|
stack.visible = this.visible;
|
||||||
|
stack.borders = this.borders;
|
||||||
|
stack.bounds = this.bounds;
|
||||||
|
stack.clip = this.clip;
|
||||||
|
stack.backgroundClip = this.backgroundClip;
|
||||||
|
stack.computedStyles = this.computedStyles;
|
||||||
|
stack.styles = this.styles;
|
||||||
|
stack.backgroundImages = this.backgroundImages;
|
||||||
|
stack.opacity = this.opacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeContainer.prototype.getOpacity = function() {
|
||||||
|
return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;
|
||||||
|
};
|
||||||
|
|
||||||
NodeContainer.prototype.assignStack = function(stack) {
|
NodeContainer.prototype.assignStack = function(stack) {
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
stack.children.push(this);
|
stack.children.push(this);
|
||||||
@ -31,7 +49,7 @@ NodeContainer.prototype.isElementVisible = function() {
|
|||||||
|
|
||||||
NodeContainer.prototype.css = function(attribute) {
|
NodeContainer.prototype.css = function(attribute) {
|
||||||
if (!this.computedStyles) {
|
if (!this.computedStyles) {
|
||||||
this.computedStyles = this.computedStyle(null);
|
this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
|
return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
|
||||||
|
@ -19,11 +19,12 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
|||||||
}).map(this.getPseudoElements, this));
|
}).map(this.getPseudoElements, this));
|
||||||
this.fontMetrics = new FontMetrics();
|
this.fontMetrics = new FontMetrics();
|
||||||
log("Fetched nodes, total:", this.nodes.length);
|
log("Fetched nodes, total:", this.nodes.length);
|
||||||
|
log("Calculate overflow clips");
|
||||||
|
this.calculateOverflowClips();
|
||||||
|
log("Start fetching images");
|
||||||
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
||||||
this.ready = this.images.ready.then(bind(function() {
|
this.ready = this.images.ready.then(bind(function() {
|
||||||
log("Images loaded, starting parsing");
|
log("Images loaded, starting parsing");
|
||||||
log("Calculate overflow clips");
|
|
||||||
this.calculateOverflowClips();
|
|
||||||
log("Creating stacking contexts");
|
log("Creating stacking contexts");
|
||||||
this.createStackingContexts();
|
this.createStackingContexts();
|
||||||
log("Sorting stacking contexts");
|
log("Sorting stacking contexts");
|
||||||
@ -47,14 +48,22 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
|||||||
NodeParser.prototype.calculateOverflowClips = function() {
|
NodeParser.prototype.calculateOverflowClips = function() {
|
||||||
this.nodes.forEach(function(container) {
|
this.nodes.forEach(function(container) {
|
||||||
if (isElement(container)) {
|
if (isElement(container)) {
|
||||||
|
if (isPseudoElement(container)) {
|
||||||
|
container.appendToDOM();
|
||||||
|
}
|
||||||
container.borders = this.parseBorders(container);
|
container.borders = this.parseBorders(container);
|
||||||
var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
|
var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
|
||||||
container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
|
container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
|
||||||
container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;
|
container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;
|
||||||
|
if (isPseudoElement(container)) {
|
||||||
|
container.cleanDOM();
|
||||||
|
}
|
||||||
} else if (isTextNode(container)) {
|
} else if (isTextNode(container)) {
|
||||||
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
||||||
}
|
}
|
||||||
container.bounds = null;
|
if (!isPseudoElement(container)) {
|
||||||
|
container.bounds = null;
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,8 +87,8 @@ NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
|
|||||||
|
|
||||||
NodeParser.prototype.createPseudoHideStyles = function(document) {
|
NodeParser.prototype.createPseudoHideStyles = function(document) {
|
||||||
var hidePseudoElements = document.createElement('style');
|
var hidePseudoElements = document.createElement('style');
|
||||||
hidePseudoElements.innerHTML = '.' + this.pseudoHideClass + ':before { content: "" !important; display: none !important; }' +
|
hidePseudoElements.innerHTML = '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +
|
||||||
'.' + this.pseudoHideClass + ':after { content: "" !important; display: none !important; }';
|
'.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }';
|
||||||
document.body.appendChild(hidePseudoElements);
|
document.body.appendChild(hidePseudoElements);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,18 +99,12 @@ NodeParser.prototype.getPseudoElements = function(container) {
|
|||||||
var after = this.getPseudoElement(container, ":after");
|
var after = this.getPseudoElement(container, ":after");
|
||||||
|
|
||||||
if (before) {
|
if (before) {
|
||||||
container.node.insertBefore(before[0].node, container.node.firstChild);
|
|
||||||
nodes.push(before);
|
nodes.push(before);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (after) {
|
if (after) {
|
||||||
container.node.appendChild(after[0].node);
|
|
||||||
nodes.push(after);
|
nodes.push(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (before || after) {
|
|
||||||
container.node.className += " " + this.pseudoHideClass;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return flatten(nodes);
|
return flatten(nodes);
|
||||||
};
|
};
|
||||||
@ -121,14 +124,14 @@ NodeParser.prototype.getPseudoElement = function(container, type) {
|
|||||||
var content = stripQuotes(style.content);
|
var content = stripQuotes(style.content);
|
||||||
var isImage = content.substr(0, 3) === 'url';
|
var isImage = content.substr(0, 3) === 'url';
|
||||||
var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
|
var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
|
||||||
var pseudoContainer = new NodeContainer(pseudoNode, container);
|
var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);
|
||||||
|
|
||||||
for (var i = style.length-1; i >= 0; i--) {
|
for (var i = style.length-1; i >= 0; i--) {
|
||||||
var property = toCamelCase(style.item(i));
|
var property = toCamelCase(style.item(i));
|
||||||
pseudoNode.style[property] = style[property];
|
pseudoNode.style[property] = style[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudoNode.className = this.pseudoHideClass;
|
pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;
|
||||||
|
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
pseudoNode.src = parseBackgrounds(content)[0].args[0];
|
pseudoNode.src = parseBackgrounds(content)[0].args[0];
|
||||||
@ -149,12 +152,8 @@ NodeParser.prototype.getChildren = function(parentContainer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
||||||
var stack = new StackingContext(hasOwnStacking, container.cssFloat('opacity'), container.node, container.parent);
|
var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);
|
||||||
stack.visible = container.visible;
|
container.cloneTo(stack);
|
||||||
stack.borders = container.borders;
|
|
||||||
stack.bounds = container.bounds;
|
|
||||||
stack.clip = container.clip;
|
|
||||||
stack.backgroundClip = container.backgroundClip;
|
|
||||||
var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
|
var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
|
||||||
parentStack.contexts.push(stack);
|
parentStack.contexts.push(stack);
|
||||||
container.stack = stack;
|
container.stack = stack;
|
||||||
@ -251,7 +250,13 @@ NodeParser.prototype.paint = function(container) {
|
|||||||
if (container instanceof ClearTransform) {
|
if (container instanceof ClearTransform) {
|
||||||
this.renderer.ctx.restore();
|
this.renderer.ctx.restore();
|
||||||
} else if (isTextNode(container)) {
|
} else if (isTextNode(container)) {
|
||||||
|
if (isPseudoElement(container.parent)) {
|
||||||
|
container.parent.appendToDOM();
|
||||||
|
}
|
||||||
this.paintText(container);
|
this.paintText(container);
|
||||||
|
if (isPseudoElement(container.parent)) {
|
||||||
|
container.parent.cleanDOM();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.paintNode(container);
|
this.paintNode(container);
|
||||||
}
|
}
|
||||||
@ -268,6 +273,7 @@ NodeParser.prototype.paintNode = function(container) {
|
|||||||
this.renderer.setTransform(container.parseTransform());
|
this.renderer.setTransform(container.parseTransform());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = container.parseBounds();
|
var bounds = container.parseBounds();
|
||||||
this.renderer.clip(container.backgroundClip, function() {
|
this.renderer.clip(container.backgroundClip, function() {
|
||||||
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
||||||
@ -481,8 +487,6 @@ NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, bor
|
|||||||
return borderArgs;
|
return borderArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeParser.prototype.pseudoHideClass = "___html2canvas___pseudoelement";
|
|
||||||
|
|
||||||
function getCurvePoints(x, y, r1, r2) {
|
function getCurvePoints(x, y, r1, r2) {
|
||||||
var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
|
var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
|
||||||
var ox = (r1) * kappa, // control point offset horizontal
|
var ox = (r1) * kappa, // control point offset horizontal
|
||||||
@ -676,6 +680,10 @@ function isElement(container) {
|
|||||||
return container.node.nodeType === Node.ELEMENT_NODE;
|
return container.node.nodeType === Node.ELEMENT_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPseudoElement(container) {
|
||||||
|
return container.isPseudoElement === true;
|
||||||
|
}
|
||||||
|
|
||||||
function isTextNode(container) {
|
function isTextNode(container) {
|
||||||
return container.node.nodeType === Node.TEXT_NODE;
|
return container.node.nodeType === Node.TEXT_NODE;
|
||||||
}
|
}
|
||||||
@ -685,7 +693,7 @@ function zIndexSort(a, b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasOpacity(container) {
|
function hasOpacity(container) {
|
||||||
return container.css("opacity") < 1;
|
return container.getOpacity() < 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind(callback, context) {
|
function bind(callback, context) {
|
||||||
|
34
src/pseudoelementcontainer.js
Normal file
34
src/pseudoelementcontainer.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
function PseudoElementContainer(node, parent, type) {
|
||||||
|
NodeContainer.call(this, node, parent);
|
||||||
|
this.isPseudoElement = true;
|
||||||
|
this.before = type === ":before";
|
||||||
|
}
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.cloneTo = function(stack) {
|
||||||
|
PseudoElementContainer.prototype.cloneTo.call(this, stack);
|
||||||
|
stack.isPseudoElement = true;
|
||||||
|
stack.before = this.before;
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.appendToDOM = function() {
|
||||||
|
if (this.before) {
|
||||||
|
this.parent.node.insertBefore(this.node, this.parent.node.firstChild);
|
||||||
|
} else {
|
||||||
|
this.parent.node.appendChild(this.node);
|
||||||
|
}
|
||||||
|
this.parent.node.className += " " + this.getHideClass();
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.cleanDOM = function() {
|
||||||
|
this.node.parentNode.removeChild(this.node);
|
||||||
|
this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), "");
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.getHideClass = function() {
|
||||||
|
return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")];
|
||||||
|
};
|
||||||
|
|
||||||
|
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";
|
||||||
|
PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
.background *::before{
|
.background *::before{
|
||||||
background: url(../assets/image_1.jpg);
|
background: url(../assets/image_1.jpg);
|
||||||
|
border: 5px solid red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.background *::after{
|
.background *::after{
|
||||||
|
@ -11,7 +11,7 @@ var h2cSelector, h2cOptions;
|
|||||||
document.write('<script type="text/javascript" src="' + src + '.js?' + Math.random() + '"></script>');
|
document.write('<script type="text/javascript" src="' + src + '.js?' + Math.random() + '"></script>');
|
||||||
}
|
}
|
||||||
|
|
||||||
var sources = ['log', 'punycode/punycode', 'core', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer',
|
var sources = ['log', 'punycode/punycode', 'core', 'nodecontainer', 'pseudoelementcontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer',
|
||||||
'lineargradientcontainer', 'webkitgradientcontainer', 'svgcontainer', 'svgnodecontainer', 'imageloader', 'nodeparser', 'font', 'fontmetrics', 'renderer', 'promise', 'xhr', 'framecontainer', 'proxy', 'renderers/canvas'];
|
'lineargradientcontainer', 'webkitgradientcontainer', 'svgcontainer', 'svgnodecontainer', 'imageloader', 'nodeparser', 'font', 'fontmetrics', 'renderer', 'promise', 'xhr', 'framecontainer', 'proxy', 'renderers/canvas'];
|
||||||
|
|
||||||
['/tests/assets/jquery-1.6.2'].concat(window.location.search === "?selenium" ? ['/dist/html2canvas'] : sources.map(function(src) { return '/src/' + src; })).forEach(appendScript);
|
['/tests/assets/jquery-1.6.2'].concat(window.location.search === "?selenium" ? ['/dist/html2canvas'] : sources.map(function(src) { return '/src/' + src; })).forEach(appendScript);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user