@@ -581,6 +581,7 @@ window.html2canvas = function(nodeList, options) {
581
581
options . allowTaint = typeof ( options . allowTaint ) === "undefined" ? false : options . allowTaint ;
582
582
options . removeContainer = typeof ( options . removeContainer ) === "undefined" ? true : options . removeContainer ;
583
583
options . javascriptEnabled = typeof ( options . javascriptEnabled ) === "undefined" ? false : options . javascriptEnabled ;
584
+ options . imageTimeout = typeof ( options . imageTimeout ) === "undefined" ? 10000 : options . imageTimeout ;
584
585
585
586
if ( typeof ( nodeList ) === "string" ) {
586
587
if ( typeof ( options . proxy ) !== "string" ) {
@@ -627,7 +628,7 @@ function renderWindow(node, container, options, windowWidth, windowHeight) {
627
628
var parser = new NodeParser ( node , renderer , support , imageLoader , options ) ;
628
629
return parser . ready . then ( function ( ) {
629
630
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 } ) ;
631
632
cleanupContainer ( container , options ) ;
632
633
return canvas ;
633
634
} ) ;
@@ -693,10 +694,13 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
693
694
if window url is about:blank, we can assign the url to current by writing onto the document
694
695
*/
695
696
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 ) ;
700
704
} ;
701
705
702
706
documentClone . open ( ) ;
@@ -718,11 +722,8 @@ function loadUrlDocument(src, proxy, document, width, height, options) {
718
722
719
723
function documentFromHTML ( src ) {
720
724
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" ) ;
726
727
var b = doc . querySelector ( "base" ) ;
727
728
if ( ! b || ! b . href . host ) {
728
729
var base = doc . createElement ( "base" ) ;
@@ -871,7 +872,7 @@ function FrameContainer(container, sameOrigin, options) {
871
872
resolve ( container ) ;
872
873
}
873
874
} ) ) . 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 } ) ;
875
876
} ) . then ( function ( canvas ) {
876
877
return self . image = canvas ;
877
878
} ) ;
@@ -927,17 +928,17 @@ ImageLoader.prototype.findImages = function(nodes) {
927
928
var images = [ ] ;
928
929
nodes . reduce ( function ( imageNodes , container ) {
929
930
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
+ } ] ) ;
941
942
}
942
943
return imageNodes ;
943
944
} , [ ] ) . forEach ( this . addImage ( images , this . loadImage ) , this ) ;
@@ -1012,7 +1013,7 @@ ImageLoader.prototype.isSameOrigin = function(url) {
1012
1013
} ;
1013
1014
1014
1015
ImageLoader . prototype . getPromise = function ( container ) {
1015
- return container . promise [ 'catch' ] ( function ( ) {
1016
+ return this . timeout ( container , this . options . imageTimeout ) [ 'catch' ] ( function ( ) {
1016
1017
var dummy = new DummyImageContainer ( container . src ) ;
1017
1018
return dummy . promise . then ( function ( image ) {
1018
1019
container . image = image ;
@@ -1031,16 +1032,29 @@ ImageLoader.prototype.fetch = function(nodes) {
1031
1032
this . images = nodes . reduce ( bind ( this . findBackgroundImage , this ) , this . findImages ( nodes ) ) ;
1032
1033
this . images . forEach ( function ( image , index ) {
1033
1034
image . promise . then ( function ( ) {
1034
- log ( "Succesfully loaded image #" + ( index + 1 ) ) ;
1035
+ log ( "Succesfully loaded image #" + ( index + 1 ) , image ) ;
1035
1036
} , function ( e ) {
1036
- log ( "Failed loading image #" + ( index + 1 ) , e ) ;
1037
+ log ( "Failed loading image #" + ( index + 1 ) , image , e ) ;
1037
1038
} ) ;
1038
1039
} ) ;
1039
- this . ready = Promise . all ( this . images . map ( this . getPromise ) ) ;
1040
+ this . ready = Promise . all ( this . images . map ( this . getPromise , this ) ) ;
1040
1041
log ( "Finished searching images" ) ;
1041
1042
return this ;
1042
1043
} ;
1043
1044
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
+
1044
1058
function LinearGradientContainer ( imageData ) {
1045
1059
GradientContainer . apply ( this , arguments ) ;
1046
1060
this . type = this . TYPES . LINEAR ;
@@ -1509,7 +1523,7 @@ function NodeParser(element, renderer, support, imageLoader, options) {
1509
1523
return container . visible = container . isElementVisible ( ) ;
1510
1524
} ) . map ( this . getPseudoElements , this ) ) ;
1511
1525
this . fontMetrics = new FontMetrics ( ) ;
1512
- log ( "Fetched nodes" ) ;
1526
+ log ( "Fetched nodes, total:" , this . nodes . length ) ;
1513
1527
this . images = imageLoader . fetch ( this . nodes . filter ( isElement ) ) ;
1514
1528
this . ready = this . images . ready . then ( bind ( function ( ) {
1515
1529
log ( "Images loaded, starting parsing" ) ;
@@ -2658,7 +2672,7 @@ function CanvasRenderer(width, height) {
2658
2672
this . taintCtx = this . document . createElement ( "canvas" ) . getContext ( "2d" ) ;
2659
2673
this . ctx . textBaseline = "bottom" ;
2660
2674
this . variables = { } ;
2661
- log ( "Initialized CanvasRenderer" ) ;
2675
+ log ( "Initialized CanvasRenderer with size" , width , "x" , height ) ;
2662
2676
}
2663
2677
2664
2678
CanvasRenderer . prototype = Object . create ( Renderer . prototype ) ;
0 commit comments