diff --git a/src/Generate.js b/src/Generate.js index f07d8f7..a9a41ba 100644 --- a/src/Generate.js +++ b/src/Generate.js @@ -323,18 +323,16 @@ _html2canvas.Generate.Gradient = function(src, bounds) { var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'), - gradient, grad, i, len, img; + gradient, grad, i, len; canvas.width = bounds.width; canvas.height = bounds.height; - // TODO: add support for multi defined background gradients (like radial gradient example in background.html) + // TODO: add support for multi defined background gradients gradient = _html2canvas.Generate.parseGradient(src, bounds); - img = new Image(); - - if(gradient){ - if(gradient.type === 'linear'){ + if(gradient) { + if(gradient.type === 'linear') { grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1); for (i = 0, len = gradient.colorStops.length; i < len; i+=1) { @@ -349,8 +347,7 @@ ctx.fillStyle = grad; ctx.fillRect(0, 0, bounds.width, bounds.height); - img.src = canvas.toDataURL(); - } else if(gradient.type === 'circle'){ + } else if(gradient.type === 'circle') { grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx); @@ -366,8 +363,7 @@ ctx.fillStyle = grad; ctx.fillRect(0, 0, bounds.width, bounds.height); - img.src = canvas.toDataURL(); - } else if(gradient.type === 'ellipse'){ + } else if(gradient.type === 'ellipse') { // draw circle var canvasRadial = document.createElement('canvas'), @@ -378,7 +374,7 @@ canvasRadial.width = canvasRadial.height = di; grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri); - + for (i = 0, len = gradient.colorStops.length; i < len; i+=1) { try { grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color); @@ -393,21 +389,12 @@ ctx.fillStyle = gradient.colorStops[i - 1].color; ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(canvasRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry); - imgRadial = new Image(); - imgRadial.onload = function() { // wait until the image is filled - - // transform circle to ellipse - ctx.drawImage(imgRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry); - - img.src = canvas.toDataURL(); - - }; - imgRadial.src = canvasRadial.toDataURL(); } } - return img; + return canvas; }; _html2canvas.Generate.ListAlpha = function(number) { diff --git a/src/Parse.js b/src/Parse.js index 98aeace..103ade9 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -740,118 +740,27 @@ _html2canvas.Parse = function (images, options) { numDraws+=1; } - function renderBackgroundSlice (ctx, image, x, y, width, height, elx, ely){ - var sourceX = (elx - x > 0) ? elx-x :0, - sourceY= (ely - y > 0) ? ely-y : 0; - - drawImage( - ctx, - image, - Math.floor(sourceX), // source X - Math.floor(sourceY), // source Y - Math.ceil(width-sourceX), // source Width - Math.ceil(height-sourceY), // source Height - Math.ceil(x+sourceX), // destination X - Math.ceil(y+sourceY), // destination Y - Math.ceil(width-sourceX), // destination width - Math.ceil(height-sourceY) // destination height - ); - } - function renderBackgroundRepeat(ctx, image, backgroundPosition, bounds) { - var bgy, - height, - add, - h; + var offsetX = Math.round(bounds.left + backgroundPosition.left), + offsetY = Math.round(bounds.top + backgroundPosition.top); - backgroundPosition.top -= Math.ceil(backgroundPosition.top / image.height) * image.height; - - for(bgy = (bounds.top + backgroundPosition.top); bgy < (bounds.height + bounds.top); bgy = Math.floor(bgy+image.height) - add) { - h = Math.min(image.height,(bounds.height + bounds.top) - bgy); - - height = (Math.floor(bgy + image.height) > h + bgy) ? (h + bgy) - bgy : image.height; - - if (bgy < bounds.top){ - add = bounds.top - bgy; - bgy = bounds.top; - } else { - add = 0; - } - - renderBackgroundRepeatX(ctx, image, backgroundPosition, bounds.left, bgy, bounds.width, height); - - if (add > 0){ - backgroundPosition.top += add; - } - } + ctx.createPattern(image); + ctx.translate(offsetX, offsetY); + ctx.fill(); + ctx.translate(-offsetX, -offsetY); } - function renderBackgroundNoRepeat(ctx, image, backgroundPosition, x, y, w, h) { - var bgdw = w - backgroundPosition.left, - bgdh = h - backgroundPosition.top, - bgsx = backgroundPosition.left, - bgsy = backgroundPosition.top, - bgdx = backgroundPosition.left + x, - bgdy = backgroundPosition.top + y; - - if (bgsx<0){ - bgsx = Math.abs(bgsx); - bgdx += bgsx; - bgdw = Math.min(w,image.width-bgsx); - } else { - bgdw = Math.min(bgdw,image.width); - bgsx = 0; - } - - if (bgsy < 0){ - bgsy = Math.abs(bgsy); - bgdy += bgsy; - bgdh = Math.min(h, image.height - bgsy); - } else { - bgdh = Math.min(bgdh, image.height); - bgsy = 0; - } - - if (bgdh > 0 && bgdw > 0){ - drawImage( - ctx, - image, - bgsx, - bgsy, - bgdw, - bgdh, - bgdx, - bgdy, - bgdw, - bgdh - ); - } - } - - function renderBackgroundRepeatY (ctx, image, backgroundPosition, x, y, w, h){ - var height, - width = Math.min(image.width, w), - bgy; - - backgroundPosition.top -= Math.ceil(backgroundPosition.top / image.height) * image.height; - - for (bgy = y + backgroundPosition.top; bgy < h + y; bgy = Math.round(bgy + image.height)){ - height = (Math.floor(bgy + image.height) > h + y) ? (h+y) - bgy : image.height; - renderBackgroundSlice(ctx, image, x + backgroundPosition.left, bgy,width, height, x, y); - } - } - - function renderBackgroundRepeatX(ctx, image, backgroundPosition, x, y, w, h){ - var height = Math.min(image.height, h), - width, - bgx; - - backgroundPosition.left -= Math.ceil(backgroundPosition.left / image.width) * image.width; - - for (bgx = x + backgroundPosition.left; bgx < w + x; bgx = Math.round(bgx + image.width)) { - width = (Math.floor(bgx + image.width) > w + x) ? (w + x) - bgx : image.width; - renderBackgroundSlice(ctx, image, bgx,(y + backgroundPosition.top), width, height, x, y); - } + function backgroundRepeatShape(ctx, image, backgroundPosition, bounds, left, top, width, height) { + var args = []; + args.push(["line", Math.round(left), Math.round(top)]); + args.push(["line", Math.round(left + width), Math.round(top)]); + args.push(["line", Math.round(left + width), Math.round(height + top)]); + args.push(["line", Math.round(left), Math.round(height + top)]); + createShape(ctx, args); + ctx.save(); + ctx.clip(); + renderBackgroundRepeat(ctx, image, backgroundPosition, bounds); + ctx.restore(); } function renderBackgroundColor(ctx, backgroundBounds, bgcolor) { @@ -870,15 +779,18 @@ _html2canvas.Parse = function (images, options) { backgroundRepeat = getCSS(el, "backgroundRepeat").split(",")[0]; switch (backgroundRepeat) { case "repeat-x": - renderBackgroundRepeatX(ctx, image, backgroundPosition, bounds.left, bounds.top, bounds.width, bounds.height); + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left, bounds.top + backgroundPosition.top, 99999, image.height); break; case "repeat-y": - renderBackgroundRepeatY(ctx, image, backgroundPosition, bounds.left, bounds.top, bounds.width, bounds.height); + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left + backgroundPosition.left, bounds.top, image.width, 99999); break; case "no-repeat": - renderBackgroundNoRepeat(ctx, image, backgroundPosition, bounds.left, bounds.top, bounds.width, bounds.height); + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left + backgroundPosition.left, bounds.top + backgroundPosition.top, image.width, image.height); break; default: @@ -960,8 +872,9 @@ _html2canvas.Parse = function (images, options) { borders = stack.borders, ctx = stack.ctx, backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip), - borderData = parseBorders(element, bounds, borders), - clipPath = createShape(ctx, borderData.clip); + borderData = parseBorders(element, bounds, borders); + + createShape(ctx, borderData.clip); ctx.save(); ctx.clip(); diff --git a/src/Preload.js b/src/Preload.js index 4a6f168..cab1e7d 100644 --- a/src/Preload.js +++ b/src/Preload.js @@ -119,16 +119,14 @@ _html2canvas.Preload = function( options ) { // opera throws exception on external-content.html try { background_image = _html2canvas.Util.getCSS(el, 'backgroundImage'); - }catch(e) { + } catch(e) { h2clog("html2canvas: failed to get background-image - Exception: " + e.message); } - if ( background_image && background_image !== "1" && background_image !== "none" ) { - + if (background_image && background_image !== "1" && background_image !== "none") { // TODO add multi image background support if (/^(-webkit|-o|-moz|-ms|linear)-/.test( background_image )) { - - img = _html2canvas.Generate.Gradient( background_image, _html2canvas.Util.Bounds( el ) ); + img = _html2canvas.Generate.Gradient(background_image, _html2canvas.Util.Bounds( el ) ); if ( img !== undefined ){ images[background_image] = { diff --git a/src/Queue.js b/src/Queue.js index 8d33477..3a8d22c 100644 --- a/src/Queue.js +++ b/src/Queue.js @@ -11,6 +11,13 @@ function h2cRenderContext(width, height) { 'arguments': arguments }); }, + translate: function() { + storage.push({ + type: "function", + name: "translate", + 'arguments': arguments + }); + }, fill: function() { storage.push({ type: "function", @@ -39,6 +46,13 @@ function h2cRenderContext(width, height) { 'arguments': arguments }); }, + createPattern: function() { + storage.push({ + type: "function", + name: "createPattern", + 'arguments': arguments + }); + }, drawShape: function() { var shape = []; diff --git a/src/renderers/Canvas.js b/src/renderers/Canvas.js index 6d1be34..78e8d7e 100644 --- a/src/renderers/Canvas.js +++ b/src/renderers/Canvas.js @@ -145,6 +145,8 @@ _html2canvas.Renderer.Canvas = function( options ) { 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 === "createPattern") { + ctx.fillStyle = ctx.createPattern(renderItem['arguments'][0], "repeat"); } else if (renderItem.name === "drawShape") { createShape(renderItem['arguments']); } else if (renderItem.name === "fillText") { diff --git a/tests/test.js b/tests/test.js index 77079c7..cc720a3 100644 --- a/tests/test.js +++ b/tests/test.js @@ -13,7 +13,7 @@ var h2cSelector, h2cOptions; document.write(srcStart + '/tests/assets/jquery.plugin.html2canvas.js' + scrEnd); var html2canvas = ['Core', 'Generate', 'Parse', 'Preload', 'Queue', 'Renderer', 'Util', 'Support', 'Font', 'renderers/Canvas'], i; for (i = 0; i < html2canvas.length; ++i) { - document.write(srcStart + '/src/' + html2canvas[i] + '.js' + scrEnd); + document.write(srcStart + '/src/' + html2canvas[i] + '.js?' + Math.random() + scrEnd); } window.onload = function() { h2cSelector = [document.body];