From 7694b11a04e1e6a8200111ee52f1503fa9704d18 Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Mon, 31 Dec 2012 20:10:18 +0200 Subject: [PATCH 1/6] added border radius test --- tests/cases/border/radius.html | 57 ++++++++++++++++++++++++++++++++++ tests/rangetest.html | 37 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 tests/cases/border/radius.html create mode 100644 tests/rangetest.html diff --git a/tests/cases/border/radius.html b/tests/cases/border/radius.html new file mode 100644 index 0000000..fe100b1 --- /dev/null +++ b/tests/cases/border/radius.html @@ -0,0 +1,57 @@ +<!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: #00b5e2; + border-top-color: red; + border-right-color: green; + } + + .box4 { + border-width: 50px; + border-left-color: #00b5e2; + border-top-color: red; + border-right-color: green; + } + + html { + background: #3a84c3; + } + </style> + </head> + <body> + <div class="box1"> </div> + <div class="box2"> </div> + <div class="box3"> </div> + <div class="box4"> </div> + </body> +</html> diff --git a/tests/rangetest.html b/tests/rangetest.html new file mode 100644 index 0000000..bbd3308 --- /dev/null +++ b/tests/rangetest.html @@ -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> From ca32ce6254fe9b88efaf9d1a50b2424328d7b461 Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Wed, 2 Jan 2013 21:26:24 +0200 Subject: [PATCH 2/6] initial border-radius rendering --- src/Parse.js | 345 +++++++++++++++++++++++++-------- src/Queue.js | 6 + tests/cases/border/radius.html | 4 +- 3 files changed, 273 insertions(+), 82 deletions(-) diff --git a/src/Parse.js b/src/Parse.js index eb5ba85..9850ba9 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -330,105 +330,293 @@ _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'); + }); + } + + function pathArc(x, y, cornerX, cornerY, radius) { + return ["arc", cornerX, cornerY, x, y, 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 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 parseBorders(element, ctx, bounds, clip, borders){ var x = bounds.left, y = bounds.top, - w = bounds.width, - h = bounds.height, + 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; - - for (s = 0; s < 4; s+=1){ - borders.push( getCSS(el, 'border' + sides[s] + 'Radius') ); - } - - return borders; - })( el ); + borderRadius = getBorderRadiusData(element); + var tlh = borderRadius[0][0]; + var tlv = borderRadius[0][1]; + var trh = borderRadius[1][0]; + var trv = borderRadius[1][1]; + var brv = borderRadius[2][0]; + var brh = borderRadius[2][1]; + var blh = borderRadius[3][0]; + var blv = borderRadius[3][1]; - for ( borderSide = 0; borderSide < 4; borderSide+=1 ) { - borderData = borders[ borderSide ]; + + var topWidth = width - trh; + var rightHeight = height - brv; + var bottomWidth = width - brh; + var leftHeight = height - blv; + + var topLeftOuter = getCurvePoints( + x, + y, + tlh, + tlv + ).topLeft.subdivide(0.5); + + var 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); + + var topRightOuter = getCurvePoints( + x + topWidth, + y, + trh, + trv + ).topRight.subdivide(0.5); + + var 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); + + var bottomRightOuter = getCurvePoints( + x + bottomWidth, + y + rightHeight, + brh, + brv + ).bottomRight.subdivide(0.5); + var 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); + + var bottomLeftOuter = getCurvePoints( + x, + y + leftHeight, + blh, + blv + ).bottomLeft.subdivide(0.5); + + var 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); + + for (borderSide = 0; borderSide < 4; borderSide++) { + borderData = borders[borderSide]; borderArgs = []; if (borderData.width>0){ bx = x; by = y; - bw = w; - bh = h - (borders[2].width); + bw = width; + bh = height - (borders[2].width); 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], topLeftOuter, topLeftInner, topRightOuter, 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], topRightOuter, topRightInner, bottomRightOuter, 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], bottomRightOuter, bottomRightInner, bottomLeftOuter, 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], bottomLeftOuter, bottomLeftInner, topLeftOuter, topLeftInner); break; } @@ -442,32 +630,25 @@ _html2canvas.Parse = function (images, options) { 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; - } - - } - - + renderBorders(ctx, borderArgs, borderBounds, borderData.color); } } return borders; } + function renderBorders(ctx, borderArgs, borderBounds, color) { + if (borderBounds.width > 0 && borderBounds.height > 0) { + if (color !== "transparent") { + ctx.setVariable( "fillStyle", color); + var shape = ctx.drawShape(); + borderArgs.forEach(function(border, index) { + shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1)); + }); + numDraws+=1; + } + } + } function renderFormValue (el, bounds, stack){ @@ -695,7 +876,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 }; @@ -738,6 +919,8 @@ _html2canvas.Parse = function (images, options) { renderBackgroundImage(element, backgroundBounds, ctx); } + parseBorders(element, ctx, bounds, stack.clip, borders); + switch(element.nodeName){ case "IMG": if ((image = loadImage(element.getAttribute('src')))) { diff --git a/src/Queue.js b/src/Queue.js index bf8dcdf..74ec318 100644 --- a/src/Queue.js +++ b/src/Queue.js @@ -34,6 +34,12 @@ function h2cRenderContext(width, height) { 'arguments': arguments }); }, + arcTo: function() { + shape.push({ + name: "arcTo", + 'arguments': arguments + }); + }, bezierCurveTo: function() { shape.push({ name: "bezierCurveTo", diff --git a/tests/cases/border/radius.html b/tests/cases/border/radius.html index fe100b1..84b0095 100644 --- a/tests/cases/border/radius.html +++ b/tests/cases/border/radius.html @@ -31,7 +31,7 @@ .box3 { border-width: 10px; - border-left-color: #00b5e2; + border-left-color: transparent; border-top-color: red; border-right-color: green; } @@ -40,7 +40,9 @@ border-width: 50px; border-left-color: #00b5e2; border-top-color: red; + border-top-width: 10px; border-right-color: green; + border-bottom-right-radius: 190px; } html { From d29d90b13471405544045d651341fba208b9bd1d Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Thu, 3 Jan 2013 18:37:27 +0200 Subject: [PATCH 3/6] refactored border radius calculation --- src/Parse.js | 170 ++++++++++++++++++--------------- tests/cases/border/radius.html | 3 +- 2 files changed, 96 insertions(+), 77 deletions(-) diff --git a/src/Parse.js b/src/Parse.js index 9850ba9..6c70e35 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -475,6 +475,90 @@ _html2canvas.Parse = function (images, options) { return borderArgs; } + function getBorderBounds(element) { + var backgroundClip = getCSS(element, 'backgroundClip'); + } + + function calculateCurvePoints(bounds, borderRadius, borders) { + + var x = bounds.left, + y = bounds.top, + 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 parseBorders(element, ctx, bounds, clip, borders){ var x = bounds.left, y = bounds.top, @@ -489,78 +573,8 @@ _html2canvas.Parse = function (images, options) { borderArgs, borderBounds, // http://www.w3.org/TR/css3-background/#the-border-radius - borderRadius = getBorderRadiusData(element); - - - var tlh = borderRadius[0][0]; - var tlv = borderRadius[0][1]; - var trh = borderRadius[1][0]; - var trv = borderRadius[1][1]; - var brv = borderRadius[2][0]; - var brh = borderRadius[2][1]; - var blh = borderRadius[3][0]; - var blv = borderRadius[3][1]; - - - var topWidth = width - trh; - var rightHeight = height - brv; - var bottomWidth = width - brh; - var leftHeight = height - blv; - - var topLeftOuter = getCurvePoints( - x, - y, - tlh, - tlv - ).topLeft.subdivide(0.5); - - var 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); - - var topRightOuter = getCurvePoints( - x + topWidth, - y, - trh, - trv - ).topRight.subdivide(0.5); - - var 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); - - var bottomRightOuter = getCurvePoints( - x + bottomWidth, - y + rightHeight, - brh, - brv - ).bottomRight.subdivide(0.5); - var 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); - - var bottomLeftOuter = getCurvePoints( - x, - y + leftHeight, - blh, - blv - ).bottomLeft.subdivide(0.5); - - var 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); + borderRadius = getBorderRadiusData(element), + borderPoints = calculateCurvePoints(bounds, borderRadius, borders); for (borderSide = 0; borderSide < 4; borderSide++) { borderData = borders[borderSide]; @@ -581,7 +595,8 @@ _html2canvas.Parse = function (images, options) { c2: [bx + bw, by], c3: [bx + bw - borders[1].width, by + bh], c4: [bx + borders[3].width, by + bh] - }, borderRadius[0], borderRadius[1], topLeftOuter, topLeftInner, topRightOuter, topRightInner); + }, borderRadius[0], borderRadius[1], + borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner); break; case 1: // right border @@ -593,7 +608,8 @@ _html2canvas.Parse = function (images, options) { c2: [bx + bw, by + bh + borders[2].width], c3: [bx, by + bh], c4: [bx, by + borders[0].width] - }, borderRadius[1], borderRadius[2], topRightOuter, topRightInner, bottomRightOuter, bottomRightInner); + }, borderRadius[1], borderRadius[2], + borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner); break; case 2: // bottom border @@ -605,7 +621,8 @@ _html2canvas.Parse = function (images, options) { c2: [bx, by + bh], c3: [bx + borders[3].width, by], c4: [bx + bw - borders[2].width, by] - }, borderRadius[2], borderRadius[3], bottomRightOuter, bottomRightInner, bottomLeftOuter, bottomLeftInner); + }, borderRadius[2], borderRadius[3], + borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner); break; case 3: // left border @@ -616,7 +633,8 @@ _html2canvas.Parse = function (images, options) { c2: [bx, by], c3: [bx + bw, by + borders[0].width], c4: [bx + bw, by + bh] - }, borderRadius[3], borderRadius[0], bottomLeftOuter, bottomLeftInner, topLeftOuter, topLeftInner); + }, borderRadius[3], borderRadius[0], + borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner); break; } diff --git a/tests/cases/border/radius.html b/tests/cases/border/radius.html index 84b0095..6b883fe 100644 --- a/tests/cases/border/radius.html +++ b/tests/cases/border/radius.html @@ -38,11 +38,12 @@ .box4 { border-width: 50px; - border-left-color: #00b5e2; + 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 { From 1b29b8bc20b2af935ccd1143f9b2d8c351b3d258 Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Thu, 3 Jan 2013 20:34:47 +0200 Subject: [PATCH 4/6] background clipping support --- src/Parse.js | 120 ++++++++++++++++++++----------- src/Queue.js | 28 ++++++++ src/renderers/Canvas.js | 16 ++--- tests/cases/background/clip.html | 60 ++++++++++++++++ 4 files changed, 174 insertions(+), 50 deletions(-) create mode 100644 tests/cases/background/clip.html diff --git a/src/Parse.js b/src/Parse.js index 6c70e35..98aeace 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -345,10 +345,6 @@ _html2canvas.Parse = function (images, options) { }); } - function pathArc(x, y, cornerX, cornerY, radius) { - return ["arc", cornerX, cornerY, x, y, radius]; - } - var getCurvePoints = (function(kappa) { return function(x, y, r1, r2) { @@ -445,6 +441,20 @@ _html2canvas.Parse = function (images, options) { }; } + 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 = []; @@ -475,10 +485,6 @@ _html2canvas.Parse = function (images, options) { return borderArgs; } - function getBorderBounds(element) { - var backgroundClip = getCSS(element, 'backgroundClip'); - } - function calculateCurvePoints(bounds, borderRadius, borders) { var x = bounds.left, @@ -556,36 +562,61 @@ _html2canvas.Parse = function (images, options) { Math.max(0, blh - borders[3].width), Math.max(0, blv - borders[2].width) ).bottomLeft.subdivide(0.5) - } + }; } - function parseBorders(element, ctx, bounds, clip, borders){ + 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, borderArgs, - borderBounds, // http://www.w3.org/TR/css3-background/#the-border-radius borderRadius = getBorderRadiusData(element), - borderPoints = calculateCurvePoints(bounds, borderRadius, borders); + borderPoints = calculateCurvePoints(bounds, borderRadius, borders), + borderData = { + clip: getBorderClip(element, borderPoints, borders, borderRadius, bounds), + borders: [] + }; for (borderSide = 0; borderSide < 4; borderSide++) { - borderData = borders[borderSide]; - borderArgs = []; - if (borderData.width>0){ + + if (borders[borderSide].width > 0) { bx = x; by = y; bw = width; bh = height - (borders[2].width); - switch(borderSide){ + switch(borderSide) { case 0: // top border bh = borders[0].width; @@ -638,33 +669,31 @@ _html2canvas.Parse = function (images, options) { break; } - borderBounds = { - left:bx, - top:by, - width: bw, - height:bh - }; + borderData.borders.push({ + args: borderArgs, + color: borders[borderSide].color + }); - if (clip){ - borderBounds = clipBounds(borderBounds, clip); - } - renderBorders(ctx, borderArgs, borderBounds, borderData.color); } } - return borders; + return borderData; } - function renderBorders(ctx, borderArgs, borderBounds, color) { - if (borderBounds.width > 0 && borderBounds.height > 0) { - if (color !== "transparent") { - ctx.setVariable( "fillStyle", color); - var shape = ctx.drawShape(); - borderArgs.forEach(function(border, index) { - shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1)); - }); - numDraws+=1; - } + 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; } } @@ -930,14 +959,23 @@ _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), + clipPath = 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); } - parseBorders(element, ctx, bounds, stack.clip, borders); + ctx.restore(); + + borderData.borders.forEach(function(border) { + renderBorders(ctx, border.args, border.color); + }); switch(element.nodeName){ case "IMG": diff --git a/src/Queue.js b/src/Queue.js index 74ec318..8d33477 100644 --- a/src/Queue.js +++ b/src/Queue.js @@ -4,6 +4,34 @@ function h2cRenderContext(width, height) { storage: storage, width: width, height: height, + clip: function() { + storage.push({ + type: "function", + name: "clip", + '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", diff --git a/src/renderers/Canvas.js b/src/renderers/Canvas.js index a8fe43c..6d1be34 100644 --- a/src/renderers/Canvas.js +++ b/src/renderers/Canvas.js @@ -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 ) { @@ -150,7 +146,7 @@ _html2canvas.Renderer.Canvas = function( options ) { ctx.fillRect.apply( ctx, renderItem['arguments'] ); } } 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 +171,8 @@ _html2canvas.Renderer.Canvas = function( options ) { } ctx.drawImage.apply( ctx, renderItem['arguments'] ); } + } else { + ctx[renderItem.name].apply(ctx, renderItem['arguments']); } diff --git a/tests/cases/background/clip.html b/tests/cases/background/clip.html new file mode 100644 index 0000000..00bbb22 --- /dev/null +++ b/tests/cases/background/clip.html @@ -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> From 1e81b220270f300112afcaf7b928e37429df1224 Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Thu, 3 Jan 2013 22:25:35 +0200 Subject: [PATCH 5/6] switched background rendering to use patterns --- src/Generate.js | 31 +++------ src/Parse.js | 139 ++++++++-------------------------------- src/Preload.js | 8 +-- src/Queue.js | 14 ++++ src/renderers/Canvas.js | 2 + tests/test.js | 2 +- 6 files changed, 55 insertions(+), 141 deletions(-) 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]; From 687d77174fe8ad6c12d92033cc5b21b9cdbf8899 Mon Sep 17 00:00:00 2001 From: MoyuScript <i@moyu.moe> Date: Thu, 3 Jan 2013 22:30:52 +0200 Subject: [PATCH 6/6] updated results --- tests/readme.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/readme.md b/tests/readme.md index bf29ecd..51db39c 100644 --- a/tests/readme.md +++ b/tests/readme.md @@ -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> \ No newline at end of file