@@ -581,6 +581,7 @@ window.html2canvas = function(nodeList, options) {
581581 options . allowTaint = typeof ( options . allowTaint ) === "undefined" ? false : options . allowTaint ;
582582 options . removeContainer = typeof ( options . removeContainer ) === "undefined" ? true : options . removeContainer ;
583583 options . javascriptEnabled = typeof ( options . javascriptEnabled ) === "undefined" ? false : options . javascriptEnabled ;
584+ options . imageTimeout = typeof ( options . imageTimeout ) === "undefined" ? 10000 : options . imageTimeout ;
584585
585586 if ( typeof ( nodeList ) === "string" ) {
586587 if ( typeof ( options . proxy ) !== "string" ) {
@@ -627,7 +628,7 @@ function renderWindow(node, container, options, windowWidth, windowHeight) {
627628 var parser = new NodeParser ( node , renderer , support , imageLoader , options ) ;
628629 return parser . ready . then ( function ( ) {
629630 log ( "Finished rendering" ) ;
630- var canvas = ( options . type !== "view" && ( node === clonedWindow . document . body || node === clonedWindow . document . documentElement ) ) ? renderer . canvas : crop ( renderer . canvas , bounds ) ;
631+ var canvas = ( options . type !== "view" && ( node === clonedWindow . document . body || node === clonedWindow . document . documentElement ) ) ? renderer . canvas : crop ( renderer . canvas , { width : width , height : height , top : bounds . top , left : bounds . left } ) ;
631632 cleanupContainer ( container , options ) ;
632633 return canvas ;
633634 } ) ;
@@ -693,10 +694,13 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
693694 if window url is about:blank, we can assign the url to current by writing onto the document
694695 */
695696 container . contentWindow . onload = container . onload = function ( ) {
696- setTimeout ( function ( ) {
697- cloneCanvasContents ( ownerDocument , documentClone ) ;
698- resolve ( container ) ;
699- } , 0 ) ;
697+ var interval = setInterval ( function ( ) {
698+ if ( documentClone . body . childNodes . length > 0 ) {
699+ cloneCanvasContents ( ownerDocument , documentClone ) ;
700+ clearInterval ( interval ) ;
701+ resolve ( container ) ;
702+ }
703+ } , 50 ) ;
700704 } ;
701705
702706 documentClone . open ( ) ;
@@ -718,11 +722,8 @@ function loadUrlDocument(src, proxy, document, width, height, options) {
718722
719723function documentFromHTML ( src ) {
720724 return function ( html ) {
721- var doc = document . implementation . createHTMLDocument ( "" ) ;
722- doc . open ( ) ;
723- doc . write ( html ) ;
724- doc . close ( ) ;
725-
725+ var parser = new DOMParser ( ) ;
726+ var doc = parser . parseFromString ( html , "text/html" ) ;
726727 var b = doc . querySelector ( "base" ) ;
727728 if ( ! b || ! b . href . host ) {
728729 var base = doc . createElement ( "base" ) ;
@@ -871,7 +872,7 @@ function FrameContainer(container, sameOrigin, options) {
871872 resolve ( container ) ;
872873 }
873874 } ) ) . then ( function ( container ) {
874- return html2canvas ( container . contentWindow . document . documentElement , { type : 'view' , proxy : options . proxy , javascriptEnabled : options . javascriptEnabled , removeContainer : options . removeContainer } ) ;
875+ return html2canvas ( container . contentWindow . document . documentElement , { type : 'view' , width : container . width , height : container . height , proxy : options . proxy , javascriptEnabled : options . javascriptEnabled , removeContainer : options . removeContainer , allowTaint : options . allowTaint , imageTimeout : options . imageTimeout / 2 } ) ;
875876 } ) . then ( function ( canvas ) {
876877 return self . image = canvas ;
877878 } ) ;
@@ -927,17 +928,17 @@ ImageLoader.prototype.findImages = function(nodes) {
927928 var images = [ ] ;
928929 nodes . reduce ( function ( imageNodes , container ) {
929930 switch ( container . node . nodeName ) {
930- case "IMG" :
931- return imageNodes . concat ( [ {
932- args : [ container . node . src ] ,
933- method : "url"
934- } ] ) ;
935- case "svg" :
936- case "IFRAME" :
937- return imageNodes . concat ( [ {
938- args : [ container . node ] ,
939- method : container . node . nodeName
940- } ] ) ;
931+ case "IMG" :
932+ return imageNodes . concat ( [ {
933+ args : [ container . node . src ] ,
934+ method : "url"
935+ } ] ) ;
936+ case "svg" :
937+ case "IFRAME" :
938+ return imageNodes . concat ( [ {
939+ args : [ container . node ] ,
940+ method : container . node . nodeName
941+ } ] ) ;
941942 }
942943 return imageNodes ;
943944 } , [ ] ) . forEach ( this . addImage ( images , this . loadImage ) , this ) ;
@@ -1012,7 +1013,7 @@ ImageLoader.prototype.isSameOrigin = function(url) {
10121013} ;
10131014
10141015ImageLoader . prototype . getPromise = function ( container ) {
1015- return container . promise [ 'catch' ] ( function ( ) {
1016+ return this . timeout ( container , this . options . imageTimeout ) [ 'catch' ] ( function ( ) {
10161017 var dummy = new DummyImageContainer ( container . src ) ;
10171018 return dummy . promise . then ( function ( image ) {
10181019 container . image = image ;
@@ -1031,16 +1032,29 @@ ImageLoader.prototype.fetch = function(nodes) {
10311032 this . images = nodes . reduce ( bind ( this . findBackgroundImage , this ) , this . findImages ( nodes ) ) ;
10321033 this . images . forEach ( function ( image , index ) {
10331034 image . promise . then ( function ( ) {
1034- log ( "Succesfully loaded image #" + ( index + 1 ) ) ;
1035+ log ( "Succesfully loaded image #" + ( index + 1 ) , image ) ;
10351036 } , function ( e ) {
1036- log ( "Failed loading image #" + ( index + 1 ) , e ) ;
1037+ log ( "Failed loading image #" + ( index + 1 ) , image , e ) ;
10371038 } ) ;
10381039 } ) ;
1039- this . ready = Promise . all ( this . images . map ( this . getPromise ) ) ;
1040+ this . ready = Promise . all ( this . images . map ( this . getPromise , this ) ) ;
10401041 log ( "Finished searching images" ) ;
10411042 return this ;
10421043} ;
10431044
1045+ ImageLoader . prototype . timeout = function ( container , timeout ) {
1046+ var timer ;
1047+ return Promise . race ( [ container . promise , new Promise ( function ( res , reject ) {
1048+ timer = setTimeout ( function ( ) {
1049+ log ( "Timed out loading image" , container ) ;
1050+ reject ( container ) ;
1051+ } , timeout ) ;
1052+ } ) ] ) . then ( function ( container ) {
1053+ clearTimeout ( timer ) ;
1054+ return container ;
1055+ } ) ;
1056+ } ;
1057+
10441058function LinearGradientContainer ( imageData ) {
10451059 GradientContainer . apply ( this , arguments ) ;
10461060 this . type = this . TYPES . LINEAR ;
@@ -1509,7 +1523,7 @@ function NodeParser(element, renderer, support, imageLoader, options) {
15091523 return container . visible = container . isElementVisible ( ) ;
15101524 } ) . map ( this . getPseudoElements , this ) ) ;
15111525 this . fontMetrics = new FontMetrics ( ) ;
1512- log ( "Fetched nodes" ) ;
1526+ log ( "Fetched nodes, total:" , this . nodes . length ) ;
15131527 this . images = imageLoader . fetch ( this . nodes . filter ( isElement ) ) ;
15141528 this . ready = this . images . ready . then ( bind ( function ( ) {
15151529 log ( "Images loaded, starting parsing" ) ;
@@ -2658,7 +2672,7 @@ function CanvasRenderer(width, height) {
26582672 this . taintCtx = this . document . createElement ( "canvas" ) . getContext ( "2d" ) ;
26592673 this . ctx . textBaseline = "bottom" ;
26602674 this . variables = { } ;
2661- log ( "Initialized CanvasRenderer" ) ;
2675+ log ( "Initialized CanvasRenderer with size" , width , "x" , height ) ;
26622676}
26632677
26642678CanvasRenderer . prototype = Object . create ( Renderer . prototype ) ;
0 commit comments