mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Correctly handle overflow content
This commit is contained in:
parent
fa360b8022
commit
ce2517ee6d
65
dist/html2canvas.js
vendored
65
dist/html2canvas.js
vendored
@ -1067,6 +1067,9 @@ function NodeContainer(node, parent) {
|
||||
this.parent = parent;
|
||||
this.stack = null;
|
||||
this.bounds = null;
|
||||
this.borders = null;
|
||||
this.clip = [];
|
||||
this.backgroundClip = [];
|
||||
this.offsetBounds = null;
|
||||
this.visible = null;
|
||||
this.computedStyles = null;
|
||||
@ -1331,8 +1334,7 @@ function parseBackgrounds(backgroundImage) {
|
||||
case '"':
|
||||
if(!quote) {
|
||||
quote = c;
|
||||
}
|
||||
else if(quote === c) {
|
||||
} else if(quote === c) {
|
||||
quote = null;
|
||||
}
|
||||
break;
|
||||
@ -1450,12 +1452,14 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
||||
this.fontMetrics = new FontMetrics();
|
||||
log("Fetched nodes");
|
||||
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
||||
this.ready = this.images.ready.then(bind(function() {
|
||||
log("Images loaded, starting parsing");
|
||||
log("Calculate overflow clips");
|
||||
this.calculateOverflowClips();
|
||||
log("Creating stacking contexts");
|
||||
this.createStackingContexts();
|
||||
log("Sorting stacking contexts");
|
||||
this.sortStackingContexts(this.stack);
|
||||
this.ready = this.images.ready.then(bind(function() {
|
||||
log("Images loaded, starting parsing");
|
||||
this.parse(this.stack);
|
||||
log("Render queue created with " + this.renderQueue.length + " items");
|
||||
return new Promise(bind(function(resolve) {
|
||||
@ -1472,6 +1476,24 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
||||
}, this));
|
||||
}
|
||||
|
||||
NodeParser.prototype.calculateOverflowClips = function() {
|
||||
this.nodes.forEach(function(container) {
|
||||
if (isElement(container)) {
|
||||
container.borders = this.parseBorders(container);
|
||||
var clip = (container.css('overflow') === "hidden") ? [container.borders.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;
|
||||
} else if (isTextNode(container)) {
|
||||
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
||||
}
|
||||
container.bounds = null;
|
||||
}, this);
|
||||
};
|
||||
|
||||
function hasParentClip(container) {
|
||||
return container.parent && container.parent.clip.length;
|
||||
}
|
||||
|
||||
NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
|
||||
asyncTimer = asyncTimer || Date.now();
|
||||
this.paint(queue[this.renderIndex++]);
|
||||
@ -1561,6 +1583,10 @@ NodeParser.prototype.getChildren = function(parentContainer) {
|
||||
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
||||
var stack = new StackingContext(hasOwnStacking, container.cssFloat('opacity'), container.node, container.parent);
|
||||
stack.visible = container.visible;
|
||||
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;
|
||||
parentStack.contexts.push(stack);
|
||||
container.stack = stack;
|
||||
@ -1675,17 +1701,19 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
}
|
||||
}
|
||||
var bounds = container.parseBounds();
|
||||
var borderData = this.parseBorders(container);
|
||||
this.renderer.clip(borderData.clip, function() {
|
||||
this.renderer.renderBackground(container, bounds, borderData.borders.map(getWidth));
|
||||
this.renderer.clip(container.backgroundClip, function() {
|
||||
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
||||
}, this);
|
||||
this.renderer.renderBorders(borderData.borders);
|
||||
|
||||
this.renderer.clip(container.clip, function() {
|
||||
this.renderer.renderBorders(container.borders.borders);
|
||||
|
||||
switch (container.node.nodeName) {
|
||||
case "svg":
|
||||
case "IFRAME":
|
||||
var imgContainer = this.images.get(container.node);
|
||||
if (imgContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imgContainer);
|
||||
this.renderer.renderImage(container, bounds, container.borders, imgContainer);
|
||||
} else {
|
||||
log("Error loading <" + container.node.nodeName + ">", container.node);
|
||||
}
|
||||
@ -1693,7 +1721,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
case "IMG":
|
||||
var imageContainer = this.images.get(container.node.src);
|
||||
if (imageContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer);
|
||||
this.renderer.renderImage(container, bounds, container.borders, imageContainer);
|
||||
} else {
|
||||
log("Error loading <img>", container.node.src);
|
||||
}
|
||||
@ -1704,6 +1732,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
this.paintFormValue(container);
|
||||
break;
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
|
||||
NodeParser.prototype.paintFormValue = function(container) {
|
||||
@ -1754,12 +1783,14 @@ NodeParser.prototype.paintText = function(container) {
|
||||
this.renderer.clearShadow();
|
||||
}
|
||||
|
||||
this.renderer.clip(container.parent.clip, function() {
|
||||
textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
|
||||
if (bounds) {
|
||||
this.renderer.text(textList[index], bounds.left, bounds.bottom);
|
||||
this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
};
|
||||
|
||||
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) {
|
||||
@ -1780,7 +1811,7 @@ NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics)
|
||||
};
|
||||
|
||||
NodeParser.prototype.parseBorders = function(container) {
|
||||
var nodeBounds = container.bounds;
|
||||
var nodeBounds = container.parseBounds();
|
||||
var radius = getBorderRadiusData(container);
|
||||
var borders = ["Top", "Right", "Bottom", "Left"].map(function(side) {
|
||||
return {
|
||||
@ -2148,7 +2179,7 @@ function isWordBoundary(characterCode) {
|
||||
}
|
||||
|
||||
function hasUnicode(string) {
|
||||
return /[^\u0000-\u00ff]/.test(string);
|
||||
return (/[^\u0000-\u00ff]/).test(string);
|
||||
}
|
||||
|
||||
function Proxy(src, proxyUrl, document) {
|
||||
@ -2605,9 +2636,11 @@ CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx
|
||||
}
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.clip = function(shape, callback, context) {
|
||||
CanvasRenderer.prototype.clip = function(shapes, callback, context) {
|
||||
this.ctx.save();
|
||||
shapes.filter(hasEntries).forEach(function(shape) {
|
||||
this.shape(shape).clip();
|
||||
}, this);
|
||||
callback.call(context);
|
||||
this.ctx.restore();
|
||||
};
|
||||
@ -2665,7 +2698,7 @@ CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgr
|
||||
["line", Math.round(left + width), Math.round(height + top)],
|
||||
["line", Math.round(left), Math.round(height + top)]
|
||||
];
|
||||
this.clip(shape, function() {
|
||||
this.clip([shape], function() {
|
||||
this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);
|
||||
}, this);
|
||||
};
|
||||
@ -2706,4 +2739,8 @@ CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
|
||||
return canvas;
|
||||
};
|
||||
|
||||
function hasEntries(array) {
|
||||
return array.length > 0;
|
||||
}
|
||||
|
||||
})(window, document);
|
4
dist/html2canvas.min.js
vendored
4
dist/html2canvas.min.js
vendored
File diff suppressed because one or more lines are too long
@ -3,6 +3,9 @@ function NodeContainer(node, parent) {
|
||||
this.parent = parent;
|
||||
this.stack = null;
|
||||
this.bounds = null;
|
||||
this.borders = null;
|
||||
this.clip = [];
|
||||
this.backgroundClip = [];
|
||||
this.offsetBounds = null;
|
||||
this.visible = null;
|
||||
this.computedStyles = null;
|
||||
@ -267,8 +270,7 @@ function parseBackgrounds(backgroundImage) {
|
||||
case '"':
|
||||
if(!quote) {
|
||||
quote = c;
|
||||
}
|
||||
else if(quote === c) {
|
||||
} else if(quote === c) {
|
||||
quote = null;
|
||||
}
|
||||
break;
|
||||
|
@ -20,12 +20,14 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
||||
this.fontMetrics = new FontMetrics();
|
||||
log("Fetched nodes");
|
||||
this.images = imageLoader.fetch(this.nodes.filter(isElement));
|
||||
this.ready = this.images.ready.then(bind(function() {
|
||||
log("Images loaded, starting parsing");
|
||||
log("Calculate overflow clips");
|
||||
this.calculateOverflowClips();
|
||||
log("Creating stacking contexts");
|
||||
this.createStackingContexts();
|
||||
log("Sorting stacking contexts");
|
||||
this.sortStackingContexts(this.stack);
|
||||
this.ready = this.images.ready.then(bind(function() {
|
||||
log("Images loaded, starting parsing");
|
||||
this.parse(this.stack);
|
||||
log("Render queue created with " + this.renderQueue.length + " items");
|
||||
return new Promise(bind(function(resolve) {
|
||||
@ -42,6 +44,24 @@ function NodeParser(element, renderer, support, imageLoader, options) {
|
||||
}, this));
|
||||
}
|
||||
|
||||
NodeParser.prototype.calculateOverflowClips = function() {
|
||||
this.nodes.forEach(function(container) {
|
||||
if (isElement(container)) {
|
||||
container.borders = this.parseBorders(container);
|
||||
var clip = (container.css('overflow') === "hidden") ? [container.borders.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;
|
||||
} else if (isTextNode(container)) {
|
||||
container.clip = hasParentClip(container) ? container.parent.clip : [];
|
||||
}
|
||||
container.bounds = null;
|
||||
}, this);
|
||||
};
|
||||
|
||||
function hasParentClip(container) {
|
||||
return container.parent && container.parent.clip.length;
|
||||
}
|
||||
|
||||
NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
|
||||
asyncTimer = asyncTimer || Date.now();
|
||||
this.paint(queue[this.renderIndex++]);
|
||||
@ -131,6 +151,10 @@ NodeParser.prototype.getChildren = function(parentContainer) {
|
||||
NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
|
||||
var stack = new StackingContext(hasOwnStacking, container.cssFloat('opacity'), container.node, container.parent);
|
||||
stack.visible = container.visible;
|
||||
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;
|
||||
parentStack.contexts.push(stack);
|
||||
container.stack = stack;
|
||||
@ -245,17 +269,19 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
}
|
||||
}
|
||||
var bounds = container.parseBounds();
|
||||
var borderData = this.parseBorders(container);
|
||||
this.renderer.clip(borderData.clip, function() {
|
||||
this.renderer.renderBackground(container, bounds, borderData.borders.map(getWidth));
|
||||
this.renderer.clip(container.backgroundClip, function() {
|
||||
this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
|
||||
}, this);
|
||||
this.renderer.renderBorders(borderData.borders);
|
||||
|
||||
this.renderer.clip(container.clip, function() {
|
||||
this.renderer.renderBorders(container.borders.borders);
|
||||
|
||||
switch (container.node.nodeName) {
|
||||
case "svg":
|
||||
case "IFRAME":
|
||||
var imgContainer = this.images.get(container.node);
|
||||
if (imgContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imgContainer);
|
||||
this.renderer.renderImage(container, bounds, container.borders, imgContainer);
|
||||
} else {
|
||||
log("Error loading <" + container.node.nodeName + ">", container.node);
|
||||
}
|
||||
@ -263,7 +289,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
case "IMG":
|
||||
var imageContainer = this.images.get(container.node.src);
|
||||
if (imageContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer);
|
||||
this.renderer.renderImage(container, bounds, container.borders, imageContainer);
|
||||
} else {
|
||||
log("Error loading <img>", container.node.src);
|
||||
}
|
||||
@ -274,6 +300,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
this.paintFormValue(container);
|
||||
break;
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
|
||||
NodeParser.prototype.paintFormValue = function(container) {
|
||||
@ -324,12 +351,14 @@ NodeParser.prototype.paintText = function(container) {
|
||||
this.renderer.clearShadow();
|
||||
}
|
||||
|
||||
this.renderer.clip(container.parent.clip, function() {
|
||||
textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
|
||||
if (bounds) {
|
||||
this.renderer.text(textList[index], bounds.left, bounds.bottom);
|
||||
this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
};
|
||||
|
||||
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) {
|
||||
@ -350,7 +379,7 @@ NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics)
|
||||
};
|
||||
|
||||
NodeParser.prototype.parseBorders = function(container) {
|
||||
var nodeBounds = container.bounds;
|
||||
var nodeBounds = container.parseBounds();
|
||||
var radius = getBorderRadiusData(container);
|
||||
var borders = ["Top", "Right", "Bottom", "Left"].map(function(side) {
|
||||
return {
|
||||
@ -718,5 +747,5 @@ function isWordBoundary(characterCode) {
|
||||
}
|
||||
|
||||
function hasUnicode(string) {
|
||||
return /[^\u0000-\u00ff]/.test(string);
|
||||
return (/[^\u0000-\u00ff]/).test(string);
|
||||
}
|
||||
|
@ -47,9 +47,11 @@ CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx
|
||||
}
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.clip = function(shape, callback, context) {
|
||||
CanvasRenderer.prototype.clip = function(shapes, callback, context) {
|
||||
this.ctx.save();
|
||||
shapes.filter(hasEntries).forEach(function(shape) {
|
||||
this.shape(shape).clip();
|
||||
}, this);
|
||||
callback.call(context);
|
||||
this.ctx.restore();
|
||||
};
|
||||
@ -107,7 +109,7 @@ CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgr
|
||||
["line", Math.round(left + width), Math.round(height + top)],
|
||||
["line", Math.round(left), Math.round(height + top)]
|
||||
];
|
||||
this.clip(shape, function() {
|
||||
this.clip([shape], function() {
|
||||
this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);
|
||||
}, this);
|
||||
};
|
||||
@ -147,3 +149,7 @@ CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
|
||||
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height );
|
||||
return canvas;
|
||||
};
|
||||
|
||||
function hasEntries(array) {
|
||||
return array.length > 0;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
<div style="overflow:hidden;">
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s
|
||||
|
||||
with the release of <div style="border-width:10px 0 5px 0;background:green;">a</div>Letraset sheets containing Lorem Ipsum passages, <img src="image.jpg" /> and more recently with desktop publishing software like <b>Aldus PageMaker</b> including versions of Lorem Ipsum.
|
||||
with the release of <div style="border-width:10px 0 5px 0;background:green;">a</div>Letraset sheets containing Lorem Ipsum passages, <img src="../assets/image.jpg" /> and more recently with desktop publishing software like <b>Aldus PageMaker</b> including versions of Lorem Ipsum.
|
||||
|
||||
|
||||
<div style="overflow:visible;position:relative;"><u>position:relative within a overflow:hidden element</u><br /> <br />
|
||||
|
Loading…
x
Reference in New Issue
Block a user