From 467ff8748209c82640a5afec4a4b730cf5451b72 Mon Sep 17 00:00:00 2001 From: Niklas von Hertzen Date: Mon, 3 Feb 2014 19:42:42 +0200 Subject: [PATCH] Switch to using Promises --- build/html2canvas.js | 313 ++++++++++++++++++---- build/html2canvas.min.js | 2 +- readme.md | 13 +- src/core.js | 28 +- src/nodeparser.js | 3 +- tests/assets/jquery.plugin.html2canvas.js | 13 +- 6 files changed, 299 insertions(+), 73 deletions(-) diff --git a/build/html2canvas.js b/build/html2canvas.js index 24a4ba7..6e06723 100644 --- a/build/html2canvas.js +++ b/build/html2canvas.js @@ -13,7 +13,17 @@ window.html2canvas = function(nodeList, options) { window.html2canvas.logging = true; window.html2canvas.start = Date.now(); } - createWindowClone(document, window.innerWidth, window.innerHeight).then(function(container) { + return renderDocument(document, options, window.innerWidth, window.innerHeight).then(function(canvas) { + if (typeof(options.onrendered) === "function") { + log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); + options.onrendered(canvas); + } + return canvas; + }); +}; + +function renderDocument(document, options, width, height) { + return createWindowClone(document, width, height).then(function(container) { log("Document cloned"); var clonedWindow = container.contentWindow; //var element = (nodeList === undefined) ? document.body : nodeList[0]; @@ -21,14 +31,16 @@ window.html2canvas = function(nodeList, options) { var support = new Support(); var imageLoader = new ImageLoader(options, support); var bounds = NodeParser.prototype.getBounds(node); - var width = options.type === "view" ? Math.min(bounds.width, window.innerWidth) : documentWidth(); - var height = options.type === "view" ? Math.min(bounds.height, window.innerHeight) : documentHeight(); + var width = options.type === "view" ? Math.min(bounds.width, width) : documentWidth(); + var height = options.type === "view" ? Math.min(bounds.height, height) : documentHeight(); var renderer = new CanvasRenderer(width, height, imageLoader); var parser = new NodeParser(node, renderer, support, imageLoader, options); - - window.console.log(parser); + return parser.ready.then(function() { + container.parentNode.removeChild(container); + return renderer.canvas; + }); }); -}; +} function documentWidth () { return Math.max( @@ -46,11 +58,15 @@ function documentHeight () { ); } +function smallImage() { + return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; +} + function createWindowClone(ownerDocument, width, height) { var documentElement = ownerDocument.documentElement.cloneNode(true), container = ownerDocument.createElement("iframe"); - container.style.display = "hidden"; + container.style.visibility = "hidden"; container.style.position = "absolute"; container.width = width; container.height = height; @@ -60,7 +76,7 @@ function createWindowClone(ownerDocument, width, height) { return new Promise(function(resolve) { var loadedTimer = function() { /* Chrome doesn't detect relative background-images assigned in style sheets when fetched through getComputedStyle, - before a certain time has passed + before a certain time has passed */ if (container.contentWindow.getComputedStyle(div, null)['backgroundImage'] !== "none") { documentClone.body.removeChild(div); @@ -84,12 +100,88 @@ function createWindowClone(ownerDocument, width, height) { div.className = "html2canvas-ready-test"; documentClone.body.appendChild(div); var style = documentClone.createElement("style"); - style.innerHTML = "body div.html2canvas-ready-test { background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); }"; + style.innerHTML = "body div.html2canvas-ready-test { background-image:url(" + smallImage() + "); }"; documentClone.body.appendChild(style); window.setTimeout(loadedTimer, 1000); }); } +function Font(family, size) { + var container = document.createElement('div'), + img = document.createElement('img'), + span = document.createElement('span'), + sampleText = 'Hidden Text', + baseline, + middle; + + container.style.visibility = "hidden"; + container.style.fontFamily = family; + container.style.fontSize = size; + container.style.margin = 0; + container.style.padding = 0; + + document.body.appendChild(container); + + img.src = smallImage(); + img.width = 1; + img.height = 1; + + img.style.margin = 0; + img.style.padding = 0; + img.style.verticalAlign = "baseline"; + + span.style.fontFamily = family; + span.style.fontSize = size; + span.style.margin = 0; + span.style.padding = 0; + + span.appendChild(document.createTextNode(sampleText)); + container.appendChild(span); + container.appendChild(img); + baseline = (img.offsetTop - span.offsetTop) + 1; + + container.removeChild(span); + container.appendChild(document.createTextNode(sampleText)); + + container.style.lineHeight = "normal"; + img.style.verticalAlign = "super"; + + middle = (img.offsetTop-container.offsetTop) + 1; + + document.body.removeChild(container); + + this.baseline = baseline; + this.lineWidth = 1; + this.middle = middle; +} + +function FontMetrics() { + this.data = {}; +} + +FontMetrics.prototype.getMetrics = function(family, size) { + if (this.data[family + "-" + size] === undefined) { + this.data[family + "-" + size] = new Font(family, size); + } + return this.data[family + "-" + size]; +}; + +function GradientContainer(imageData) { + this.src = imageData.value; + this.colorStops = []; + this.type = null; + this.x0 = 0.5; + this.y0 = 0.5; + this.x1 = 0.5; + this.y1 = 0.5; + this.promise = Promise.resolve(true); +} + +GradientContainer.prototype.TYPES = { + LINEAR: 1, + RADIAL: 2 +}; + function ImageContainer(src, cors) { this.src = src; this.image = new Image(); @@ -121,7 +213,7 @@ ImageLoader.prototype.findImages = function(nodes) { }; ImageLoader.prototype.findBackgroundImage = function(images, container) { - container.parseBackgroundImages().filter(this.isImageBackground).map(this.getBackgroundUrl).forEach(this.addImage(images, this.loadImage), this); + container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this); return images; }; @@ -129,30 +221,33 @@ ImageLoader.prototype.addImage = function(images, callback) { return function(newImage) { if (!this.imageExists(images, newImage)) { images.splice(0, 0, callback.apply(this, arguments)); - log('Added image #' + (images.length), newImage.substring(0, 100)); + log('Added image #' + (images.length), newImage); } }; }; -ImageLoader.prototype.getBackgroundUrl = function(imageData) { - return imageData.args[0]; +ImageLoader.prototype.hasImageBackground = function(imageData) { + return imageData.method !== "none"; }; -ImageLoader.prototype.isImageBackground = function(imageData) { - return imageData.method === "url"; -}; - -ImageLoader.prototype.loadImage = function(src) { - if (src.match(/data:image\/.*;base64,/i)) { - return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false); - } else if (this.isSameOrigin(src) || this.options.allowTaint === true) { - return new ImageContainer(src, false); - } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) { - return new ImageContainer(src, true); - } else if (this.options.proxy) { - return new ProxyImageContainer(src); - } else { - return new DummyImageContainer(src); +ImageLoader.prototype.loadImage = function(imageData) { + if (imageData.method === "url") { + var src = imageData.args[0]; + if (src.match(/data:image\/.*;base64,/i)) { + return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false); + } else if (this.isSameOrigin(src) || this.options.allowTaint === true) { + return new ImageContainer(src, false); + } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) { + return new ImageContainer(src, true); + } else if (this.options.proxy) { + return new ProxyImageContainer(src); + } else { + return new DummyImageContainer(src); + } + } else if (imageData.method === "linear-gradient") { + return new LinearGradientContainer(imageData); + } else if (imageData.method === "gradient") { + return new WebkitGradientContainer(imageData); } }; @@ -203,6 +298,40 @@ function src(container) { return container.node.src; } +function LinearGradientContainer(imageData) { + GradientContainer.apply(this, arguments); + this.type = this.TYPES.LINEAR; + + imageData.args[0].split(" ").forEach(function(position) { + switch(position) { + case "left": + this.x0 = 0; + this.x1 = 1; + break; + case "top": + this.y0 = 0; + this.y1 = 1; + break; + case "right": + this.x0 = 1; + this.x1 = 0; + break; + case "bottom": + this.y0 = 1; + this.y1 = 0; + break; + } + }, this); + + imageData.args.slice(1).forEach(function(colorStop) { + // console.log(colorStop, colorStop.match(this.stepRegExp)); + }, this); +} + +LinearGradientContainer.prototype = Object.create(GradientContainer.prototype); + +LinearGradientContainer.prototype.stepRegExp = /((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/; + function log() { if (window.html2canvas.logging && window.console && window.console.log) { window.console.log.apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0))); @@ -427,6 +556,28 @@ NodeContainer.prototype.parseBackgroundRepeat = function(index) { return this.cssList("backgroundRepeat", index)[0]; }; +NodeContainer.prototype.parseTextShadows = function() { + var textShadow = this.css("textShadow"); + var results = []; + + if (textShadow && textShadow !== 'none') { + var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY); + for (var i = 0; shadows && (i < shadows.length); i++) { + var s = shadows[i].match(this.TEXT_SHADOW_VALUES); + results.push({ + color: s[0], + offsetX: s[1] ? s[1].replace('px', '') : 0, + offsetY: s[2] ? s[2].replace('px', '') : 0, + blur: s[3] ? s[3].replace('px', '') : 0 + }); + } + } + return results; +}; + +NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g; +NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g; + function isPercentage(value) { return value.toString().indexOf("%") !== -1; } @@ -443,17 +594,17 @@ function NodeParser(element, renderer, support, imageLoader, options) { this.nodes = [parent].concat(this.getChildren(parent)).filter(function(container) { return container.visible = container.isElementVisible(); }); + this.fontMetrics = new FontMetrics(); log("Fetched nodes"); this.images = imageLoader.fetch(this.nodes.filter(isElement)); log("Creating stacking contexts"); this.createStackingContexts(); log("Sorting stacking contexts"); this.sortStackingContexts(this.stack); - this.images.ready.then(bind(function() { + this.ready = this.images.ready.then(bind(function() { log("Images loaded, starting parsing"); this.parse(this.stack); log("Finished rendering"); - options.onrendered(renderer.canvas); }, this)); } @@ -505,11 +656,13 @@ NodeParser.prototype.getBounds = function(node) { if (node.getBoundingClientRect) { var clientRect = node.getBoundingClientRect(); var isBody = node.nodeName === "BODY"; + var width = isBody ? node.scrollWidth : node.offsetWidth; return { top: clientRect.top, bottom: clientRect.bottom || (clientRect.top + clientRect.height), + right: clientRect.left + width, left: clientRect.left, - width: isBody ? node.scrollWidth : node.offsetWidth, + width: width, height: isBody ? node.scrollHeight : node.offsetHeight }; } @@ -519,8 +672,8 @@ NodeParser.prototype.getBounds = function(node) { NodeParser.prototype.parseTextBounds = function(container) { return function(text, index, textList) { if (container.parent.css("textDecoration") !== "none" || text.trim().length !== 0) { - var offset = textList.slice(0, index).join("").length; if (this.support.rangeBounds) { + var offset = textList.slice(0, index).join("").length; return this.getRangeBounds(container.node, offset, text.length); } else if (container.node && typeof(container.node.data) === "string") { var replacementNode = container.node.splitText(text.length); @@ -528,7 +681,10 @@ NodeParser.prototype.parseTextBounds = function(container) { container.node = replacementNode; return bounds; } + } else if (!this.support.rangeBounds) { + container.node = container.node.splitText(text.length); } + return {}; }; }; @@ -621,21 +777,41 @@ NodeParser.prototype.paintText = function(container) { var weight = container.parent.fontWeight(); var size = container.parent.css('fontSize'); var family = container.parent.css('fontFamily'); + var shadows = container.parent.parseTextShadows(); + this.renderer.font(container.parent.css('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family); + if (shadows.length) { + // TODO: support multiple text shadows + this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur); + } else { + this.renderer.clearShadow(); + } textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) { if (bounds) { this.renderer.text(textList[index], bounds.left, bounds.bottom); - // renderTextDecoration(ctx, textDecoration, bounds, metrics, color); + this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size)); } - /* var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1), stack.transform.matrix); - if (bounds) { - drawText(text, bounds.left, bounds.bottom, ctx); - renderTextDecoration(ctx, textDecoration, bounds, metrics, color); - } */ }, this); }; +NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { + switch(container.css("textDecoration").split(" ")[0]) { + case "underline": + // Draws a line at the baseline of the font + // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size + this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.css("color")); + break; + case "overline": + this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.css("color")); + break; + case "line-through": + // TODO try and find exact position for line-through + this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.css("color")); + break; + } +}; + NodeParser.prototype.parseBorders = function(container) { var nodeBounds = container.bounds; var radius = getBorderRadiusData(container); @@ -1031,13 +1207,26 @@ Renderer.prototype.renderBorder = function(data) { Renderer.prototype.renderBackgroundImage = function(container, bounds) { var backgroundImages = container.parseBackgroundImages(); backgroundImages.reverse().forEach(function(backgroundImage, index, arr) { - if (backgroundImage.method === "url") { - var image = this.images.get(backgroundImage.args[0]); - if (image) { - this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1)); - } else { - log("Error loading background-image", backgroundImage.args[0]); - } + switch(backgroundImage.method) { + case "url": + var image = this.images.get(backgroundImage.args[0]); + if (image) { + this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1)); + } else { + log("Error loading background-image", backgroundImage.args[0]); + } + break; + case "linear-gradient": + case "gradient": + var gradientImage = this.images.get(backgroundImage.value); + if (gradientImage) { + this.renderBackgroundGradient(gradientImage, bounds); + } else { + log("Error loading background-image", backgroundImage.args[0]); + } + break; + default: + log("Unknown background-image type", backgroundImage.args[0]); } }, this); }; @@ -1076,6 +1265,7 @@ function CanvasRenderer(width, height) { this.canvas.height = height; this.ctx = this.canvas.getContext("2d"); this.ctx.textBaseline = "bottom"; + this.variables = {}; log("Initialized CanvasRenderer"); } @@ -1119,10 +1309,29 @@ CanvasRenderer.prototype.font = function(color, style, variant, weight, size, fa this.setFillStyle(color).font = [style, variant, weight, size, family].join(" "); }; +CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) { + this.setVariable("shadowColor", color) + .setVariable("shadowOffsetY", offsetX) + .setVariable("shadowOffsetX", offsetY) + .setVariable("shadowBlur", blur); +}; + +CanvasRenderer.prototype.clearShadow = function() { + this.setVariable("shadowColor", "rgba(0,0,0,0)"); +}; + CanvasRenderer.prototype.setOpacity = function(opacity) { this.ctx.globalAlpha = opacity; }; +CanvasRenderer.prototype.setVariable = function(property, value) { + if (this.variables[property] !== value) { + this.variables[property] = this.ctx[property] = value; + } + + return this; +}; + CanvasRenderer.prototype.text = function(text, left, bottom) { this.ctx.fillText(text, left, bottom); }; @@ -1147,6 +1356,13 @@ CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backg this.ctx.translate(-offsetX, -offsetY); }; +CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) { + if (gradientImage instanceof LinearGradientContainer) { + var gradient = this.ctx.createLinearGradient(bounds.left, bounds.top, bounds.right, bounds.bottom); + //console.log(gradientImage, bounds, gradient); + } +}; + CanvasRenderer.prototype.resizeImage = function(imageContainer, size) { var image = imageContainer.image; if(image.width === size.width && image.height === size.height) { @@ -1240,4 +1456,11 @@ function capitalize(m, p1, p2) { } } +function WebkitGradientContainer(imageData) { + GradientContainer.apply(this, arguments); + this.type = (imageData.args[0] === "linear") ? this.TYPES.LINEAR : this.TYPES.RADIAL; +} + +WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype); + })(window,document); \ No newline at end of file diff --git a/build/html2canvas.min.js b/build/html2canvas.min.js index 8fc6e15..efbd0c9 100644 --- a/build/html2canvas.min.js +++ b/build/html2canvas.min.js @@ -4,4 +4,4 @@ Released under MIT License */ -(function(t,e){function n(){return Math.max(Math.max(e.body.scrollWidth,e.documentElement.scrollWidth),Math.max(e.body.offsetWidth,e.documentElement.offsetWidth),Math.max(e.body.clientWidth,e.documentElement.clientWidth))}function i(){return Math.max(Math.max(e.body.scrollHeight,e.documentElement.scrollHeight),Math.max(e.body.offsetHeight,e.documentElement.offsetHeight),Math.max(e.body.clientHeight,e.documentElement.clientHeight))}function o(e,n,i){var o=e.documentElement.cloneNode(!0),r=e.createElement("iframe");return r.style.display="hidden",r.style.position="absolute",r.width=n,r.height=i,r.scrolling="no",e.body.appendChild(r),new Promise(function(e){var n=function(){"none"!==r.contentWindow.getComputedStyle(s,null).backgroundImage?(i.body.removeChild(s),i.body.removeChild(a),e(r)):t.setTimeout(n,10)},i=r.contentWindow.document;i.open(),i.write(""),i.close(),i.replaceChild(i.adoptNode(o),i.documentElement),r.contentWindow.scrollTo(t.scrollX,t.scrollY);var s=i.createElement("div");s.className="html2canvas-ready-test",i.body.appendChild(s);var a=i.createElement("style");a.innerHTML="body div.html2canvas-ready-test { background-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); }",i.body.appendChild(a),t.setTimeout(n,1e3)})}function r(t,e){this.src=t,this.image=new Image;var n=this.image;this.promise=new Promise(function(i,o){n.onload=i,n.onerror=o,e&&(n.crossOrigin="anonymous"),n.src=t,n.complete===!0&&i(n)})}function s(e,n){this.link=null,this.options=e,this.support=n,this.origin=t.location.protocol+t.location.host}function a(t){return"IMG"===t.node.nodeName}function c(t){return t.node.src}function u(){t.html2canvas.logging&&t.console&&t.console.log&&t.console.log.apply(t.console,[Date.now()-t.html2canvas.start+"ms","html2canvas:"].concat([].slice.call(arguments,0)))}function h(t,e){this.node=t,this.parent=e,this.stack=null,this.bounds=null,this.visible=null,this.computedStyles=null,this.styles={},this.backgroundImages=null}function p(t){return-1!==(""+t).indexOf("%")}function d(t,e,n,i,o){u("Starting NodeParser"),this.renderer=e,this.options=o,this.range=null,this.support=n,this.stack=new z(!0,1,t.ownerDocument,null);var r=new h(t,null);r.visibile=r.isElementVisible(),this.nodes=[r].concat(this.getChildren(r)).filter(function(t){return t.visible=t.isElementVisible()}),u("Fetched nodes"),this.images=i.fetch(this.nodes.filter(L)),u("Creating stacking contexts"),this.createStackingContexts(),u("Sorting stacking contexts"),this.sortStackingContexts(this.stack),this.images.ready.then(P(function(){u("Images loaded, starting parsing"),this.parse(this.stack),u("Finished rendering"),o.onrendered(e.canvas)},this))}function l(t,e,n,i){var o=4*((Math.sqrt(2)-1)/3),r=n*o,s=i*o,a=t+n,c=e+i;return{topLeft:g({x:t,y:c},{x:t,y:c-s},{x:a-r,y:e},{x:a,y:e}),topRight:g({x:t,y:e},{x:t+r,y:e},{x:a,y:c-s},{x:a,y:c}),bottomRight:g({x:a,y:e},{x:a,y:e+s},{x:t+r,y:c},{x:t,y:c}),bottomLeft:g({x:a,y:c},{x:a-r,y:c},{x:t,y:e+s},{x:t,y:e})}}function f(t,e,n){var i=t.left,o=t.top,r=t.width,s=t.height,a=e[0][0],c=e[0][1],u=e[1][0],h=e[1][1],p=e[2][0],d=e[2][1],f=e[3][0],g=e[3][1],m=r-u,y=s-d,w=r-p,v=s-g;return{topLeftOuter:l(i,o,a,c).topLeft.subdivide(.5),topLeftInner:l(i+n[3].width,o+n[0].width,Math.max(0,a-n[3].width),Math.max(0,c-n[0].width)).topLeft.subdivide(.5),topRightOuter:l(i+m,o,u,h).topRight.subdivide(.5),topRightInner:l(i+Math.min(m,r+n[3].width),o+n[0].width,m>r+n[3].width?0:u-n[3].width,h-n[0].width).topRight.subdivide(.5),bottomRightOuter:l(i+w,o+y,p,d).bottomRight.subdivide(.5),bottomRightInner:l(i+Math.min(w,r+n[3].width),o+Math.min(y,s+n[0].width),Math.max(0,p-n[1].width),Math.max(0,d-n[2].width)).bottomRight.subdivide(.5),bottomLeftOuter:l(i,o+v,f,g).bottomLeft.subdivide(.5),bottomLeftInner:l(i+n[3].width,o+v,Math.max(0,f-n[3].width),Math.max(0,g-n[2].width)).bottomLeft.subdivide(.5)}}function g(t,e,n,i){var o=function(t,e,n){return{x:t.x+(e.x-t.x)*n,y:t.y+(e.y-t.y)*n}};return{start:t,startControl:e,endControl:n,end:i,subdivide:function(r){var s=o(t,e,r),a=o(e,n,r),c=o(n,i,r),u=o(s,a,r),h=o(a,c,r),p=o(u,h,r);return[g(t,s,u,p),g(p,h,c,i)]},curveTo:function(t){t.push(["bezierCurve",e.x,e.y,n.x,n.y,i.x,i.y])},curveToReversed:function(i){i.push(["bezierCurve",n.x,n.y,e.x,e.y,t.x,t.y])}}}function m(t,e,n,i,o,r,s){var a=[];return e[0]>0||e[1]>0?(a.push(["line",i[1].start.x,i[1].start.y]),i[1].curveTo(a)):a.push(["line",t.c1[0],t.c1[1]]),n[0]>0||n[1]>0?(a.push(["line",r[0].start.x,r[0].start.y]),r[0].curveTo(a),a.push(["line",s[0].end.x,s[0].end.y]),s[0].curveToReversed(a)):(a.push(["line",t.c2[0],t.c2[1]]),a.push(["line",t.c3[0],t.c3[1]])),e[0]>0||e[1]>0?(a.push(["line",o[1].end.x,o[1].end.y]),o[1].curveToReversed(a)):a.push(["line",t.c4[0],t.c4[1]]),a}function y(t,e,n,i,o,r,s){e[0]>0||e[1]>0?(t.push(["line",i[0].start.x,i[0].start.y]),i[0].curveTo(t),i[1].curveTo(t)):t.push(["line",r,s]),(n[0]>0||n[1]>0)&&t.push(["line",o[0].start.x,o[0].start.y])}function w(t){return 0>t.cssInt("zIndex")}function v(t){return t.cssInt("zIndex")>0}function b(t){return 0===t.cssInt("zIndex")}function x(t){return-1!==["inline","inline-block","inline-table"].indexOf(t.css("display"))}function k(t){return t instanceof z}function I(t){return t.node.data.trim().length>0}function E(t){return/^(normal|none|0px)$/.test(t.parent.css("letterSpacing"))}function R(t){return["TopLeft","TopRight","BottomRight","BottomLeft"].map(function(e){var n=t.css("border"+e+"Radius"),i=n.split(" ");return 1>=i.length&&(i[1]=i[0]),i.map(_)})}function T(t){return t.nodeType===Node.TEXT_NODE||t.nodeType===Node.ELEMENT_NODE}function B(t){var e=t.css("position"),n="absolute"===e||"relative"===e?t.css("zIndex"):"auto";return"auto"!==n}function C(t){return"static"!==t.css("position")}function O(t){return"none"!==t.css("float")}function S(t){var e=this;return function(){return!t.apply(e,arguments)}}function L(t){return t.node.nodeType===Node.ELEMENT_NODE}function N(t){return t.node.nodeType===Node.TEXT_NODE}function M(t,e){return t.cssInt("zIndex")-e.cssInt("zIndex")}function A(t){return 1>t.css("opacity")}function P(t,e){return function(){return t.apply(e,arguments)}}function _(t){return parseInt(t,10)}function D(t){return t.node.nodeType!==Node.ELEMENT_NODE||-1===["SCRIPT","HEAD","TITLE","OBJECT","BR"].indexOf(t.node.nodeName)}function F(t){return[].concat.apply([],t)}function W(t,e,n){this.width=t,this.height=e,this.images=n}function j(t,n){W.apply(this,arguments),this.canvas=e.createElement("canvas"),this.canvas.width=t,this.canvas.height=n,this.ctx=this.canvas.getContext("2d"),this.ctx.textBaseline="bottom",u("Initialized CanvasRenderer")}function z(t,e,n,i){h.call(this,n,i),this.ownStacking=t,this.contexts=[],this.children=[],this.opacity=(this.parent?this.parent.stack.opacity:1)*e}function H(){this.rangeBounds=this.testRangeBounds(),this.cors=this.testCORS()}function V(t,e){h.call(this,t,e)}function Y(t,e,n){return t.length>0?e+n.toUpperCase():undefined}t.html2canvas=function(r,a){a=a||{},a.logging&&(t.html2canvas.logging=!0,t.html2canvas.start=Date.now()),o(e,t.innerWidth,t.innerHeight).then(function(e){u("Document cloned");var o=e.contentWindow,r=o.document.documentElement,c=new H,h=new s(a,c),p=d.prototype.getBounds(r),l="view"===a.type?Math.min(p.width,t.innerWidth):n(),f="view"===a.type?Math.min(p.height,t.innerHeight):i(),g=new j(l,f,h),m=new d(r,g,c,h,a);t.console.log(m)})},s.prototype.findImages=function(t){var e=[];return t.filter(a).map(c).forEach(this.addImage(e,this.loadImage),this),e},s.prototype.findBackgroundImage=function(t,e){return e.parseBackgroundImages().filter(this.isImageBackground).map(this.getBackgroundUrl).forEach(this.addImage(t,this.loadImage),this),t},s.prototype.addImage=function(t,e){return function(n){this.imageExists(t,n)||(t.splice(0,0,e.apply(this,arguments)),u("Added image #"+t.length,n.substring(0,100)))}},s.prototype.getBackgroundUrl=function(t){return t.args[0]},s.prototype.isImageBackground=function(t){return"url"===t.method},s.prototype.loadImage=function(t){return t.match(/data:image\/.*;base64,/i)?new r(t.replace(/url\(['"]{0,}|['"]{0,}\)$/gi,""),!1):this.isSameOrigin(t)||this.options.allowTaint===!0?new r(t,!1):this.support.cors&&!this.options.allowTaint&&this.options.useCORS?new r(t,!0):this.options.proxy?new ProxyImageContainer(t):new DummyImageContainer(t)},s.prototype.imageExists=function(t,e){return t.some(function(t){return t.src===e})},s.prototype.isSameOrigin=function(t){var n=this.link||(this.link=e.createElement("a"));n.href=t,n.href=n.href;var i=n.protocol+n.host;return i===this.origin},s.prototype.getPromise=function(t){return t.promise},s.prototype.get=function(t){var e=null;return this.images.some(function(n){return(e=n).src===t})?e:null},s.prototype.fetch=function(t){return this.images=t.reduce(P(this.findBackgroundImage,this),this.findImages(t)),this.images.forEach(function(t,e){t.promise.then(function(){u("Succesfully loaded image #"+(e+1))},function(){u("Failed loading image #"+(e+1))})}),this.ready=Promise.all(this.images.map(this.getPromise)),u("Finished searching images"),this},h.prototype.assignStack=function(t){this.stack=t,t.children.push(this)},h.prototype.isElementVisible=function(){return this.node.nodeType===Node.TEXT_NODE?this.parent.visible:"none"!==this.css("display")&&"hidden"!==this.css("visibility")&&!this.node.hasAttribute("data-html2canvas-ignore")},h.prototype.css=function(t){return this.computedStyles||(this.computedStyles=this.node.ownerDocument.defaultView.getComputedStyle(this.node,null)),this.styles[t]||(this.styles[t]=this.computedStyles[t])},h.prototype.cssInt=function(t){var e=parseInt(this.css(t),10);return isNaN(e)?0:e},h.prototype.cssFloat=function(t){var e=parseFloat(this.css(t));return isNaN(e)?0:e},h.prototype.fontWeight=function(){var t=this.css("fontWeight");switch(parseInt(t,10)){case 401:t="bold";break;case 400:t="normal"}return t},h.prototype.parseBackgroundImages=function(){var t,e,n,i,o,r,s,a=" \r\n ",c=[],u=0,h=0,p=function(){t&&('"'===e.substr(0,1)&&(e=e.substr(1,e.length-2)),e&&s.push(e),"-"===t.substr(0,1)&&(i=t.indexOf("-",1)+1)>0&&(n=t.substr(0,i),t=t.substr(i)),c.push({prefix:n,method:t.toLowerCase(),value:o,args:s,image:null})),s=[],t=n=e=o=""};return s=[],t=n=e=o="",this.css("backgroundImage").split("").forEach(function(n){if(!(0===u&&a.indexOf(n)>-1)){switch(n){case'"':r?r===n&&(r=null):r=n;break;case"(":if(r)break;if(0===u)return u=1,o+=n,undefined;h++;break;case")":if(r)break;if(1===u){if(0===h)return u=0,o+=n,p(),undefined;h--}break;case",":if(r)break;if(0===u)return p(),undefined;if(1===u&&0===h&&!t.match(/^url$/i))return s.push(e),e="",o+=n,undefined}o+=n,0===u?t+=n:e+=n}}),p(),this.backgroundImages||(this.backgroundImages=c)},h.prototype.cssList=function(t,e){var n=(this.css(t)||"").split(",");return n=n[e||0]||n[0]||"auto",n=n.trim().split(" "),1===n.length&&(n=[n[0],n[0]]),n},h.prototype.parseBackgroundSize=function(t,e,n){var i,o,r=this.cssList("backgroundSize",n);if(p(r[0]))i=t.width*parseFloat(r[0])/100;else{if(/contain|cover/.test(r[0])){var s=t.width/t.height,a=e.width/e.height;return a>s^"contain"===r[0]?{width:t.height*a,height:t.height}:{width:t.width,height:t.width/a}}i=parseInt(r[0],10)}return o="auto"===r[0]&&"auto"===r[1]?e.height:"auto"===r[1]?i/e.width*e.height:p(r[1])?t.height*parseFloat(r[1])/100:parseInt(r[1],10),"auto"===r[0]&&(i=o/e.height*e.width),{width:i,height:o}},h.prototype.parseBackgroundPosition=function(t,e,n,i){var o,r,s=this.cssList("backgroundPosition",n);return o=p(s[0])?(t.width-(i||e).width)*(parseFloat(s[0])/100):parseInt(s[0],10),r="auto"===s[1]?o/e.width*e.height:p(s[1])?(t.height-(i||e).height)*parseFloat(s[1])/100:parseInt(s[1],10),"auto"===s[0]&&(o=r/e.height*e.width),{left:o,top:r}},h.prototype.parseBackgroundRepeat=function(t){return this.cssList("backgroundRepeat",t)[0]},d.prototype.getChildren=function(t){return F([].filter.call(t.node.childNodes,T).map(function(e){var n=[e.nodeType===Node.TEXT_NODE?new V(e,t):new h(e,t)].filter(D);return e.nodeType===Node.ELEMENT_NODE&&n.length?n[0].isElementVisible()?n.concat(this.getChildren(n[0])):[]:n},this))},d.prototype.newStackingContext=function(t,e){var n=new z(e,t.cssFloat("opacity"),t.node,t.parent);n.visible=t.visible;var i=n.getParentStack(this);i.contexts.push(n),t.stack=n},d.prototype.createStackingContexts=function(){this.nodes.forEach(function(t){L(t)&&(this.isRootElement(t)||A(t)||B(t)||this.isBodyWithTransparentRoot(t))?this.newStackingContext(t,!0):L(t)&&C(t)?this.newStackingContext(t,!1):t.assignStack(t.parent.stack)},this)},d.prototype.isBodyWithTransparentRoot=function(t){return"BODY"===t.node.nodeName&&this.renderer.isTransparent(t.parent.css("backgroundColor"))},d.prototype.isRootElement=function(t){return"HTML"===t.node.nodeName},d.prototype.sortStackingContexts=function(t){t.contexts.sort(M),t.contexts.forEach(this.sortStackingContexts,this)},d.prototype.parseBounds=function(t){return t.bounds=this.getBounds(t.node)},d.prototype.getBounds=function(t){if(t.getBoundingClientRect){var e=t.getBoundingClientRect(),n="BODY"===t.nodeName;return{top:e.top,bottom:e.bottom||e.top+e.height,left:e.left,width:n?t.scrollWidth:t.offsetWidth,height:n?t.scrollHeight:t.offsetHeight}}return{}},d.prototype.parseTextBounds=function(t){return function(e,n,i){if("none"!==t.parent.css("textDecoration")||0!==e.trim().length){var o=i.slice(0,n).join("").length;if(this.support.rangeBounds)return this.getRangeBounds(t.node,o,e.length);if(t.node&&"string"==typeof t.node.data){var r=t.node.splitText(e.length),s=this.getWrapperBounds(t.node);return t.node=r,s}}}},d.prototype.getWrapperBounds=function(t){var e=t.ownerDocument.createElement("wrapper"),n=t.parentNode,i=t.cloneNode(!0);e.appendChild(t.cloneNode(!0)),n.replaceChild(e,t);var o=this.getBounds(e);return n.replaceChild(i,e),o},d.prototype.getRangeBounds=function(t,e,n){var i=this.range||(this.range=t.ownerDocument.createRange());return i.setStart(t,e),i.setEnd(t,e+n),i.getBoundingClientRect()},d.prototype.parse=function(t){var e=t.contexts.filter(w),n=t.children.filter(L),i=n.filter(S(O)),o=i.filter(S(C)).filter(S(x)),r=n.filter(S(C)).filter(O),s=i.filter(S(C)).filter(x),a=t.contexts.concat(i.filter(C)).filter(b),c=t.children.filter(N).filter(I),h=t.contexts.filter(v),p=[];e.concat(o).concat(r).concat(s).concat(a).concat(c).concat(h).forEach(function(t){if(this.paint(t),-1!==p.indexOf(t.node))throw u(t,t.node),Error("rendering twice");p.push(t.node),k(t)&&this.parse(t)},this)},d.prototype.paint=function(t){try{N(t)?this.paintText(t):this.paintNode(t)}catch(e){u(e)}},d.prototype.paintNode=function(t){k(t)&&this.renderer.setOpacity(t.opacity);var e=this.parseBounds(t),n=this.parseBorders(t);switch(this.renderer.clip(n.clip,function(){this.renderer.renderBackground(t,e)},this),this.renderer.renderBorders(n.borders),t.node.nodeName){case"IMG":var i=this.images.get(t.node.src);i?this.renderer.renderImage(t,e,n,i.image):u("Error loading ",t.node.src)}},d.prototype.paintText=function(t){t.applyTextTransform();var e=t.node.data.split(!this.options.letterRendering||E(t)?/(\b| )/:""),n=t.parent.fontWeight(),i=t.parent.css("fontSize"),o=t.parent.css("fontFamily");this.renderer.font(t.parent.css("color"),t.parent.css("fontStyle"),t.parent.css("fontVariant"),n,i,o),e.map(this.parseTextBounds(t),this).forEach(function(t,n){t&&this.renderer.text(e[n],t.left,t.bottom)},this)},d.prototype.parseBorders=function(t){var e=t.bounds,n=R(t),i=["Top","Right","Bottom","Left"].map(function(e){return{width:t.cssInt("border"+e+"Width"),color:t.css("border"+e+"Color"),args:null}}),o=f(e,n,i);return{clip:this.parseBackgroundClip(t,o,i,n,e),borders:i.map(function(t,r){if(t.width>0){var s=e.left,a=e.top,c=e.width,u=e.height-i[2].width;switch(r){case 0:u=i[0].width,t.args=m({c1:[s,a],c2:[s+c,a],c3:[s+c-i[1].width,a+u],c4:[s+i[3].width,a+u]},n[0],n[1],o.topLeftOuter,o.topLeftInner,o.topRightOuter,o.topRightInner);break;case 1:s=e.left+e.width-i[1].width,c=i[1].width,t.args=m({c1:[s+c,a],c2:[s+c,a+u+i[2].width],c3:[s,a+u],c4:[s,a+i[0].width]},n[1],n[2],o.topRightOuter,o.topRightInner,o.bottomRightOuter,o.bottomRightInner);break;case 2:a=a+e.height-i[2].width,u=i[2].width,t.args=m({c1:[s+c,a+u],c2:[s,a+u],c3:[s+i[3].width,a],c4:[s+c-i[3].width,a]},n[2],n[3],o.bottomRightOuter,o.bottomRightInner,o.bottomLeftOuter,o.bottomLeftInner);break;case 3:c=i[3].width,t.args=m({c1:[s,a+u+i[2].width],c2:[s,a],c3:[s+c,a+i[0].width],c4:[s+c,a+u]},n[3],n[0],o.bottomLeftOuter,o.bottomLeftInner,o.topLeftOuter,o.topLeftInner)}}return t})}},d.prototype.parseBackgroundClip=function(t,e,n,i,o){var r=t.css("backgroundClip"),s=[];switch(r){case"content-box":case"padding-box":y(s,i[0],i[1],e.topLeftInner,e.topRightInner,o.left+n[3].width,o.top+n[0].width),y(s,i[1],i[2],e.topRightInner,e.bottomRightInner,o.left+o.width-n[1].width,o.top+n[0].width),y(s,i[2],i[3],e.bottomRightInner,e.bottomLeftInner,o.left+o.width-n[1].width,o.top+o.height-n[2].width),y(s,i[3],i[0],e.bottomLeftInner,e.topLeftInner,o.left+n[3].width,o.top+o.height-n[2].width);break;default:y(s,i[0],i[1],e.topLeftOuter,e.topRightOuter,o.left,o.top),y(s,i[1],i[2],e.topRightOuter,e.bottomRightOuter,o.left+o.width,o.top),y(s,i[2],i[3],e.bottomRightOuter,e.bottomLeftOuter,o.left+o.width,o.top+o.height),y(s,i[3],i[0],e.bottomLeftOuter,e.topLeftOuter,o.left,o.top+o.height)}return s},!function(){var n,i,o,r;!function(){var t={},e={};n=function(e,n,i){t[e]={deps:n,callback:i}},r=o=i=function(n){function o(t){if("."!==t.charAt(0))return t;for(var e=t.split("/"),i=n.split("/").slice(0,-1),o=0,r=e.length;r>o;o++){var s=e[o];if(".."===s)i.pop();else{if("."===s)continue;i.push(s)}}return i.join("/")}if(r._eak_seen=t,e[n])return e[n];if(e[n]={},!t[n])throw Error("Could not find module "+n);for(var s,a=t[n],c=a.deps,u=a.callback,h=[],p=0,d=c.length;d>p;p++)"exports"===c[p]?h.push(s={}):h.push(i(o(c[p])));var l=u.apply(this,h);return e[n]=s||l}}(),n("promise/all",["./utils","exports"],function(t,e){"use strict";function n(t){var e=this;if(!i(t))throw new TypeError("You must pass an array to all.");return new e(function(e,n){function i(t){return function(e){r(t,e)}}function r(t,n){a[t]=n,0===--c&&e(a)}var s,a=[],c=t.length;0===c&&e([]);for(var u=0;t.length>u;u++)s=t[u],s&&o(s.then)?s.then(i(u),n):r(u,s)})}var i=t.isArray,o=t.isFunction;e.all=n}),n("promise/asap",["exports"],function(n){"use strict";function i(){return function(){process.nextTick(s)}}function o(){var t=0,n=new h(s),i=e.createTextNode("");return n.observe(i,{characterData:!0}),function(){i.data=t=++t%2}}function r(){return function(){p.setTimeout(s,1)}}function s(){for(var t=0;d.length>t;t++){var e=d[t],n=e[0],i=e[1];n(i)}d=[]}function a(t,e){var n=d.push([t,e]);1===n&&c()}var c,u=t!==undefined?t:{},h=u.MutationObserver||u.WebKitMutationObserver,p="undefined"!=typeof global?global:this,d=[];c="undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?i():h?o():r(),n.asap=a}),n("promise/cast",["exports"],function(t){"use strict";function e(t){if(t&&"object"==typeof t&&t.constructor===this)return t;var e=this;return new e(function(e){e(t)})}t.cast=e}),n("promise/config",["exports"],function(t){"use strict";function e(t,e){return 2!==arguments.length?n[t]:(n[t]=e,void 0)}var n={instrument:!1};t.config=n,t.configure=e}),n("promise/polyfill",["./promise","./utils","exports"],function(e,n,i){"use strict";function o(){var e="Promise"in t&&"cast"in t.Promise&&"resolve"in t.Promise&&"reject"in t.Promise&&"all"in t.Promise&&"race"in t.Promise&&function(){var e;return new t.Promise(function(t){e=t}),s(e)}();e||(t.Promise=r)}var r=e.Promise,s=n.isFunction;i.polyfill=o}),n("promise/promise",["./config","./utils","./cast","./all","./race","./resolve","./reject","./asap","exports"],function(t,e,n,i,o,r,s,a,c){"use strict";function u(t){if(!k(t))throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(!(this instanceof u))throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");this._subscribers=[],h(t,this)}function h(t,e){function n(t){g(e,t)}function i(t){y(e,t)}try{t(n,i)}catch(o){i(o)}}function p(t,e,n,i){var o,r,s,a,c=k(n);if(c)try{o=n(i),s=!0}catch(u){a=!0,r=u}else o=i,s=!0;f(e,o)||(c&&s?g(e,o):a?y(e,r):t===L?g(e,o):t===N&&y(e,o))}function d(t,e,n,i){var o=t._subscribers,r=o.length;o[r]=e,o[r+L]=n,o[r+N]=i}function l(t,e){for(var n,i,o=t._subscribers,r=t._detail,s=0;o.length>s;s+=3)n=o[s],i=o[s+e],p(e,n,i,r);t._subscribers=null}function f(t,e){var n,i=null;try{if(t===e)throw new TypeError("A promises callback cannot return that same promise.");if(x(e)&&(i=e.then,k(i)))return i.call(e,function(i){return n?!0:(n=!0,e!==i?g(t,i):m(t,i),void 0)},function(e){return n?!0:(n=!0,y(t,e),void 0)}),!0}catch(o){return n?!0:(y(t,o),!0)}return!1}function g(t,e){t===e?m(t,e):f(t,e)||m(t,e)}function m(t,e){t._state===O&&(t._state=S,t._detail=e,b.async(w,t))}function y(t,e){t._state===O&&(t._state=S,t._detail=e,b.async(v,t))}function w(t){l(t,t._state=L)}function v(t){l(t,t._state=N)}var b=t.config,x=(t.configure,e.objectOrFunction),k=e.isFunction,I=(e.now,n.cast),E=i.all,R=o.race,T=r.resolve,B=s.reject,C=a.asap;b.async=C;var O=void 0,S=0,L=1,N=2;u.prototype={constructor:u,_state:void 0,_detail:void 0,_subscribers:void 0,then:function(t,e){var n=this,i=new this.constructor(function(){});if(this._state){var o=arguments;b.async(function(){p(n._state,i,o[n._state-1],n._detail)})}else d(this,i,t,e);return i},"catch":function(t){return this.then(null,t)}},u.all=E,u.cast=I,u.race=R,u.resolve=T,u.reject=B,c.Promise=u}),n("promise/race",["./utils","exports"],function(t,e){"use strict";function n(t){var e=this;if(!i(t))throw new TypeError("You must pass an array to race.");return new e(function(e,n){for(var i,o=0;t.length>o;o++)i=t[o],i&&"function"==typeof i.then?i.then(e,n):e(i)})}var i=t.isArray;e.race=n}),n("promise/reject",["exports"],function(t){"use strict";function e(t){var e=this;return new e(function(e,n){n(t)})}t.reject=e}),n("promise/resolve",["exports"],function(t){"use strict";function e(t){var e=this;return new e(function(e){e(t)})}t.resolve=e}),n("promise/utils",["exports"],function(t){"use strict";function e(t){return n(t)||"object"==typeof t&&null!==t}function n(t){return"function"==typeof t}function i(t){return"[object Array]"===Object.prototype.toString.call(t)}var o=Date.now||function(){return(new Date).getTime()};t.objectOrFunction=e,t.isFunction=n,t.isArray=i,t.now=o}),i("promise/polyfill").polyfill()}(),W.prototype.renderImage=function(t,e,n,i){var o=t.cssInt("paddingLeft"),r=t.cssInt("paddingTop"),s=t.cssInt("paddingRight"),a=t.cssInt("paddingBottom"),c=n.borders;this.drawImage(i,0,0,i.width,i.height,e.left+o+c[3].width,e.top+r+c[0].width,e.width-(c[1].width+c[3].width+o+s),e.height-(c[0].width+c[2].width+r+a))},W.prototype.renderBackground=function(t,e){e.height>0&&e.width>0&&(this.renderBackgroundColor(t,e),this.renderBackgroundImage(t,e))},W.prototype.renderBackgroundColor=function(t,e){var n=t.css("backgroundColor");this.isTransparent(n)||this.rectangle(e.left,e.top,e.width,e.height,t.css("backgroundColor"))},W.prototype.renderBorders=function(t){t.forEach(this.renderBorder,this)},W.prototype.renderBorder=function(t){this.isTransparent(t.color)||null===t.args||this.drawShape(t.args,t.color)},W.prototype.renderBackgroundImage=function(t,e){var n=t.parseBackgroundImages();n.reverse().forEach(function(n,i,o){if("url"===n.method){var r=this.images.get(n.args[0]);r?this.renderBackgroundRepeating(t,e,r,o.length-(i+1)):u("Error loading background-image",n.args[0])}},this)},W.prototype.renderBackgroundRepeating=function(t,e,n,i){var o=t.parseBackgroundSize(e,n.image,i),r=t.parseBackgroundPosition(e,n.image,i,o),s=t.parseBackgroundRepeat(i);switch(s){case"repeat-x":case"repeat no-repeat":this.backgroundRepeatShape(n,r,o,e,e.left,e.top+r.top,99999,n.image.height);break;case"repeat-y":case"no-repeat repeat":this.backgroundRepeatShape(n,r,o,e,e.left+r.left,e.top,n.image.width,99999);break;case"no-repeat":this.backgroundRepeatShape(n,r,o,e,e.left+r.left,e.top+r.top,n.image.width,n.image.height);break;default:this.renderBackgroundRepeat(n,r,o,{top:e.top,left:e.left})}},W.prototype.isTransparent=function(t){return!t||"transparent"===t||"rgba(0, 0, 0, 0)"===t},j.prototype=Object.create(W.prototype),j.prototype.setFillStyle=function(t){return this.ctx.fillStyle=t,this.ctx},j.prototype.rectangle=function(t,e,n,i,o){this.setFillStyle(o).fillRect(t,e,n,i)},j.prototype.drawShape=function(t,e){this.shape(t),this.setFillStyle(e).fill()},j.prototype.drawImage=function(t,e,n,i,o,r,s,a,c){this.ctx.drawImage(t,e,n,i,o,r,s,a,c)},j.prototype.clip=function(t,e,n){this.ctx.save(),this.shape(t).clip(),e.call(n),this.ctx.restore()},j.prototype.shape=function(t){return this.ctx.beginPath(),t.forEach(function(t,e){this.ctx[0===e?"moveTo":t[0]+"To"].apply(this.ctx,t.slice(1))},this),this.ctx.closePath(),this.ctx},j.prototype.font=function(t,e,n,i,o,r){this.setFillStyle(t).font=[e,n,i,o,r].join(" ")},j.prototype.setOpacity=function(t){this.ctx.globalAlpha=t},j.prototype.text=function(t,e,n){this.ctx.fillText(t,e,n)},j.prototype.backgroundRepeatShape=function(t,e,n,i,o,r,s,a){var c=[["line",Math.round(o),Math.round(r)],["line",Math.round(o+s),Math.round(r)],["line",Math.round(o+s),Math.round(a+r)],["line",Math.round(o),Math.round(a+r)]];this.clip(c,function(){this.renderBackgroundRepeat(t,e,n,i)},this)},j.prototype.renderBackgroundRepeat=function(t,e,n,i){var o=Math.round(i.left+e.left),r=Math.round(i.top+e.top);this.setFillStyle(this.ctx.createPattern(this.resizeImage(t,n),"repeat")),this.ctx.translate(o,r),this.ctx.fill(),this.ctx.translate(-o,-r)},j.prototype.resizeImage=function(t,n){var i=t.image;if(i.width===n.width&&i.height===n.height)return i;var o,r=e.createElement("canvas");return r.width=n.width,r.height=n.height,o=r.getContext("2d"),o.drawImage(i,0,0,i.width,i.height,0,0,n.width,n.height),r},z.prototype=Object.create(h.prototype),z.prototype.getParentStack=function(t){var e=this.parent?this.parent.stack:null;return e?e.ownStacking?e:e.getParentStack(t):t.stack},H.prototype.testRangeBounds=function(){var t,n,i,o,r=!1;return e.createRange&&(t=e.createRange(),t.getBoundingClientRect&&(n=e.createElement("boundtest"),n.style.height="123px",n.style.display="block",e.body.appendChild(n),t.selectNode(n),i=t.getBoundingClientRect(),o=i.height,123===o&&(r=!0),e.body.removeChild(n))),r},H.prototype.testCORS=function(){return(new Image).crossOrigin!==undefined},V.prototype=Object.create(h.prototype),V.prototype.applyTextTransform=function(){this.node.data=this.transform(this.parent.css("textTransform"))},V.prototype.transform=function(t){var e=this.node.data;switch(t){case"lowercase":return e.toLowerCase();case"capitalize":return e.replace(/(^|\s|:|-|\(|\))([a-z])/g,Y);case"uppercase":return e.toUpperCase();default:return e}}})(window,document); \ No newline at end of file +(function(t,e,n){function r(t,e,n,r){return a(t,n,r).then(function(t){m("Document cloned");var n=t.contentWindow,r=n.document.documentElement,s=new q,a=new d(e,s),c=w.prototype.getBounds(r),h="view"===e.type?Math.min(c.width,h):i(),u="view"===e.type?Math.min(c.height,u):o(),p=new U(h,u,a),l=new w(r,p,s,a,e);return l.ready.then(function(){return t.parentNode.removeChild(t),p.canvas})})}function i(){return Math.max(Math.max(e.body.scrollWidth,e.documentElement.scrollWidth),Math.max(e.body.offsetWidth,e.documentElement.offsetWidth),Math.max(e.body.clientWidth,e.documentElement.clientWidth))}function o(){return Math.max(Math.max(e.body.scrollHeight,e.documentElement.scrollHeight),Math.max(e.body.offsetHeight,e.documentElement.offsetHeight),Math.max(e.body.clientHeight,e.documentElement.clientHeight))}function s(){return"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"}function a(e,n,r){var i=e.documentElement.cloneNode(!0),o=e.createElement("iframe");return o.style.visibility="hidden",o.style.position="absolute",o.width=n,o.height=r,o.scrolling="no",e.body.appendChild(o),new Promise(function(e){var n=function(){"none"!==o.contentWindow.getComputedStyle(a,null).backgroundImage?(r.body.removeChild(a),r.body.removeChild(c),e(o)):t.setTimeout(n,10)},r=o.contentWindow.document;r.open(),r.write(""),r.close(),r.replaceChild(r.adoptNode(i),r.documentElement),o.contentWindow.scrollTo(t.scrollX,t.scrollY);var a=r.createElement("div");a.className="html2canvas-ready-test",r.body.appendChild(a);var c=r.createElement("style");c.innerHTML="body div.html2canvas-ready-test { background-image:url("+s()+"); }",r.body.appendChild(c),t.setTimeout(n,1e3)})}function c(t,n){var r,i,o=e.createElement("div"),a=e.createElement("img"),c=e.createElement("span"),h="Hidden Text";o.style.visibility="hidden",o.style.fontFamily=t,o.style.fontSize=n,o.style.margin=0,o.style.padding=0,e.body.appendChild(o),a.src=s(),a.width=1,a.height=1,a.style.margin=0,a.style.padding=0,a.style.verticalAlign="baseline",c.style.fontFamily=t,c.style.fontSize=n,c.style.margin=0,c.style.padding=0,c.appendChild(e.createTextNode(h)),o.appendChild(c),o.appendChild(a),r=a.offsetTop-c.offsetTop+1,o.removeChild(c),o.appendChild(e.createTextNode(h)),o.style.lineHeight="normal",a.style.verticalAlign="super",i=a.offsetTop-o.offsetTop+1,e.body.removeChild(o),this.baseline=r,this.lineWidth=1,this.middle=i}function h(){this.data={}}function u(t){this.src=t.value,this.colorStops=[],this.type=null,this.x0=.5,this.y0=.5,this.x1=.5,this.y1=.5,this.promise=Promise.resolve(!0)}function p(t,e){this.src=t,this.image=new Image;var n=this.image;this.promise=new Promise(function(r,i){n.onload=r,n.onerror=i,e&&(n.crossOrigin="anonymous"),n.src=t,n.complete===!0&&r(n)})}function d(e,n){this.link=null,this.options=e,this.support=n,this.origin=t.location.protocol+t.location.host}function l(t){return"IMG"===t.node.nodeName}function f(t){return t.node.src}function g(t){u.apply(this,arguments),this.type=this.TYPES.LINEAR,t.args[0].split(" ").forEach(function(t){switch(t){case"left":this.x0=0,this.x1=1;break;case"top":this.y0=0,this.y1=1;break;case"right":this.x0=1,this.x1=0;break;case"bottom":this.y0=1,this.y1=0}},this),t.args.slice(1).forEach(function(){},this)}function m(){t.html2canvas.logging&&t.console&&t.console.log&&t.console.log.apply(t.console,[Date.now()-t.html2canvas.start+"ms","html2canvas:"].concat([].slice.call(arguments,0)))}function y(t,e){this.node=t,this.parent=e,this.stack=null,this.bounds=null,this.visible=null,this.computedStyles=null,this.styles={},this.backgroundImages=null}function b(t){return-1!==(""+t).indexOf("%")}function w(t,e,n,r,i){m("Starting NodeParser"),this.renderer=e,this.options=i,this.range=null,this.support=n,this.stack=new $(!0,1,t.ownerDocument,null);var o=new y(t,null);o.visibile=o.isElementVisible(),this.nodes=[o].concat(this.getChildren(o)).filter(function(t){return t.visible=t.isElementVisible()}),this.fontMetrics=new h,m("Fetched nodes"),this.images=r.fetch(this.nodes.filter(W)),m("Creating stacking contexts"),this.createStackingContexts(),m("Sorting stacking contexts"),this.sortStackingContexts(this.stack),this.ready=this.images.ready.then(H(function(){m("Images loaded, starting parsing"),this.parse(this.stack),m("Finished rendering")},this))}function v(t,e,n,r){var i=4*((Math.sqrt(2)-1)/3),o=n*i,s=r*i,a=t+n,c=e+r;return{topLeft:k({x:t,y:c},{x:t,y:c-s},{x:a-o,y:e},{x:a,y:e}),topRight:k({x:t,y:e},{x:t+o,y:e},{x:a,y:c-s},{x:a,y:c}),bottomRight:k({x:a,y:e},{x:a,y:e+s},{x:t+o,y:c},{x:t,y:c}),bottomLeft:k({x:a,y:c},{x:a-o,y:c},{x:t,y:e+s},{x:t,y:e})}}function x(t,e,n){var r=t.left,i=t.top,o=t.width,s=t.height,a=e[0][0],c=e[0][1],h=e[1][0],u=e[1][1],p=e[2][0],d=e[2][1],l=e[3][0],f=e[3][1],g=o-h,m=s-d,y=o-p,b=s-f;return{topLeftOuter:v(r,i,a,c).topLeft.subdivide(.5),topLeftInner:v(r+n[3].width,i+n[0].width,Math.max(0,a-n[3].width),Math.max(0,c-n[0].width)).topLeft.subdivide(.5),topRightOuter:v(r+g,i,h,u).topRight.subdivide(.5),topRightInner:v(r+Math.min(g,o+n[3].width),i+n[0].width,g>o+n[3].width?0:h-n[3].width,u-n[0].width).topRight.subdivide(.5),bottomRightOuter:v(r+y,i+m,p,d).bottomRight.subdivide(.5),bottomRightInner:v(r+Math.min(y,o+n[3].width),i+Math.min(m,s+n[0].width),Math.max(0,p-n[1].width),Math.max(0,d-n[2].width)).bottomRight.subdivide(.5),bottomLeftOuter:v(r,i+b,l,f).bottomLeft.subdivide(.5),bottomLeftInner:v(r+n[3].width,i+b,Math.max(0,l-n[3].width),Math.max(0,f-n[2].width)).bottomLeft.subdivide(.5)}}function k(t,e,n,r){var i=function(t,e,n){return{x:t.x+(e.x-t.x)*n,y:t.y+(e.y-t.y)*n}};return{start:t,startControl:e,endControl:n,end:r,subdivide:function(o){var s=i(t,e,o),a=i(e,n,o),c=i(n,r,o),h=i(s,a,o),u=i(a,c,o),p=i(h,u,o);return[k(t,s,h,p),k(p,u,c,r)]},curveTo:function(t){t.push(["bezierCurve",e.x,e.y,n.x,n.y,r.x,r.y])},curveToReversed:function(r){r.push(["bezierCurve",n.x,n.y,e.x,e.y,t.x,t.y])}}}function E(t,e,n,r,i,o,s){var a=[];return e[0]>0||e[1]>0?(a.push(["line",r[1].start.x,r[1].start.y]),r[1].curveTo(a)):a.push(["line",t.c1[0],t.c1[1]]),n[0]>0||n[1]>0?(a.push(["line",o[0].start.x,o[0].start.y]),o[0].curveTo(a),a.push(["line",s[0].end.x,s[0].end.y]),s[0].curveToReversed(a)):(a.push(["line",t.c2[0],t.c2[1]]),a.push(["line",t.c3[0],t.c3[1]])),e[0]>0||e[1]>0?(a.push(["line",i[1].end.x,i[1].end.y]),i[1].curveToReversed(a)):a.push(["line",t.c4[0],t.c4[1]]),a}function T(t,e,n,r,i,o,s){e[0]>0||e[1]>0?(t.push(["line",r[0].start.x,r[0].start.y]),r[0].curveTo(t),r[1].curveTo(t)):t.push(["line",o,s]),(n[0]>0||n[1]>0)&&t.push(["line",i[0].start.x,i[0].start.y])}function I(t){return 0>t.cssInt("zIndex")}function R(t){return t.cssInt("zIndex")>0}function B(t){return 0===t.cssInt("zIndex")}function S(t){return-1!==["inline","inline-block","inline-table"].indexOf(t.css("display"))}function C(t){return t instanceof $}function O(t){return t.node.data.trim().length>0}function A(t){return/^(normal|none|0px)$/.test(t.parent.css("letterSpacing"))}function L(t){return["TopLeft","TopRight","BottomRight","BottomLeft"].map(function(e){var n=t.css("border"+e+"Radius"),r=n.split(" ");return 1>=r.length&&(r[1]=r[0]),r.map(Y)})}function N(t){return t.nodeType===Node.TEXT_NODE||t.nodeType===Node.ELEMENT_NODE}function M(t){var e=t.css("position"),n="absolute"===e||"relative"===e?t.css("zIndex"):"auto";return"auto"!==n}function P(t){return"static"!==t.css("position")}function _(t){return"none"!==t.css("float")}function D(t){var e=this;return function(){return!t.apply(e,arguments)}}function W(t){return t.node.nodeType===Node.ELEMENT_NODE}function F(t){return t.node.nodeType===Node.TEXT_NODE}function j(t,e){return t.cssInt("zIndex")-e.cssInt("zIndex")}function z(t){return 1>t.css("opacity")}function H(t,e){return function(){return t.apply(e,arguments)}}function Y(t){return parseInt(t,10)}function V(t){return t.node.nodeType!==Node.ELEMENT_NODE||-1===["SCRIPT","HEAD","TITLE","OBJECT","BR"].indexOf(t.node.nodeName)}function X(t){return[].concat.apply([],t)}function G(t,e,n){this.width=t,this.height=e,this.images=n}function U(t,n){G.apply(this,arguments),this.canvas=e.createElement("canvas"),this.canvas.width=t,this.canvas.height=n,this.ctx=this.canvas.getContext("2d"),this.ctx.textBaseline="bottom",this.variables={},m("Initialized CanvasRenderer")}function $(t,e,n,r){y.call(this,n,r),this.ownStacking=t,this.contexts=[],this.children=[],this.opacity=(this.parent?this.parent.stack.opacity:1)*e}function q(){this.rangeBounds=this.testRangeBounds(),this.cors=this.testCORS()}function J(t,e){y.call(this,t,e)}function K(t,e,r){return t.length>0?e+r.toUpperCase():n}function Q(t){u.apply(this,arguments),this.type="linear"===t.args[0]?this.TYPES.LINEAR:this.TYPES.RADIAL}t.html2canvas=function(n,i){return i=i||{},i.logging&&(t.html2canvas.logging=!0,t.html2canvas.start=Date.now()),r(e,i,t.innerWidth,t.innerHeight).then(function(t){return"function"==typeof i.onrendered&&(m("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"),i.onrendered(t)),t})},h.prototype.getMetrics=function(t,e){return this.data[t+"-"+e]===n&&(this.data[t+"-"+e]=new c(t,e)),this.data[t+"-"+e]},u.prototype.TYPES={LINEAR:1,RADIAL:2},d.prototype.findImages=function(t){var e=[];return t.filter(l).map(f).forEach(this.addImage(e,this.loadImage),this),e},d.prototype.findBackgroundImage=function(t,e){return e.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(t,this.loadImage),this),t},d.prototype.addImage=function(t,e){return function(n){this.imageExists(t,n)||(t.splice(0,0,e.apply(this,arguments)),m("Added image #"+t.length,n))}},d.prototype.hasImageBackground=function(t){return"none"!==t.method},d.prototype.loadImage=function(t){if("url"===t.method){var e=t.args[0];return e.match(/data:image\/.*;base64,/i)?new p(e.replace(/url\(['"]{0,}|['"]{0,}\)$/gi,""),!1):this.isSameOrigin(e)||this.options.allowTaint===!0?new p(e,!1):this.support.cors&&!this.options.allowTaint&&this.options.useCORS?new p(e,!0):this.options.proxy?new ProxyImageContainer(e):new DummyImageContainer(e)}return"linear-gradient"===t.method?new g(t):"gradient"===t.method?new Q(t):n},d.prototype.imageExists=function(t,e){return t.some(function(t){return t.src===e})},d.prototype.isSameOrigin=function(t){var n=this.link||(this.link=e.createElement("a"));n.href=t,n.href=n.href;var r=n.protocol+n.host;return r===this.origin},d.prototype.getPromise=function(t){return t.promise},d.prototype.get=function(t){var e=null;return this.images.some(function(n){return(e=n).src===t})?e:null},d.prototype.fetch=function(t){return this.images=t.reduce(H(this.findBackgroundImage,this),this.findImages(t)),this.images.forEach(function(t,e){t.promise.then(function(){m("Succesfully loaded image #"+(e+1))},function(){m("Failed loading image #"+(e+1))})}),this.ready=Promise.all(this.images.map(this.getPromise)),m("Finished searching images"),this},g.prototype=Object.create(u.prototype),g.prototype.stepRegExp=/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/,y.prototype.assignStack=function(t){this.stack=t,t.children.push(this)},y.prototype.isElementVisible=function(){return this.node.nodeType===Node.TEXT_NODE?this.parent.visible:"none"!==this.css("display")&&"hidden"!==this.css("visibility")&&!this.node.hasAttribute("data-html2canvas-ignore")},y.prototype.css=function(t){return this.computedStyles||(this.computedStyles=this.node.ownerDocument.defaultView.getComputedStyle(this.node,null)),this.styles[t]||(this.styles[t]=this.computedStyles[t])},y.prototype.cssInt=function(t){var e=parseInt(this.css(t),10);return isNaN(e)?0:e},y.prototype.cssFloat=function(t){var e=parseFloat(this.css(t));return isNaN(e)?0:e},y.prototype.fontWeight=function(){var t=this.css("fontWeight");switch(parseInt(t,10)){case 401:t="bold";break;case 400:t="normal"}return t},y.prototype.parseBackgroundImages=function(){var t,e,r,i,o,s,a,c=" \r\n ",h=[],u=0,p=0,d=function(){t&&('"'===e.substr(0,1)&&(e=e.substr(1,e.length-2)),e&&a.push(e),"-"===t.substr(0,1)&&(i=t.indexOf("-",1)+1)>0&&(r=t.substr(0,i),t=t.substr(i)),h.push({prefix:r,method:t.toLowerCase(),value:o,args:a,image:null})),a=[],t=r=e=o=""};return a=[],t=r=e=o="",this.css("backgroundImage").split("").forEach(function(r){if(!(0===u&&c.indexOf(r)>-1)){switch(r){case'"':s?s===r&&(s=null):s=r;break;case"(":if(s)break;if(0===u)return u=1,o+=r,n;p++;break;case")":if(s)break;if(1===u){if(0===p)return u=0,o+=r,d(),n;p--}break;case",":if(s)break;if(0===u)return d(),n;if(1===u&&0===p&&!t.match(/^url$/i))return a.push(e),e="",o+=r,n}o+=r,0===u?t+=r:e+=r}}),d(),this.backgroundImages||(this.backgroundImages=h)},y.prototype.cssList=function(t,e){var n=(this.css(t)||"").split(",");return n=n[e||0]||n[0]||"auto",n=n.trim().split(" "),1===n.length&&(n=[n[0],n[0]]),n},y.prototype.parseBackgroundSize=function(t,e,n){var r,i,o=this.cssList("backgroundSize",n);if(b(o[0]))r=t.width*parseFloat(o[0])/100;else{if(/contain|cover/.test(o[0])){var s=t.width/t.height,a=e.width/e.height;return a>s^"contain"===o[0]?{width:t.height*a,height:t.height}:{width:t.width,height:t.width/a}}r=parseInt(o[0],10)}return i="auto"===o[0]&&"auto"===o[1]?e.height:"auto"===o[1]?r/e.width*e.height:b(o[1])?t.height*parseFloat(o[1])/100:parseInt(o[1],10),"auto"===o[0]&&(r=i/e.height*e.width),{width:r,height:i}},y.prototype.parseBackgroundPosition=function(t,e,n,r){var i,o,s=this.cssList("backgroundPosition",n);return i=b(s[0])?(t.width-(r||e).width)*(parseFloat(s[0])/100):parseInt(s[0],10),o="auto"===s[1]?i/e.width*e.height:b(s[1])?(t.height-(r||e).height)*parseFloat(s[1])/100:parseInt(s[1],10),"auto"===s[0]&&(i=o/e.height*e.width),{left:i,top:o}},y.prototype.parseBackgroundRepeat=function(t){return this.cssList("backgroundRepeat",t)[0]},y.prototype.parseTextShadows=function(){var t=this.css("textShadow"),e=[];if(t&&"none"!==t)for(var n=t.match(this.TEXT_SHADOW_PROPERTY),r=0;n&&n.length>r;r++){var i=n[r].match(this.TEXT_SHADOW_VALUES);e.push({color:i[0],offsetX:i[1]?i[1].replace("px",""):0,offsetY:i[2]?i[2].replace("px",""):0,blur:i[3]?i[3].replace("px",""):0})}return e},y.prototype.TEXT_SHADOW_PROPERTY=/((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g,y.prototype.TEXT_SHADOW_VALUES=/(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g,w.prototype.getChildren=function(t){return X([].filter.call(t.node.childNodes,N).map(function(e){var n=[e.nodeType===Node.TEXT_NODE?new J(e,t):new y(e,t)].filter(V);return e.nodeType===Node.ELEMENT_NODE&&n.length?n[0].isElementVisible()?n.concat(this.getChildren(n[0])):[]:n},this))},w.prototype.newStackingContext=function(t,e){var n=new $(e,t.cssFloat("opacity"),t.node,t.parent);n.visible=t.visible;var r=n.getParentStack(this);r.contexts.push(n),t.stack=n},w.prototype.createStackingContexts=function(){this.nodes.forEach(function(t){W(t)&&(this.isRootElement(t)||z(t)||M(t)||this.isBodyWithTransparentRoot(t))?this.newStackingContext(t,!0):W(t)&&P(t)?this.newStackingContext(t,!1):t.assignStack(t.parent.stack)},this)},w.prototype.isBodyWithTransparentRoot=function(t){return"BODY"===t.node.nodeName&&this.renderer.isTransparent(t.parent.css("backgroundColor"))},w.prototype.isRootElement=function(t){return"HTML"===t.node.nodeName},w.prototype.sortStackingContexts=function(t){t.contexts.sort(j),t.contexts.forEach(this.sortStackingContexts,this)},w.prototype.parseBounds=function(t){return t.bounds=this.getBounds(t.node)},w.prototype.getBounds=function(t){if(t.getBoundingClientRect){var e=t.getBoundingClientRect(),n="BODY"===t.nodeName,r=n?t.scrollWidth:t.offsetWidth;return{top:e.top,bottom:e.bottom||e.top+e.height,right:e.left+r,left:e.left,width:r,height:n?t.scrollHeight:t.offsetHeight}}return{}},w.prototype.parseTextBounds=function(t){return function(e,n,r){if("none"!==t.parent.css("textDecoration")||0!==e.trim().length){if(this.support.rangeBounds){var i=r.slice(0,n).join("").length;return this.getRangeBounds(t.node,i,e.length)}if(t.node&&"string"==typeof t.node.data){var o=t.node.splitText(e.length),s=this.getWrapperBounds(t.node);return t.node=o,s}}else this.support.rangeBounds||(t.node=t.node.splitText(e.length));return{}}},w.prototype.getWrapperBounds=function(t){var e=t.ownerDocument.createElement("wrapper"),n=t.parentNode,r=t.cloneNode(!0);e.appendChild(t.cloneNode(!0)),n.replaceChild(e,t);var i=this.getBounds(e);return n.replaceChild(r,e),i},w.prototype.getRangeBounds=function(t,e,n){var r=this.range||(this.range=t.ownerDocument.createRange());return r.setStart(t,e),r.setEnd(t,e+n),r.getBoundingClientRect()},w.prototype.parse=function(t){var e=t.contexts.filter(I),n=t.children.filter(W),r=n.filter(D(_)),i=r.filter(D(P)).filter(D(S)),o=n.filter(D(P)).filter(_),s=r.filter(D(P)).filter(S),a=t.contexts.concat(r.filter(P)).filter(B),c=t.children.filter(F).filter(O),h=t.contexts.filter(R),u=[];e.concat(i).concat(o).concat(s).concat(a).concat(c).concat(h).forEach(function(t){if(this.paint(t),-1!==u.indexOf(t.node))throw m(t,t.node),Error("rendering twice");u.push(t.node),C(t)&&this.parse(t)},this)},w.prototype.paint=function(t){try{F(t)?this.paintText(t):this.paintNode(t)}catch(e){m(e)}},w.prototype.paintNode=function(t){C(t)&&this.renderer.setOpacity(t.opacity);var e=this.parseBounds(t),n=this.parseBorders(t);switch(this.renderer.clip(n.clip,function(){this.renderer.renderBackground(t,e)},this),this.renderer.renderBorders(n.borders),t.node.nodeName){case"IMG":var r=this.images.get(t.node.src);r?this.renderer.renderImage(t,e,n,r.image):m("Error loading ",t.node.src)}},w.prototype.paintText=function(t){t.applyTextTransform();var e=t.node.data.split(!this.options.letterRendering||A(t)?/(\b| )/:""),n=t.parent.fontWeight(),r=t.parent.css("fontSize"),i=t.parent.css("fontFamily"),o=t.parent.parseTextShadows();this.renderer.font(t.parent.css("color"),t.parent.css("fontStyle"),t.parent.css("fontVariant"),n,r,i),o.length?this.renderer.fontShadow(o[0].color,o[0].offsetX,o[0].offsetY,o[0].blur):this.renderer.clearShadow(),e.map(this.parseTextBounds(t),this).forEach(function(n,o){n&&(this.renderer.text(e[o],n.left,n.bottom),this.renderTextDecoration(t.parent,n,this.fontMetrics.getMetrics(i,r)))},this)},w.prototype.renderTextDecoration=function(t,e,n){switch(t.css("textDecoration").split(" ")[0]){case"underline":this.renderer.rectangle(e.left,Math.round(e.top+n.baseline+n.lineWidth),e.width,1,t.css("color"));break;case"overline":this.renderer.rectangle(e.left,Math.round(e.top),e.width,1,t.css("color"));break;case"line-through":this.renderer.rectangle(e.left,Math.ceil(e.top+n.middle+n.lineWidth),e.width,1,t.css("color"))}},w.prototype.parseBorders=function(t){var e=t.bounds,n=L(t),r=["Top","Right","Bottom","Left"].map(function(e){return{width:t.cssInt("border"+e+"Width"),color:t.css("border"+e+"Color"),args:null}}),i=x(e,n,r);return{clip:this.parseBackgroundClip(t,i,r,n,e),borders:r.map(function(t,o){if(t.width>0){var s=e.left,a=e.top,c=e.width,h=e.height-r[2].width;switch(o){case 0:h=r[0].width,t.args=E({c1:[s,a],c2:[s+c,a],c3:[s+c-r[1].width,a+h],c4:[s+r[3].width,a+h]},n[0],n[1],i.topLeftOuter,i.topLeftInner,i.topRightOuter,i.topRightInner);break;case 1:s=e.left+e.width-r[1].width,c=r[1].width,t.args=E({c1:[s+c,a],c2:[s+c,a+h+r[2].width],c3:[s,a+h],c4:[s,a+r[0].width]},n[1],n[2],i.topRightOuter,i.topRightInner,i.bottomRightOuter,i.bottomRightInner);break;case 2:a=a+e.height-r[2].width,h=r[2].width,t.args=E({c1:[s+c,a+h],c2:[s,a+h],c3:[s+r[3].width,a],c4:[s+c-r[3].width,a]},n[2],n[3],i.bottomRightOuter,i.bottomRightInner,i.bottomLeftOuter,i.bottomLeftInner);break;case 3:c=r[3].width,t.args=E({c1:[s,a+h+r[2].width],c2:[s,a],c3:[s+c,a+r[0].width],c4:[s+c,a+h]},n[3],n[0],i.bottomLeftOuter,i.bottomLeftInner,i.topLeftOuter,i.topLeftInner)}}return t})}},w.prototype.parseBackgroundClip=function(t,e,n,r,i){var o=t.css("backgroundClip"),s=[];switch(o){case"content-box":case"padding-box":T(s,r[0],r[1],e.topLeftInner,e.topRightInner,i.left+n[3].width,i.top+n[0].width),T(s,r[1],r[2],e.topRightInner,e.bottomRightInner,i.left+i.width-n[1].width,i.top+n[0].width),T(s,r[2],r[3],e.bottomRightInner,e.bottomLeftInner,i.left+i.width-n[1].width,i.top+i.height-n[2].width),T(s,r[3],r[0],e.bottomLeftInner,e.topLeftInner,i.left+n[3].width,i.top+i.height-n[2].width);break;default:T(s,r[0],r[1],e.topLeftOuter,e.topRightOuter,i.left,i.top),T(s,r[1],r[2],e.topRightOuter,e.bottomRightOuter,i.left+i.width,i.top),T(s,r[2],r[3],e.bottomRightOuter,e.bottomLeftOuter,i.left+i.width,i.top+i.height),T(s,r[3],r[0],e.bottomLeftOuter,e.topLeftOuter,i.left,i.top+i.height)}return s},!function(){var r,i,o,s;!function(){var t={},e={};r=function(e,n,r){t[e]={deps:n,callback:r}},s=o=i=function(n){function r(t){if("."!==t.charAt(0))return t;for(var e=t.split("/"),r=n.split("/").slice(0,-1),i=0,o=e.length;o>i;i++){var s=e[i];if(".."===s)r.pop();else{if("."===s)continue;r.push(s)}}return r.join("/")}if(s._eak_seen=t,e[n])return e[n];if(e[n]={},!t[n])throw Error("Could not find module "+n);for(var o,a=t[n],c=a.deps,h=a.callback,u=[],p=0,d=c.length;d>p;p++)"exports"===c[p]?u.push(o={}):u.push(i(r(c[p])));var l=h.apply(this,u);return e[n]=o||l}}(),r("promise/all",["./utils","exports"],function(t,e){"use strict";function n(t){var e=this;if(!r(t))throw new TypeError("You must pass an array to all.");return new e(function(e,n){function r(t){return function(e){o(t,e)}}function o(t,n){a[t]=n,0===--c&&e(a)}var s,a=[],c=t.length;0===c&&e([]);for(var h=0;t.length>h;h++)s=t[h],s&&i(s.then)?s.then(r(h),n):o(h,s)})}var r=t.isArray,i=t.isFunction;e.all=n}),r("promise/asap",["exports"],function(r){"use strict";function i(){return function(){process.nextTick(a)}}function o(){var t=0,n=new p(a),r=e.createTextNode("");return n.observe(r,{characterData:!0}),function(){r.data=t=++t%2}}function s(){return function(){d.setTimeout(a,1)}}function a(){for(var t=0;l.length>t;t++){var e=l[t],n=e[0],r=e[1];n(r)}l=[]}function c(t,e){var n=l.push([t,e]);1===n&&h()}var h,u=t!==n?t:{},p=u.MutationObserver||u.WebKitMutationObserver,d="undefined"!=typeof global?global:this,l=[];h="undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?i():p?o():s(),r.asap=c}),r("promise/cast",["exports"],function(t){"use strict";function e(t){if(t&&"object"==typeof t&&t.constructor===this)return t;var e=this;return new e(function(e){e(t)})}t.cast=e}),r("promise/config",["exports"],function(t){"use strict";function e(t,e){return 2!==arguments.length?n[t]:(n[t]=e,void 0)}var n={instrument:!1};t.config=n,t.configure=e}),r("promise/polyfill",["./promise","./utils","exports"],function(e,n,r){"use strict";function i(){var e="Promise"in t&&"cast"in t.Promise&&"resolve"in t.Promise&&"reject"in t.Promise&&"all"in t.Promise&&"race"in t.Promise&&function(){var e;return new t.Promise(function(t){e=t}),s(e)}();e||(t.Promise=o)}var o=e.Promise,s=n.isFunction;r.polyfill=i}),r("promise/promise",["./config","./utils","./cast","./all","./race","./resolve","./reject","./asap","exports"],function(t,e,n,r,i,o,s,a,c){"use strict";function h(t){if(!k(t))throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(!(this instanceof h))throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");this._subscribers=[],u(t,this)}function u(t,e){function n(t){g(e,t)}function r(t){y(e,t)}try{t(n,r)}catch(i){r(i)}}function p(t,e,n,r){var i,o,s,a,c=k(n);if(c)try{i=n(r),s=!0}catch(h){a=!0,o=h}else i=r,s=!0;f(e,i)||(c&&s?g(e,i):a?y(e,o):t===A?g(e,i):t===L&&y(e,i))}function d(t,e,n,r){var i=t._subscribers,o=i.length;i[o]=e,i[o+A]=n,i[o+L]=r}function l(t,e){for(var n,r,i=t._subscribers,o=t._detail,s=0;i.length>s;s+=3)n=i[s],r=i[s+e],p(e,n,r,o);t._subscribers=null}function f(t,e){var n,r=null;try{if(t===e)throw new TypeError("A promises callback cannot return that same promise.");if(x(e)&&(r=e.then,k(r)))return r.call(e,function(r){return n?!0:(n=!0,e!==r?g(t,r):m(t,r),void 0)},function(e){return n?!0:(n=!0,y(t,e),void 0)}),!0}catch(i){return n?!0:(y(t,i),!0)}return!1}function g(t,e){t===e?m(t,e):f(t,e)||m(t,e)}function m(t,e){t._state===C&&(t._state=O,t._detail=e,v.async(b,t))}function y(t,e){t._state===C&&(t._state=O,t._detail=e,v.async(w,t))}function b(t){l(t,t._state=A)}function w(t){l(t,t._state=L)}var v=t.config,x=(t.configure,e.objectOrFunction),k=e.isFunction,E=(e.now,n.cast),T=r.all,I=i.race,R=o.resolve,B=s.reject,S=a.asap;v.async=S;var C=void 0,O=0,A=1,L=2;h.prototype={constructor:h,_state:void 0,_detail:void 0,_subscribers:void 0,then:function(t,e){var n=this,r=new this.constructor(function(){});if(this._state){var i=arguments;v.async(function(){p(n._state,r,i[n._state-1],n._detail)})}else d(this,r,t,e);return r},"catch":function(t){return this.then(null,t)}},h.all=T,h.cast=E,h.race=I,h.resolve=R,h.reject=B,c.Promise=h}),r("promise/race",["./utils","exports"],function(t,e){"use strict";function n(t){var e=this;if(!r(t))throw new TypeError("You must pass an array to race.");return new e(function(e,n){for(var r,i=0;t.length>i;i++)r=t[i],r&&"function"==typeof r.then?r.then(e,n):e(r)})}var r=t.isArray;e.race=n}),r("promise/reject",["exports"],function(t){"use strict";function e(t){var e=this;return new e(function(e,n){n(t)})}t.reject=e}),r("promise/resolve",["exports"],function(t){"use strict";function e(t){var e=this;return new e(function(e){e(t)})}t.resolve=e}),r("promise/utils",["exports"],function(t){"use strict";function e(t){return n(t)||"object"==typeof t&&null!==t}function n(t){return"function"==typeof t}function r(t){return"[object Array]"===Object.prototype.toString.call(t)}var i=Date.now||function(){return(new Date).getTime()};t.objectOrFunction=e,t.isFunction=n,t.isArray=r,t.now=i}),i("promise/polyfill").polyfill()}(),G.prototype.renderImage=function(t,e,n,r){var i=t.cssInt("paddingLeft"),o=t.cssInt("paddingTop"),s=t.cssInt("paddingRight"),a=t.cssInt("paddingBottom"),c=n.borders;this.drawImage(r,0,0,r.width,r.height,e.left+i+c[3].width,e.top+o+c[0].width,e.width-(c[1].width+c[3].width+i+s),e.height-(c[0].width+c[2].width+o+a))},G.prototype.renderBackground=function(t,e){e.height>0&&e.width>0&&(this.renderBackgroundColor(t,e),this.renderBackgroundImage(t,e))},G.prototype.renderBackgroundColor=function(t,e){var n=t.css("backgroundColor");this.isTransparent(n)||this.rectangle(e.left,e.top,e.width,e.height,t.css("backgroundColor"))},G.prototype.renderBorders=function(t){t.forEach(this.renderBorder,this)},G.prototype.renderBorder=function(t){this.isTransparent(t.color)||null===t.args||this.drawShape(t.args,t.color)},G.prototype.renderBackgroundImage=function(t,e){var n=t.parseBackgroundImages();n.reverse().forEach(function(n,r,i){switch(n.method){case"url":var o=this.images.get(n.args[0]);o?this.renderBackgroundRepeating(t,e,o,i.length-(r+1)):m("Error loading background-image",n.args[0]);break;case"linear-gradient":case"gradient":var s=this.images.get(n.value);s?this.renderBackgroundGradient(s,e):m("Error loading background-image",n.args[0]);break;default:m("Unknown background-image type",n.args[0])}},this)},G.prototype.renderBackgroundRepeating=function(t,e,n,r){var i=t.parseBackgroundSize(e,n.image,r),o=t.parseBackgroundPosition(e,n.image,r,i),s=t.parseBackgroundRepeat(r);switch(s){case"repeat-x":case"repeat no-repeat":this.backgroundRepeatShape(n,o,i,e,e.left,e.top+o.top,99999,n.image.height);break;case"repeat-y":case"no-repeat repeat":this.backgroundRepeatShape(n,o,i,e,e.left+o.left,e.top,n.image.width,99999);break;case"no-repeat":this.backgroundRepeatShape(n,o,i,e,e.left+o.left,e.top+o.top,n.image.width,n.image.height);break;default:this.renderBackgroundRepeat(n,o,i,{top:e.top,left:e.left})}},G.prototype.isTransparent=function(t){return!t||"transparent"===t||"rgba(0, 0, 0, 0)"===t},U.prototype=Object.create(G.prototype),U.prototype.setFillStyle=function(t){return this.ctx.fillStyle=t,this.ctx},U.prototype.rectangle=function(t,e,n,r,i){this.setFillStyle(i).fillRect(t,e,n,r)},U.prototype.drawShape=function(t,e){this.shape(t),this.setFillStyle(e).fill()},U.prototype.drawImage=function(t,e,n,r,i,o,s,a,c){this.ctx.drawImage(t,e,n,r,i,o,s,a,c)},U.prototype.clip=function(t,e,n){this.ctx.save(),this.shape(t).clip(),e.call(n),this.ctx.restore()},U.prototype.shape=function(t){return this.ctx.beginPath(),t.forEach(function(t,e){this.ctx[0===e?"moveTo":t[0]+"To"].apply(this.ctx,t.slice(1))},this),this.ctx.closePath(),this.ctx},U.prototype.font=function(t,e,n,r,i,o){this.setFillStyle(t).font=[e,n,r,i,o].join(" ")},U.prototype.fontShadow=function(t,e,n,r){this.setVariable("shadowColor",t).setVariable("shadowOffsetY",e).setVariable("shadowOffsetX",n).setVariable("shadowBlur",r)},U.prototype.clearShadow=function(){this.setVariable("shadowColor","rgba(0,0,0,0)")},U.prototype.setOpacity=function(t){this.ctx.globalAlpha=t},U.prototype.setVariable=function(t,e){return this.variables[t]!==e&&(this.variables[t]=this.ctx[t]=e),this},U.prototype.text=function(t,e,n){this.ctx.fillText(t,e,n)},U.prototype.backgroundRepeatShape=function(t,e,n,r,i,o,s,a){var c=[["line",Math.round(i),Math.round(o)],["line",Math.round(i+s),Math.round(o)],["line",Math.round(i+s),Math.round(a+o)],["line",Math.round(i),Math.round(a+o)]];this.clip(c,function(){this.renderBackgroundRepeat(t,e,n,r)},this)},U.prototype.renderBackgroundRepeat=function(t,e,n,r){var i=Math.round(r.left+e.left),o=Math.round(r.top+e.top);this.setFillStyle(this.ctx.createPattern(this.resizeImage(t,n),"repeat")),this.ctx.translate(i,o),this.ctx.fill(),this.ctx.translate(-i,-o)},U.prototype.renderBackgroundGradient=function(t,e){t instanceof g&&this.ctx.createLinearGradient(e.left,e.top,e.right,e.bottom)},U.prototype.resizeImage=function(t,n){var r=t.image;if(r.width===n.width&&r.height===n.height)return r;var i,o=e.createElement("canvas");return o.width=n.width,o.height=n.height,i=o.getContext("2d"),i.drawImage(r,0,0,r.width,r.height,0,0,n.width,n.height),o},$.prototype=Object.create(y.prototype),$.prototype.getParentStack=function(t){var e=this.parent?this.parent.stack:null;return e?e.ownStacking?e:e.getParentStack(t):t.stack},q.prototype.testRangeBounds=function(){var t,n,r,i,o=!1;return e.createRange&&(t=e.createRange(),t.getBoundingClientRect&&(n=e.createElement("boundtest"),n.style.height="123px",n.style.display="block",e.body.appendChild(n),t.selectNode(n),r=t.getBoundingClientRect(),i=r.height,123===i&&(o=!0),e.body.removeChild(n))),o},q.prototype.testCORS=function(){return(new Image).crossOrigin!==n},J.prototype=Object.create(y.prototype),J.prototype.applyTextTransform=function(){this.node.data=this.transform(this.parent.css("textTransform"))},J.prototype.transform=function(t){var e=this.node.data;switch(t){case"lowercase":return e.toLowerCase();case"capitalize":return e.replace(/(^|\s|:|-|\(|\))([a-z])/g,K);case"uppercase":return e.toUpperCase();default:return e}},Q.prototype=Object.create(u.prototype)})(window,document); \ No newline at end of file diff --git a/readme.md b/readme.md index d24f973..ea45058 100644 --- a/readme.md +++ b/readme.md @@ -33,17 +33,12 @@ As each CSS property needs to be manually built to be supported, there are a num ### Usage ### To render an `element` with html2canvas, simply call: -` html2canvas(element, options);` +` html2canvas(element[, options]);` -To access the created canvas, provide the `onrendered` event in the options which returns the canvas element as the first argument, as such: +The function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) containing the `` element. Simply add a promise fullfillment handler to the promise using `then`: - html2canvas(document.body, { - onrendered: function(canvas) { - /* canvas is the actual canvas element, - to append it to the page call for example - document.body.appendChild( canvas ); - */ - } + html2canvas(document.body).then(function(canvas) { + document.body.appendChild(canvas); }); ### Building ### diff --git a/src/core.js b/src/core.js index 68ee035..9e7f848 100644 --- a/src/core.js +++ b/src/core.js @@ -4,7 +4,17 @@ window.html2canvas = function(nodeList, options) { window.html2canvas.logging = true; window.html2canvas.start = Date.now(); } - createWindowClone(document, window.innerWidth, window.innerHeight).then(function(container) { + return renderDocument(document, options, window.innerWidth, window.innerHeight).then(function(canvas) { + if (typeof(options.onrendered) === "function") { + log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); + options.onrendered(canvas); + } + return canvas; + }); +}; + +function renderDocument(document, options, width, height) { + return createWindowClone(document, width, height).then(function(container) { log("Document cloned"); var clonedWindow = container.contentWindow; //var element = (nodeList === undefined) ? document.body : nodeList[0]; @@ -12,14 +22,16 @@ window.html2canvas = function(nodeList, options) { var support = new Support(); var imageLoader = new ImageLoader(options, support); var bounds = NodeParser.prototype.getBounds(node); - var width = options.type === "view" ? Math.min(bounds.width, window.innerWidth) : documentWidth(); - var height = options.type === "view" ? Math.min(bounds.height, window.innerHeight) : documentHeight(); + var width = options.type === "view" ? Math.min(bounds.width, width) : documentWidth(); + var height = options.type === "view" ? Math.min(bounds.height, height) : documentHeight(); var renderer = new CanvasRenderer(width, height, imageLoader); var parser = new NodeParser(node, renderer, support, imageLoader, options); - - window.console.log(parser); + return parser.ready.then(function() { + container.parentNode.removeChild(container); + return renderer.canvas; + }); }); -}; +} function documentWidth () { return Math.max( @@ -45,7 +57,7 @@ function createWindowClone(ownerDocument, width, height) { var documentElement = ownerDocument.documentElement.cloneNode(true), container = ownerDocument.createElement("iframe"); - container.style.display = "hidden"; + container.style.visibility = "hidden"; container.style.position = "absolute"; container.width = width; container.height = height; @@ -81,6 +93,6 @@ function createWindowClone(ownerDocument, width, height) { var style = documentClone.createElement("style"); style.innerHTML = "body div.html2canvas-ready-test { background-image:url(" + smallImage() + "); }"; documentClone.body.appendChild(style); - window.setTimeout(loadedTimer, 10); + window.setTimeout(loadedTimer, 1000); }); } diff --git a/src/nodeparser.js b/src/nodeparser.js index 64c8fb9..4d59548 100644 --- a/src/nodeparser.js +++ b/src/nodeparser.js @@ -17,11 +17,10 @@ function NodeParser(element, renderer, support, imageLoader, options) { this.createStackingContexts(); log("Sorting stacking contexts"); this.sortStackingContexts(this.stack); - this.images.ready.then(bind(function() { + this.ready = this.images.ready.then(bind(function() { log("Images loaded, starting parsing"); this.parse(this.stack); log("Finished rendering"); - options.onrendered(renderer.canvas); }, this)); } diff --git a/tests/assets/jquery.plugin.html2canvas.js b/tests/assets/jquery.plugin.html2canvas.js index 09b1cdc..851062d 100644 --- a/tests/assets/jquery.plugin.html2canvas.js +++ b/tests/assets/jquery.plugin.html2canvas.js @@ -4,21 +4,20 @@ (function( $ ){ $.fn.html2canvas = function(options) { if (options && options.profile && window.console && window.console.profile && window.location.search !== "?selenium2") { - console.profile(); + window.console.profile(); } var date = new Date(), - html2obj, $message = null, timeoutTimer = false, timer = date.getTime(); options = options || {}; - options.onrendered = options.onrendered || function( canvas ) { + html2canvas(this, options).then(function(canvas) { var $canvas = $(canvas), finishTime = new Date(); if (options && options.profile && window.console && window.console.profileEnd) { - console.profileEnd(); + window.console.profileEnd(); } $canvas.addClass("html2canvas") .css({ @@ -43,12 +42,10 @@ } catch(e) { if ($canvas[0].nodeName.toLowerCase() === "canvas") { // TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed - alert("Canvas is tainted, unable to read data"); + window.alert("Canvas is tainted, unable to read data"); } } - }; - - html2obj = html2canvas(this, options); + }); function throwMessage(msg,duration){ window.clearTimeout(timeoutTimer);