diff --git a/src/Parse.js b/src/Parse.js
index 6c3703c..9176578 100644
--- a/src/Parse.js
+++ b/src/Parse.js
@@ -14,8 +14,8 @@ _html2canvas.Parse = function ( images, options ) {
window.scroll(0,0);
var support = {
- rangeBounds: false
- /*,svgRendering: (function( ){
+ rangeBounds: false,
+ svgRendering: options.svgRendering && (function( ){
var img = new Image(),
canvas = document.createElement("canvas"),
ctx = (canvas.getContext === undefined) ? false : canvas.getContext("2d");
@@ -43,7 +43,7 @@ _html2canvas.Parse = function ( images, options ) {
h2clog('html2canvas: Parse: SVG powered rendering available');
return true;
- })()*/
+ })()
},
element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default
needReorder = false,
@@ -63,86 +63,24 @@ _html2canvas.Parse = function ( images, options ) {
children,
childrenLen;
- /*
- SVG powered HTML rendering, non-tainted canvas available from FF 11+ onwards,
- but due to bug https://bugzilla.mozilla.org/show_bug.cgi?id=733345 excluding this code out for now
- if (support.svgRendering || true) {
- (function( body, width, height ){
- var img = new Image(),
- html = "";
-
- function parseDOM( el ) {
- var children = _html2canvas.Util.Children( el ),
- len = children.length,
- attr,
- a,
- alen,
- elm,
- i;
- for ( i = 0; i < len; i+=1 ) {
- elm = children[ i ];
- if ( elm.nodeType === 3 ) {
- // Text node
-
- html += elm.nodeValue.replace(/\/g,">");
- } else if ( elm.nodeType === 1 ) {
- // Element
- if ( !/^(script|meta|title)$/.test(elm.nodeName.toLowerCase()) ) {
-
- html += "<" + elm.nodeName.toLowerCase();
-
- // add attributes
- if ( elm.hasAttributes() ) {
- attr = elm.attributes;
- alen = attr.length;
- for ( a = 0; a < alen; a+=1 ) {
- html += " " + attr[ a ].name + '="' + attr[ a ].value + '"';
- }
- }
-
-
- html += '>';
-
- parseDOM( elm );
-
-
- html += "" + elm.nodeName.toLowerCase() + ">";
- }
- }
-
- }
-
- }
-
- parseDOM( body );
- img.src = [
- "data:image/svg+xml,",
- ""
- ].join("");
-
- console.log(img.src);
- img.onerror = function(e) {
- console.log(e);
- };
-
- img.onload = function() {
- console.log("loaded");
- };
-
- document.body.appendChild(img);
- })( document.documentElement, 1280, 1024 );
+ function docSize(){
+
+ return {
+ width: Math.max(
+ Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
+ Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
+ Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
+ ),
+ height: Math.max(
+ Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
+ Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
+ Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
+ )
+ };
}
- return;
- */
-
+
images = images || {};
// Test whether we can use ranges to measure bounding boxes
@@ -183,22 +121,7 @@ _html2canvas.Parse = function ( images, options ) {
*/
- function docSize(){
- return {
- width: Math.max(
- Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
- Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
- Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
- ),
- height: Math.max(
- Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
- Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
- Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
- )
- };
-
- }
var getCSS = _html2canvas.Util.getCSS;
function getCSSInt(element, attribute) {
@@ -930,7 +853,7 @@ _html2canvas.Parse = function ( images, options ) {
bgp = _html2canvas.Util.BackgroundPosition(el, bounds, image);
-
+ // TODO add support for background-origin
if ( image ){
switch ( background_repeat ) {
@@ -1297,6 +1220,83 @@ _html2canvas.Parse = function ( images, options ) {
stack = renderElement(element, null);
+ /*
+ SVG powered HTML rendering, non-tainted canvas available from FF 11+ onwards
+ */
+
+ if ( support.svgRendering ) {
+ (function( body ){
+ var img = new Image(),
+ size = docSize(),
+ html = "";
+
+ function parseDOM( el ) {
+ var children = _html2canvas.Util.Children( el ),
+ len = children.length,
+ attr,
+ a,
+ alen,
+ elm,
+ i;
+ for ( i = 0; i < len; i+=1 ) {
+ elm = children[ i ];
+ if ( elm.nodeType === 3 ) {
+ // Text node
+
+ html += elm.nodeValue.replace(/\/g,">");
+ } else if ( elm.nodeType === 1 ) {
+ // Element
+ if ( !/^(script|meta|title)$/.test(elm.nodeName.toLowerCase()) ) {
+
+ html += "<" + elm.nodeName.toLowerCase();
+
+ // add attributes
+ if ( elm.hasAttributes() ) {
+ attr = elm.attributes;
+ alen = attr.length;
+ for ( a = 0; a < alen; a+=1 ) {
+ html += " " + attr[ a ].name + '="' + attr[ a ].value + '"';
+ }
+ }
+
+
+ html += '>';
+
+ parseDOM( elm );
+
+
+ html += "" + elm.nodeName.toLowerCase() + ">";
+ }
+ }
+
+ }
+
+ }
+
+ parseDOM( body );
+ img.src = [
+ "data:image/svg+xml,",
+ ""
+ ].join("");
+
+
+
+
+ img.onload = function() {
+ stack.svgRender = img;
+ };
+
+ })( document.documentElement );
+
+ }
+
+
// parse every child element
for (i = 0, children = element.children, childrenLen = children.length; i < childrenLen; i+=1){
parseElement(children[i], stack);
diff --git a/src/Util.js b/src/Util.js
index e97125e..63708dd 100644
--- a/src/Util.js
+++ b/src/Util.js
@@ -23,6 +23,7 @@ html2canvas = function( elements, opts ) {
allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true
// parse options
+ svgRendering: false, // use svg powered rendering where available (FF11+)
iframeDefault: "default",
ignoreElements: "IFRAME|OBJECT|PARAM",
useOverflow: true,
diff --git a/src/renderers/Canvas.js b/src/renderers/Canvas.js
index d563df2..edabb0f 100644
--- a/src/renderers/Canvas.js
+++ b/src/renderers/Canvas.js
@@ -107,85 +107,88 @@ html2canvas.Renderer.Canvas = function( options ) {
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fstyle;
- for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
+ if ( options.svgRendering && zStack.svgRender !== undefined ) {
+ // TODO: enable async rendering to support this
+ ctx.drawImage( zStack.svgRender, 0, 0 );
+ } else {
+ for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
- storageContext = queue.splice(0, 1)[0];
- storageContext.canvasPosition = storageContext.canvasPosition || {};
+ storageContext = queue.splice(0, 1)[0];
+ storageContext.canvasPosition = storageContext.canvasPosition || {};
- //this.canvasRenderContext(storageContext,parentctx);
+ //this.canvasRenderContext(storageContext,parentctx);
- // set common settings for canvas
- ctx.textBaseline = "bottom";
+ // set common settings for canvas
+ ctx.textBaseline = "bottom";
- if (storageContext.clip){
- ctx.save();
- ctx.beginPath();
- // console.log(storageContext);
- ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
- ctx.clip();
+ if (storageContext.clip){
+ ctx.save();
+ ctx.beginPath();
+ // console.log(storageContext);
+ ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
+ ctx.clip();
- }
+ }
- if (storageContext.ctx.storage){
+ if (storageContext.ctx.storage){
- for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
+ for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
- renderItem = storageContext.ctx.storage[a];
+ renderItem = storageContext.ctx.storage[a];
- switch(renderItem.type){
- case "variable":
- ctx[renderItem.name] = renderItem['arguments'];
- break;
- case "function":
- if (renderItem.name === "fillRect") {
+ switch(renderItem.type){
+ case "variable":
+ ctx[renderItem.name] = renderItem['arguments'];
+ break;
+ case "function":
+ if (renderItem.name === "fillRect") {
- if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
- ctx.fillRect.apply( ctx, renderItem['arguments'] );
- }
- }else if(renderItem.name === "fillText") {
- if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
- ctx.fillText.apply( ctx, renderItem['arguments'] );
- }
- }else if(renderItem.name === "drawImage") {
-
- if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
- if ( hasCTX && options.taintTest ) {
- if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
- testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
- try {
- testctx.getImageData( 0, 0, 1, 1 );
- } catch(e) {
- testCanvas = doc.createElement("canvas");
- testctx = testCanvas.getContext("2d");
- continue;
- }
-
- safeImages.push( renderItem['arguments'][ 0 ].src );
-
- }
+ if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
+ ctx.fillRect.apply( ctx, renderItem['arguments'] );
}
- ctx.drawImage.apply( ctx, renderItem['arguments'] );
- }
- }
+ }else if(renderItem.name === "fillText") {
+ if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
+ ctx.fillText.apply( ctx, renderItem['arguments'] );
+ }
+ }else if(renderItem.name === "drawImage") {
+
+ if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
+ if ( hasCTX && options.taintTest ) {
+ if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
+ testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
+ try {
+ testctx.getImageData( 0, 0, 1, 1 );
+ } catch(e) {
+ testCanvas = doc.createElement("canvas");
+ testctx = testCanvas.getContext("2d");
+ continue;
+ }
+
+ safeImages.push( renderItem['arguments'][ 0 ].src );
+
+ }
+ }
+ ctx.drawImage.apply( ctx, renderItem['arguments'] );
+ }
+ }
- break;
- default:
+ break;
+ default:
- }
+ }
+ }
+
+ }
+ if (storageContext.clip){
+ ctx.restore();
}
-
- }
- if (storageContext.clip){
- ctx.restore();
- }
-
-
-
+ }
}
+
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
queueLen = options.elements.length;