Merge remote-tracking branch 'niklasvh/develop' into develop

Conflicts:
	src/Parse.js
	src/Preload.js
This commit is contained in:
Andy Edinborough 2013-01-03 15:07:38 -06:00
commit 3edf9fa743
10 changed files with 608 additions and 264 deletions

View File

@ -327,18 +327,16 @@
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) {
@ -353,8 +351,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);
@ -370,8 +367,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'),
@ -382,7 +378,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);
@ -397,21 +393,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) {

View File

@ -326,144 +326,372 @@ _html2canvas.Parse = function (images, options) {
);
}
function renderBorders(el, ctx, bounds, clip){
function getBorderData(element) {
return ["Top", "Right", "Bottom", "Left"].map(function(side) {
return {
width: getCSSInt(element, 'border' + side + 'Width'),
color: getCSS(element, 'border' + side + 'Color')
};
});
}
function getBorderRadiusData(element) {
return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {
return getCSS(element, 'border' + side + 'Radius');
});
}
var getCurvePoints = (function(kappa) {
return function(x, y, r1, r2) {
var ox = (r1) * kappa, // control point offset horizontal
oy = (r2) * kappa, // control point offset vertical
xm = x + r1, // x-middle
ym = y + r2; // y-middle
return {
topLeft: bezierCurve({
x:x,
y:ym
}, {
x:x,
y:ym - oy
}, {
x:xm - ox,
y:y
}, {
x:xm,
y:y
}),
topRight: bezierCurve({
x:x,
y:y
}, {
x:x + ox,
y:y
}, {
x:xm,
y:ym - oy
}, {
x:xm,
y:ym
}),
bottomRight: bezierCurve({
x:xm,
y:y
}, {
x:xm,
y:y + oy
}, {
x:x + ox,
y:ym
}, {
x:x,
y:ym
}),
bottomLeft: bezierCurve({
x:xm,
y:ym
}, {
x:xm - ox,
y:ym
}, {
x:x,
y:y + oy
}, {
x:x,
y:y
})
};
};
})(4 * ((Math.sqrt(2) - 1) / 3));
function bezierCurve(start, startControl, endControl, end) {
var lerp = function (a, b, t) {
return {
x:a.x + (b.x - a.x) * t,
y:a.y + (b.y - a.y) * t
};
};
return {
start: start,
startControl: startControl,
endControl: endControl,
end: end,
subdivide: function(t) {
var ab = lerp(start, startControl, t),
bc = lerp(startControl, endControl, t),
cd = lerp(endControl, end, t),
abbc = lerp(ab, bc, t),
bccd = lerp(bc, cd, t),
dest = lerp(abbc, bccd, t);
return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
},
curveTo: function(borderArgs) {
borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
},
curveToReversed: function(borderArgs) {
borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
}
};
}
function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) {
if (radius1[0] > 0 || radius1[1] > 0) {
borderArgs.push(["line", corner1[0].start.x, corner1[0].start.y]);
corner1[0].curveTo(borderArgs);
corner1[1].curveTo(borderArgs);
} else {
borderArgs.push(["line", x, y]);
}
if (radius2[0] > 0 || radius2[1] > 0) {
borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]);
}
}
function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {
var borderArgs = [];
if (radius1[0] > 0 || radius1[1] > 0) {
borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);
outer1[1].curveTo(borderArgs);
} else {
borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);
}
if (radius2[0] > 0 || radius2[1] > 0) {
borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);
outer2[0].curveTo(borderArgs);
borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);
inner2[0].curveToReversed(borderArgs);
} else {
borderArgs.push([ "line", borderData.c2[0], borderData.c2[1]]);
borderArgs.push([ "line", borderData.c3[0], borderData.c3[1]]);
}
if (radius1[0] > 0 || radius1[1] > 0) {
borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);
inner1[1].curveToReversed(borderArgs);
} else {
borderArgs.push([ "line", borderData.c4[0], borderData.c4[1]]);
}
return borderArgs;
}
function calculateCurvePoints(bounds, borderRadius, borders) {
var x = bounds.left,
y = bounds.top,
w = bounds.width,
h = bounds.height,
width = bounds.width,
height = bounds.height,
tlh = borderRadius[0][0],
tlv = borderRadius[0][1],
trh = borderRadius[1][0],
trv = borderRadius[1][1],
brv = borderRadius[2][0],
brh = borderRadius[2][1],
blh = borderRadius[3][0],
blv = borderRadius[3][1],
topWidth = width - trh,
rightHeight = height - brv,
bottomWidth = width - brh,
leftHeight = height - blv;
return {
topLeftOuter: getCurvePoints(
x,
y,
tlh,
tlv
).topLeft.subdivide(0.5),
topLeftInner: getCurvePoints(
x + borders[3].width,
y + borders[0].width,
Math.max(0, tlh - borders[3].width),
Math.max(0, tlv - borders[0].width)
).topLeft.subdivide(0.5),
topRightOuter: getCurvePoints(
x + topWidth,
y,
trh,
trv
).topRight.subdivide(0.5),
topRightInner: getCurvePoints(
x + Math.min(topWidth, width + borders[3].width),
y + borders[0].width,
(topWidth > width + borders[3].width) ? 0 :trh - borders[3].width,
trv - borders[0].width
).topRight.subdivide(0.5),
bottomRightOuter: getCurvePoints(
x + bottomWidth,
y + rightHeight,
brh,
brv
).bottomRight.subdivide(0.5),
bottomRightInner: getCurvePoints(
x + Math.min(bottomWidth, width + borders[3].width),
y + Math.min(rightHeight, height + borders[0].width),
Math.max(0, brh - borders[1].width),
Math.max(0, brv - borders[2].width)
).bottomRight.subdivide(0.5),
bottomLeftOuter: getCurvePoints(
x,
y + leftHeight,
blh,
blv
).bottomLeft.subdivide(0.5),
bottomLeftInner: getCurvePoints(
x + borders[3].width,
y + leftHeight,
Math.max(0, blh - borders[3].width),
Math.max(0, blv - borders[2].width)
).bottomLeft.subdivide(0.5)
};
}
function getBorderClip(element, borderPoints, borders, radius, bounds) {
var backgroundClip = getCSS(element, 'backgroundClip'),
borderArgs = [];
switch(backgroundClip) {
case "content-box":
case "padding-box":
parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);
parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);
parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);
parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);
break;
default:
parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);
parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);
parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);
parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);
break;
}
return borderArgs;
}
function parseBorders(element, bounds, borders){
var x = bounds.left,
y = bounds.top,
width = bounds.width,
height = bounds.height,
borderSide,
borderData,
bx,
by,
bw,
bh,
i,
borderArgs,
borderBounds,
borders = (function(el){
var borders = [],
sides = ["Top","Right","Bottom","Left"],
s;
for (s = 0; s < 4; s+=1){
borders.push({
width: getCSSInt(el, 'border' + sides[s] + 'Width'),
color: getCSS(el, 'border' + sides[s] + 'Color')
});
}
return borders;
}(el)),
// http://www.w3.org/TR/css3-background/#the-border-radius
borderRadius = (function( el ) {
var borders = [],
sides = ["TopLeft","TopRight","BottomRight","BottomLeft"],
s;
borderRadius = getBorderRadiusData(element),
borderPoints = calculateCurvePoints(bounds, borderRadius, borders),
borderData = {
clip: getBorderClip(element, borderPoints, borders, borderRadius, bounds),
borders: []
};
for (s = 0; s < 4; s+=1){
borders.push( getCSS(el, 'border' + sides[s] + 'Radius') );
}
for (borderSide = 0; borderSide < 4; borderSide++) {
return borders;
})( el );
for ( borderSide = 0; borderSide < 4; borderSide+=1 ) {
borderData = borders[ borderSide ];
borderArgs = [];
if (borderData.width>0){
if (borders[borderSide].width > 0) {
bx = x;
by = y;
bw = w;
bh = h - (borders[2].width);
bw = width;
bh = height - (borders[2].width);
switch(borderSide){
switch(borderSide) {
case 0:
// top border
bh = borders[0].width;
i = 0;
borderArgs[ i++ ] = [ "line", bx, by ]; // top left
borderArgs[ i++ ] = [ "line", bx + bw, by ]; // top right
borderArgs[ i++ ] = [ "line", bx + bw - borders[ 1 ].width, by + bh ]; // bottom right
borderArgs[ i++ ] = [ "line", bx + borders[ 3 ].width, by + bh ]; // bottom left
borderArgs = drawSide({
c1: [bx, by],
c2: [bx + bw, by],
c3: [bx + bw - borders[1].width, by + bh],
c4: [bx + borders[3].width, by + bh]
}, borderRadius[0], borderRadius[1],
borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);
break;
case 1:
// right border
bx = x + w - (borders[1].width);
bx = x + width - (borders[1].width);
bw = borders[1].width;
i = 0;
borderArgs[ i++ ] = [ "line", bx, by + borders[ 0 ].width]; // top left
borderArgs[ i++ ] = [ "line", bx + bw, by ]; // top right
borderArgs[ i++ ] = [ "line", bx + bw, by + bh + borders[ 2 ].width ]; // bottom right
borderArgs[ i++ ] = [ "line", bx, by + bh ]; // bottom left
borderArgs = drawSide({
c1: [bx + bw, by],
c2: [bx + bw, by + bh + borders[2].width],
c3: [bx, by + bh],
c4: [bx, by + borders[0].width]
}, borderRadius[1], borderRadius[2],
borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);
break;
case 2:
// bottom border
by = (by + h) - (borders[2].width);
by = (by + height) - (borders[2].width);
bh = borders[2].width;
i = 0;
borderArgs[ i++ ] = [ "line", bx + borders[ 3 ].width, by ]; // top left
borderArgs[ i++ ] = [ "line", bx + bw - borders[ 2 ].width, by ]; // top right
borderArgs[ i++ ] = [ "line", bx + bw, by + bh ]; // bottom right
borderArgs[ i++ ] = [ "line", bx, by + bh ]; // bottom left
borderArgs = drawSide({
c1: [bx + bw, by + bh],
c2: [bx, by + bh],
c3: [bx + borders[3].width, by],
c4: [bx + bw - borders[2].width, by]
}, borderRadius[2], borderRadius[3],
borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);
break;
case 3:
// left border
bw = borders[3].width;
i = 0;
borderArgs[ i++ ] = [ "line", bx, by ]; // top left
borderArgs[ i++ ] = [ "line", bx + bw, by + borders[ 0 ].width ]; // top right
borderArgs[ i++ ] = [ "line", bx + bw, by + bh ]; // bottom right
borderArgs[ i++ ] = [ "line", bx, by + bh + borders[ 2 ].width ]; // bottom left
borderArgs = drawSide({
c1: [bx, by + bh + borders[2].width],
c2: [bx, by],
c3: [bx + bw, by + borders[0].width],
c4: [bx + bw, by + bh]
}, borderRadius[3], borderRadius[0],
borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);
break;
}
borderBounds = {
left:bx,
top:by,
width: bw,
height:bh
};
if (clip){
borderBounds = clipBounds(borderBounds, clip);
}
if ( borderBounds.width > 0 && borderBounds.height > 0 ) {
if ( borderData.color !== "transparent" ){
ctx.setVariable( "fillStyle", borderData.color );
var shape = ctx.drawShape(),
numBorderArgs = borderArgs.length;
for ( i = 0; i < numBorderArgs; i++ ) {
shape[( i === 0) ? "moveTo" : borderArgs[ i ][ 0 ] + "To" ].apply( null, borderArgs[ i ].slice(1) );
}
numDraws+=1;
}
}
borderData.borders.push({
args: borderArgs,
color: borders[borderSide].color
});
}
}
return borders;
return borderData;
}
function createShape(ctx, args) {
var shape = ctx.drawShape();
args.forEach(function(border, index) {
shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1));
});
return shape;
}
function renderBorders(ctx, borderArgs, color) {
if (color !== "transparent") {
ctx.setVariable( "fillStyle", color);
createShape(ctx, borderArgs);
ctx.fill();
numDraws+=1;
}
}
function renderFormValue (el, bounds, stack){
@ -512,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(image.width-sourceX), // source Width
Math.ceil(image.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,
image.width,
image.height,
bgdx,
bgdy,
bgdw + backgroundPosition.left,
bgdh + backgroundPosition.top
);
}
}
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) {
@ -646,15 +783,18 @@ _html2canvas.Parse = function (images, options) {
switch (backgroundRepeat) {
case "repeat-x":
renderBackgroundRepeatX(ctx, image, backgroundPosition, bounds.left, bounds.top, backgroundSize.width, backgroundSize.height);
backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
bounds.left, bounds.top + backgroundPosition.top, 99999, backgroundSize.height);
break;
case "repeat-y":
renderBackgroundRepeatY(ctx, image, backgroundPosition, bounds.left, bounds.top, backgroundSize.width, backgroundSize.height);
backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
bounds.left + backgroundPosition.left, bounds.top, backgroundSize.width, 99999);
break;
case "no-repeat":
renderBackgroundNoRepeat(ctx, image, backgroundPosition, bounds.left, bounds.top, backgroundSize.width, backgroundSize.height);
backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
bounds.left + backgroundPosition.left, bounds.top + backgroundPosition.top, backgroundSize.width, backgroundSize.height);
break;
default:
@ -704,7 +844,7 @@ _html2canvas.Parse = function (images, options) {
zIndex: setZ(getCSS(element, "zIndex"), (parentStack) ? parentStack.zIndex : null),
opacity: setOpacity(ctx, element, parentStack),
cssPosition: getCSS(element, "position"),
borders: renderBorders(element, ctx, bounds, false),
borders: getBorderData(element),
clip: (parentStack && parentStack.clip) ? _html2canvas.Util.Extend( {}, parentStack.clip ) : null
};
@ -740,13 +880,25 @@ _html2canvas.Parse = function (images, options) {
stack = createStack(element, parentStack, bounds),
borders = stack.borders,
ctx = stack.ctx,
backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip);
backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip),
borderData = parseBorders(element, bounds, borders);
createShape(ctx, borderData.clip);
ctx.save();
ctx.clip();
if (backgroundBounds.height > 0 && backgroundBounds.width > 0){
renderBackgroundColor(ctx, backgroundBounds, bgcolor);
renderBackgroundColor(ctx, bounds, bgcolor);
renderBackgroundImage(element, backgroundBounds, ctx);
}
ctx.restore();
borderData.borders.forEach(function(border) {
renderBorders(ctx, border.args, border.color);
});
switch(element.nodeName){
case "IMG":
if ((image = loadImage(element.getAttribute('src')))) {

View File

@ -122,10 +122,9 @@ _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);
}
background_images = _html2canvas.Util.parseBackgroundImage(background_image);
for(var imageIndex = background_images.length; imageIndex-- > 0;) {
background_image = background_images[imageIndex];
@ -136,7 +135,6 @@ _html2canvas.Preload = function( options ) {
background_image.args.length === 0 ) {
continue;
}
if (background_image.method === 'url') {
src = background_image.args[0];
methods.loadImage(src);

View File

@ -4,6 +4,41 @@ function h2cRenderContext(width, height) {
storage: storage,
width: width,
height: height,
clip: function() {
storage.push({
type: "function",
name: "clip",
'arguments': arguments
});
},
translate: function() {
storage.push({
type: "function",
name: "translate",
'arguments': arguments
});
},
fill: function() {
storage.push({
type: "function",
name: "fill",
'arguments': arguments
});
},
save: function() {
storage.push({
type: "function",
name: "save",
'arguments': arguments
});
},
restore: function() {
storage.push({
type: "function",
name: "restore",
'arguments': arguments
});
},
fillRect: function () {
storage.push({
type: "function",
@ -11,6 +46,13 @@ function h2cRenderContext(width, height) {
'arguments': arguments
});
},
createPattern: function() {
storage.push({
type: "function",
name: "createPattern",
'arguments': arguments
});
},
drawShape: function() {
var shape = [];
@ -34,6 +76,12 @@ function h2cRenderContext(width, height) {
'arguments': arguments
});
},
arcTo: function() {
shape.push({
name: "arcTo",
'arguments': arguments
});
},
bezierCurveTo: function() {
shape.push({
name: "bezierCurveTo",

View File

@ -98,16 +98,12 @@ _html2canvas.Renderer.Canvas = function( options ) {
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fstyle;
var drawShape = function(args) {
var i, len = args.length;
var createShape = function(args) {
ctx.beginPath();
for ( i = 0; i < len; i++ ) {
ctx[ args[ i ].name ].apply( ctx, args[ i ]['arguments'] );
}
args.forEach(function(arg) {
ctx[arg.name].apply(ctx, arg['arguments']);
});
ctx.closePath();
ctx.fill();
};
if ( options.svgRendering && zStack.svgRender !== undefined ) {
@ -149,8 +145,10 @@ _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") {
drawShape(renderItem['arguments']);
createShape(renderItem['arguments']);
} else if (renderItem.name === "fillText") {
if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
ctx.fillText.apply( ctx, renderItem['arguments'] );
@ -175,6 +173,8 @@ _html2canvas.Renderer.Canvas = function( options ) {
}
ctx.drawImage.apply( ctx, renderItem['arguments'] );
}
} else {
ctx[renderItem.name].apply(ctx, renderItem['arguments']);
}

View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<title>Background attribute tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
html {
background-color: red;
}
body {
background-color: lime;
}
.small div{
width:100px;
height:100px;
float:left;
margin:10px;
border:1px solid #000;
}
.medium div{
width:200px;
height:200px;
float:left;
margin:10px;
border:20px solid transparent;
border-width: 10px 20px 30px 40px;
background: green;
}
.small, .medium{
clear:both;
}
div{
display:block;
}
</style>
</head>
<body>
<div class="medium">
<div style="background:url(../../assets/image.jpg);background-clip: border-box;"></div>
<div style="background:url(../../assets/image.jpg);background-clip: padding-box;"></div>
<div style="background:url(../../assets/image.jpg);background-clip: content-box;"></div>
<div style="background:url(../../assets/image.jpg);"></div>
</div>
<div class="medium">
<div style="background-clip: border-box;"></div>
<div style="background-clip: padding-box;"></div>
<div style="background-clip: content-box;"></div>
<div style=""></div>
</div>
</body>
</html>

View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<title>Borders tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style type="text/css">
div {
width: 200px;
height: 200px;
display: inline-block;
margin: 10px;
background:#6F428C;
border-style: solid;
border-radius: 50px;
}
.box1 {
border-width: 1px;
border-left-color: #00b5e2;
border-top-color: red;
border-right-color: green;
}
.box2 {
border-width: 3px;
border-left-color: #00b5e2;
border-top-color: red;
border-right-color: green;
}
.box3 {
border-width: 10px;
border-left-color: transparent;
border-top-color: red;
border-right-color: green;
}
.box4 {
border-width: 50px;
border-left-color: transparent;
border-top-color: red;
border-top-width: 10px;
border-right-color: green;
border-bottom-right-radius: 190px;
background-clip: padding-box;
}
html {
background: #3a84c3;
}
</style>
</head>
<body>
<div class="box1">&nbsp;</div>
<div class="box2">&nbsp;</div>
<div class="box3">&nbsp;</div>
<div class="box4">&nbsp;</div>
</body>
</html>

37
tests/rangetest.html Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Range tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
#tests {
font-family:Arial;
}
</style>
</head>
<body>
<div id="tests"></div>
<script>
var div = document.getElementById("tests"), item, range, textNode, bounds;
for (var i = 6; i < 72; i++) {
item = document.createElement("div");
item.style.fontSize = i + "px";
item.style.lineHeight = (10 + i * 2) + "px";
textNode = document.createTextNode(i);
item.appendChild(textNode);
div.appendChild(item);
range = document.createRange();
range.setStart(textNode, 0);
range.setEnd(textNode, i.toString().length);
bounds = range.getBoundingClientRect();
textNode.nodeValue += " " + bounds.height + " " + bounds.bottom + (i % 3 === 0);
}
</script>
<script src="test.js"></script>
</body>
</html>

View File

@ -1,31 +1,33 @@
<table><thead><tr><td></td><th>chrome<br />23.0.1271.97</th><th>firefox<br />12.0</th><th>iexplorer<br />9</th></tr></thead><tbody>
<tr><td>background/clip.html</td><td>100%</td><td>100%</td><td>99.89%</td></tr>
<tr><td>background/encoded.html</td><td>100%</td><td>100%</td><td>100%</td></tr>
<tr><td>background/linear-gradient.html</td><td>82.27%</td><td>85.64%</td><td>100%</td></tr>
<tr><td>background/multi.html</td><td>96.6%</td><td>96.45%</td><td>96.89%</td></tr>
<tr><td>background/position.html</td><td>97.03%</td><td>96.97%</td><td>97.03%</td></tr>
<tr><td>background/radial-gradient.html</td><td>57.9%</td><td>54.87%</td><td>94.02%</td></tr>
<tr><td>background/repeat.html</td><td>100%</td><td>100%</td><td>100%</td></tr>
<tr><td>background/linear-gradient.html</td><td>89.87%</td><td>90.73%</td><td>100%</td></tr>
<tr><td>background/multi.html</td><td>96.6%</td><td>96.45%</td><td>96.85%</td></tr>
<tr><td>background/position.html</td><td>100%</td><td>100%</td><td>99.87%</td></tr>
<tr><td>background/radial-gradient.html</td><td>73.23%</td><td>70.32%</td><td>94.02%</td></tr>
<tr><td>background/repeat.html</td><td>100%</td><td>100%</td><td>99.92%</td></tr>
<tr><td>border/dashed.html</td><td>96.45%</td><td>98.38%</td><td>97.7%</td></tr>
<tr><td>border/dotted.html</td><td>97.41%</td><td>96.46%</td><td>95.93%</td></tr>
<tr><td>border/double.html</td><td>97.96%</td><td>97.87%</td><td>97.95%</td></tr>
<tr><td>border/radius.html</td><td>99.74%</td><td>99.77%</td><td>99.75%</td></tr>
<tr><td>border/solid.html</td><td>99.97%</td><td>99.97%</td><td>99.98%</td></tr>
<tr><td>forms.html</td><td>95.96%</td><td>94.55%</td><td>95.02%</td></tr>
<tr><td>forms.html</td><td>95.96%</td><td>94.55%</td><td>95.01%</td></tr>
<tr><td>images/canvas.html</td><td>99.86%</td><td>100%</td><td>100%</td></tr>
<tr><td>images/cross-origin.html</td><td>97.99%</td><td>97.58%</td><td>99.35%</td></tr>
<tr><td>images/empty.html</td><td>99.86%</td><td>99.87%</td><td>99.85%</td></tr>
<tr><td>images/images.html</td><td>83.72%</td><td>96.93%</td><td>55.09%</td></tr>
<tr><td>images/svg.html</td><td>99.92%</td><td>96.79%</td><td>99.93%</td></tr>
<tr><td>list/decimal-leading-zero.html</td><td>99.63%</td><td>99.72%</td><td>35.04%</td></tr>
<tr><td>list/decimal.html</td><td>99.64%</td><td>99.73%</td><td>35.06%</td></tr>
<tr><td>list/lower-alpha.html</td><td>99.65%</td><td>99.73%</td><td>35.05%</td></tr>
<tr><td>list/upper-roman.html</td><td>99.45%</td><td>99.61%</td><td>35.11%</td></tr>
<tr><td>overflow.html</td><td>96.85%</td><td>97.49%</td><td>96.51%</td></tr>
<tr><td>text/linethrough.html</td><td>97.14%</td><td>94.12%</td><td>45.74%</td></tr>
<tr><td>text/text.html</td><td>95.71%</td><td>94.67%</td><td>79.85%</td></tr>
<tr><td>text/underline-lineheight.html</td><td>97.06%</td><td>92.35%</td><td>51.38%</td></tr>
<tr><td>text/underline.html</td><td>97.65%</td><td>93.5%</td><td>45.69%</td></tr>
<tr><td>visibility.html</td><td>99.19%</td><td>98.92%</td><td>99.39%</td></tr>
<tr><td>zindex/z-index1.html</td><td>97.09%</td><td>99.38%</td><td>99.54%</td></tr>
<tr><td>zindex/z-index2.html</td><td>95.94%</td><td>98.16%</td><td>97.81%</td></tr>
<tr><td>zindex/z-index3.html</td><td>98.98%</td><td>98.55%</td><td>98.68%</td></tr>
<tr><td>list/decimal-leading-zero.html</td><td>99.63%</td><td>99.72%</td><td>35.88%</td></tr>
<tr><td>list/decimal.html</td><td>99.64%</td><td>99.73%</td><td>35.89%</td></tr>
<tr><td>list/lower-alpha.html</td><td>99.65%</td><td>99.73%</td><td>35.89%</td></tr>
<tr><td>list/upper-roman.html</td><td>99.45%</td><td>99.61%</td><td>35.94%</td></tr>
<tr><td>overflow.html</td><td>96.85%</td><td>97.49%</td><td>96.5%</td></tr>
<tr><td>text/linethrough.html</td><td>97.14%</td><td>94.12%</td><td>47.08%</td></tr>
<tr><td>text/text.html</td><td>95.71%</td><td>94.67%</td><td>85.01%</td></tr>
<tr><td>text/underline-lineheight.html</td><td>97.06%</td><td>92.35%</td><td>53%</td></tr>
<tr><td>text/underline.html</td><td>97.65%</td><td>93.5%</td><td>47.02%</td></tr>
<tr><td>visibility.html</td><td>99.19%</td><td>98.81%</td><td>99.39%</td></tr>
<tr><td>zindex/z-index1.html</td><td>96.99%</td><td>99.27%</td><td>99.44%</td></tr>
<tr><td>zindex/z-index2.html</td><td>95.85%</td><td>98.06%</td><td>97.72%</td></tr>
<tr><td>zindex/z-index3.html</td><td>98.6%</td><td>98.29%</td><td>98.56%</td></tr>
</tbody></table>

View File

@ -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];