Skip to content

Commit

Permalink
add svg powered rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Mar 6, 2012
1 parent 59306c8 commit c08ac5d
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 153 deletions.
192 changes: 96 additions & 96 deletions src/Parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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,
Expand All @@ -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,"&lt;").replace(/\>/g,"&gt;");
} 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,",
"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='" + width + "' height='" + height + "'>",
"<foreignObject width='" + width + "' height='" + height + "'>",
"<html xmlns='http://www.w3.org/1999/xhtml' style='margin:0;'>",
html,
"</html>",
"</foreignObject>",
"</svg>"
].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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 ) {

Expand Down Expand Up @@ -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,"&lt;").replace(/\>/g,"&gt;");
} 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,",
"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='" + size.width + "' height='" + size.height + "'>",
"<foreignObject width='" + size.width + "' height='" + size.height + "'>",
"<html xmlns='http://www.w3.org/1999/xhtml' style='margin:0;'>",
html.replace(/\#/g,"%23"),
"</html>",
"</foreignObject>",
"</svg>"
].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);
Expand Down
1 change: 1 addition & 0 deletions src/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
117 changes: 60 additions & 57 deletions src/renderers/Canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (!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;
}
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 );
safeImages.push( renderItem['arguments'][ 0 ].src );

}
}
}
ctx.drawImage.apply( ctx, renderItem['arguments'] );
}
}
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;
Expand Down

0 comments on commit c08ac5d

Please sign in to comment.