- name: 2d.getcontext.exists desc: The 2D context is implemented testing: - context.2d code: | @assert canvas.getContext('2d') !== null; - name: 2d.type.name desc: The 2D context has the correct interface name testing: - context.2d.type code: | @assert Object.prototype.toString.call(ctx) === '[object CanvasRenderingContext2D]'; - name: 2d.type.exists desc: The 2D context interface is a property of 'window' notes: &bindings Defined in "Language Bindings for DOM Specifications" (draft) testing: - context.2d.type code: | @assert window.CanvasRenderingContext2D; - name: 2d.type.delete desc: window.CanvasRenderingContext2D is DontDelete notes: *bindings testing: - context.2d.type code: | delete window.CanvasRenderingContext2D; @assert window.CanvasRenderingContext2D !== undefined; - name: 2d.type.prototype desc: window.CanvasRenderingContext2D.prototype is { DontDelete, ReadOnly }, and its methods are not notes: *bindings testing: - context.2d.type #mozilla: { bug: TODO } code: | @assert window.CanvasRenderingContext2D.prototype; @assert window.CanvasRenderingContext2D.prototype.fill; window.CanvasRenderingContext2D.prototype = null; @assert window.CanvasRenderingContext2D.prototype; delete window.CanvasRenderingContext2D.prototype; @assert window.CanvasRenderingContext2D.prototype; window.CanvasRenderingContext2D.prototype.fill = 1; @assert window.CanvasRenderingContext2D.prototype.fill === 1; delete window.CanvasRenderingContext2D.prototype.fill; @assert window.CanvasRenderingContext2D.prototype.fill === undefined; @moz-todo - name: 2d.type.replace desc: Interface methods can be overridden notes: *bindings testing: - context.2d.type code: | var fillRect = window.CanvasRenderingContext2D.prototype.fillRect; window.CanvasRenderingContext2D.prototype.fillRect = function (x, y, w, h) { this.fillStyle = '#0f0'; fillRect.call(this, x, y, w, h); }; ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.type.extend desc: Interface methods can be added notes: *bindings testing: - context.2d.type code: | window.CanvasRenderingContext2D.prototype.fillRectGreen = function (x, y, w, h) { this.fillStyle = '#0f0'; this.fillRect(x, y, w, h); }; ctx.fillStyle = '#f00'; ctx.fillRectGreen(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.getcontext.unique desc: getContext('2d') returns the same object testing: - context.2d.unique code: | @assert canvas.getContext('2d') === canvas.getContext('2d'); - name: 2d.getcontext.shared desc: getContext('2d') returns objects which share canvas state testing: - context.2d.unique code: | var ctx2 = canvas.getContext('2d'); ctx.fillStyle = '#f00'; ctx2.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.voidreturn desc: void methods return undefined images: - yellow.png code: | @assert ctx.save() === undefined; @assert ctx.restore() === undefined; @assert ctx.scale(1, 1) === undefined; @assert ctx.rotate(0) === undefined; @assert ctx.translate(0, 0) === undefined; if (ctx.transform) { // (avoid spurious failures, since the aim here is not to test that all features are supported) @assert ctx.transform(1, 0, 0, 1, 0, 0) === undefined; } if (ctx.setTransform) { @assert ctx.setTransform(1, 0, 0, 1, 0, 0) === undefined; } @assert ctx.clearRect(0, 0, 0, 0) === undefined; @assert ctx.fillRect(0, 0, 0, 0) === undefined; @assert ctx.strokeRect(0, 0, 0, 0) === undefined; @assert ctx.beginPath() === undefined; @assert ctx.closePath() === undefined; @assert ctx.moveTo(0, 0) === undefined; @assert ctx.lineTo(0, 0) === undefined; @assert ctx.quadraticCurveTo(0, 0, 0, 0) === undefined; @assert ctx.bezierCurveTo(0, 0, 0, 0, 0, 0) === undefined; @assert ctx.arcTo(0, 0, 0, 0, 1) === undefined; @assert ctx.rect(0, 0, 0, 0) === undefined; @assert ctx.arc(0, 0, 1, 0, 0, true) === undefined; @assert ctx.fill() === undefined; @assert ctx.stroke() === undefined; @assert ctx.clip() === undefined; if (ctx.putImageData) { @assert ctx.putImageData(ctx.getImageData(0, 0, 1, 1), 0, 0) === undefined; } @assert ctx.drawImage(document.getElementById('yellow.png'), 0, 0, 0, 0, 0, 0, 0, 0) === undefined; @assert ctx.drawImage(canvas, 0, 0, 0, 0, 0, 0, 0, 0) === undefined; @assert ctx.createLinearGradient(0, 0, 0, 0).addColorStop(0, 'white') === undefined; - name: 2d.coordinatespace desc: Coordinate space goes from top-left to bottom-right notes: This should not be upside down. mozilla: { disabled } # since it requires manual verification testing: - 2d.coordinatespace code: | ctx.fillStyle = '#00f'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0ff'; ctx.fillRect(0, 0, 50, 25); @assert pixel 25,12 == 0,255,255,255; @assert pixel 75,12 == 0,0,255,255; @assert pixel 25,37 == 0,0,255,255; @assert pixel 75,37 == 0,0,255,255; @manual; // because we can't tell that getPixelData isn't using the wrong coordinate space too expected: | size 100 50 cr.set_source_rgb(0, 0, 1) cr.rectangle(0, 0, 100, 50) cr.fill() cr.set_source_rgb(0, 1, 1) cr.rectangle(0, 0, 50, 25) cr.fill() - name: 2d.canvas.reference desc: CanvasRenderingContext2D.canvas refers back to its canvas testing: - 2d.canvas code: | @assert ctx.canvas === canvas; - name: 2d.canvas.readonly desc: CanvasRenderingContext2D.canvas is readonly testing: - 2d.canvas.attribute code: | var c = document.createElement('canvas'); var d = ctx.canvas; @assert c !== d; try { ctx.canvas = c; } catch (e) {} // not sure whether this should throw or not... @assert ctx.canvas === d; - meta: | state = [ # some non-default values to test with ('strokeStyle', '"#ff0000"'), ('fillStyle', '"#ff0000"'), ('globalAlpha', 0.5), ('lineWidth', 0.5), ('lineCap', '"round"'), ('lineJoin', '"round"'), ('miterLimit', 0.5), ('shadowOffsetX', 5), ('shadowOffsetY', 5), ('shadowBlur', 5), ('shadowColor', '"#ff0000"'), ('globalCompositeOperation', '"copy"'), ] for key,value in state: tests.append( { 'name': '2d.state.saverestore.%s' % key, 'desc': 'save()/restore() works for %s' % key, 'testing': [ '2d.state.%s' % key ], 'code': """// Test that restore() undoes any modifications var old = ctx.%(key)s; ctx.save(); ctx.%(key)s = %(value)s; ctx.restore(); @assert ctx.%(key)s === old; // Also test that save() doesn't modify the values ctx.%(key)s = %(value)s; old = ctx.%(key)s; // we're not interested in failures caused by get(set(x)) != x (e.g. // from rounding), so compare against d instead of against %(value)s ctx.save(); @assert ctx.%(key)s === old; ctx.restore(); """ % { 'key':key, 'value':value } } ) tests.append( { 'name': 'initial.reset.2dstate', 'desc': 'Resetting the canvas state resets 2D state variables', 'testing': [ 'initial.reset' ], 'code': """canvas.width = 100; var default_val; """ + "".join( """ default_val = ctx.%(key)s; ctx.%(key)s = %(value)s; canvas.width = 100; @assert ctx.%(key)s === default_val; """ % { 'key':key, 'value':value } for key,value in state), } ) - name: 2d.state.saverestore.transformation desc: save()/restore() affects the current transformation matrix testing: - 2d.state.transformation code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.translate(200, 0); ctx.restore(); ctx.fillStyle = '#f00'; ctx.fillRect(-200, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.state.saverestore.clip desc: save()/restore() affects the clipping path testing: - 2d.state.clip code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.rect(0, 0, 1, 1); ctx.clip(); ctx.restore(); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.state.saverestore.path desc: save()/restore() does not affect the current path testing: - 2d.state.path code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.rect(0, 0, 100, 50); ctx.restore(); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.state.saverestore.bitmap desc: save()/restore() does not affect the current bitmap testing: - 2d.state.bitmap code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.restore(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.state.saverestore.stack desc: save()/restore() can be nested as a stack testing: - 2d.state.save - 2d.state.restore code: | ctx.lineWidth = 1; ctx.save(); ctx.lineWidth = 2; ctx.save(); ctx.lineWidth = 3; @assert ctx.lineWidth == 3; ctx.restore(); @assert ctx.lineWidth == 2; ctx.restore(); @assert ctx.lineWidth == 1; - name: 2d.state.saverestore.stackdepth desc: save()/restore() stack depth is not unreasonably limited testing: - 2d.state.save - 2d.state.restore code: | var limit = 512; for (var i = 1; i < limit; ++i) { ctx.save(); ctx.lineWidth = i; } for (var i = limit-1; i > 0; --i) { @assert ctx.lineWidth == i; ctx.restore(); } - name: 2d.state.saverestore.underflow desc: restore() with an empty stack has no effect testing: - 2d.state.restore.underflow mozilla: { disabled, bug: 296821 } code: | for (var i = 0; i < 16; ++i) ctx.restore(); ctx.lineWidth = 0.5; ctx.restore(); @assert ctx.lineWidth == 0.5; - name: 2d.transformation.order desc: Transformations are applied in the right order testing: - 2d.transformation.order code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(2, 1); ctx.rotate(Math.PI / 2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -50, 50, 50); @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.basic desc: scale() works testing: - 2d.transformation.scale code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(2, 4); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 12.5); @assert pixel 90,40 == 0,255,0,255; expected: green - name: 2d.transformation.scale.zero desc: scale() with a scale factor of zero works testing: - 2d.transformation.scale code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.translate(50, 0); ctx.scale(0, 1); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.restore(); ctx.save(); ctx.translate(0, 25); ctx.scale(1, 0); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.restore(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.negative desc: scale() with negative scale factors works testing: - 2d.transformation.scale code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.scale(-1, 1); ctx.fillStyle = '#0f0'; ctx.fillRect(-50, 0, 50, 50); ctx.restore(); ctx.save(); ctx.scale(1, -1); ctx.fillStyle = '#0f0'; ctx.fillRect(50, -50, 50, 50); ctx.restore(); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.large desc: scale() with large scale factors works notes: Not really that large at all, but it hits the limits in Firefox. testing: - 2d.transformation.scale code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(1e5, 1e5); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 1, 1); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.infinity desc: scale() with Infinity makes nothing be drawn testing: - 2d.transformation.scale mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.scale(Infinity, 10); ctx.fillStyle = '#f00'; ctx.fillRect(-10, -10, 20, 20); ctx.restore(); ctx.save(); ctx.scale(10, Infinity); ctx.fillStyle = '#f00'; ctx.fillRect(-10, -10, 20, 20); ctx.restore(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.neginfinity desc: scale() with -Infinity makes nothing be drawn testing: - 2d.transformation.scale mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.scale(-Infinity, 10); ctx.fillStyle = '#f00'; ctx.fillRect(-10, -10, 20, 20); ctx.restore(); ctx.save(); ctx.scale(10, -Infinity); ctx.fillStyle = '#f00'; ctx.fillRect(-10, -10, 20, 20); ctx.restore(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.scale.nan desc: scale() with NaN throws an exception testing: - 2d.transformation.scale mozilla: { disabled } # TODO: report bug? code: | @assert throws NOT_SUPPORTED_ERR ctx.scale(NaN, 1); @assert throws NOT_SUPPORTED_ERR ctx.scale(1, NaN); @assert throws NOT_SUPPORTED_ERR ctx.scale(NaN, NaN); - name: 2d.transformation.scale.multiple desc: Multiple scale()s combine testing: - 2d.transformation.scale.multiple code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(Math.sqrt(2), Math.sqrt(2)); ctx.scale(Math.sqrt(2), Math.sqrt(2)); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 25); @assert pixel 90,40 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.zero testing: - 2d.transformation.rotate code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(0); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.radians testing: - 2d.transformation.rotate.radians code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI); ctx.fillStyle = '#0f0'; ctx.fillRect(-100, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.direction testing: - 2d.transformation.rotate.direction code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI / 2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -100, 50, 100); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.wrap testing: - 2d.transformation.rotate code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI * (1 + 4096)); // == PI (mod 2*PI) // We need about pi +/- 0.001 in order to get correct-looking results // 32-bit floats can store pi*4097 with precision 2^-10, so that should // be safe enough on reasonable implementations ctx.fillStyle = '#0f0'; ctx.fillRect(-100, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,2 == 0,255,0,255; @assert pixel 98,47 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.wrapnegative testing: - 2d.transformation.rotate code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(-Math.PI * (1 + 4096)); ctx.fillStyle = '#0f0'; ctx.fillRect(-100, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,2 == 0,255,0,255; @assert pixel 98,47 == 0,255,0,255; expected: green - name: 2d.transformation.rotate.infinity testing: - 2d.transformation.rotate #mozilla: { bug: TODO } code: | @assert throws NOT_SUPPORTED_ERR ctx.rotate(Infinity); @moz-todo - name: 2d.transformation.rotate.neginfinity testing: - 2d.transformation.rotate #mozilla: { bug: TODO } code: | @assert throws NOT_SUPPORTED_ERR ctx.rotate(-Infinity); @moz-todo - name: 2d.transformation.rotate.nan testing: - 2d.transformation.rotate #mozilla: { bug: TODO } code: | @assert throws NOT_SUPPORTED_ERR ctx.rotate(NaN); @moz-todo - name: 2d.transformation.translate.basic testing: - 2d.transformation.translate code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.translate(100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(-100, -50, 100, 50); @assert pixel 90,40 == 0,255,0,255; expected: green - name: 2d.transformation.translate.infinity testing: - 2d.transformation.translate mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.translate(Infinity, 0); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.translate.nan testing: - 2d.transformation.translate mozilla: { disabled } # TODO: report bug? code: | @assert throws NOT_SUPPORTED_ERR ctx.translate(NaN, 0); - name: 2d.transformation.transform.identity testing: - 2d.transformation.transform code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.transform(1,0, 0,1, 0,0); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.transform.skewed testing: - 2d.transformation.transform code: | // Create green with a red square ring inside it ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(20, 10, 60, 30); ctx.fillStyle = '#0f0'; ctx.fillRect(40, 20, 20, 10); // Draw a skewed shape to fill that gap, to make sure it is aligned correctly ctx.transform(1,4, 2,3, 5,6); // Post-transform coordinates: // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]]; // Hence pre-transform coordinates: var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2], [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2], [-7.4,11.2]]; ctx.beginPath(); ctx.moveTo(pts[0][0], pts[0][1]); for (var i = 0; i < pts.length; ++i) ctx.lineTo(pts[i][0], pts[i][1]); ctx.fill(); @assert pixel 21,11 == 0,255,0,255; @assert pixel 79,11 == 0,255,0,255; @assert pixel 21,39 == 0,255,0,255; @assert pixel 79,39 == 0,255,0,255; @assert pixel 39,19 == 0,255,0,255; @assert pixel 61,19 == 0,255,0,255; @assert pixel 39,31 == 0,255,0,255; @assert pixel 61,31 == 0,255,0,255; expected: green - name: 2d.transformation.transform.multiply testing: - 2d.transformation.transform.multiply code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.transform(1,2, 3,4, 5,6); ctx.transform(-2,1, 3/2,-1/2, 1,-2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.transform.infinity testing: - 2d.transformation.transform mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.transform(Infinity,0, 0,Infinity, 0,0); ctx.fillStyle = '#f00'; ctx.fillRect(-10, -10, 20, 20); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.transformation.setTransform.skewed testing: - 2d.transformation.setTransform code: | // Create green with a red square ring inside it ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(20, 10, 60, 30); ctx.fillStyle = '#0f0'; ctx.fillRect(40, 20, 20, 10); // Draw a skewed shape to fill that gap, to make sure it is aligned correctly ctx.setTransform(1,4, 2,3, 5,6); // Post-transform coordinates: // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]]; // Hence pre-transform coordinates: var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2], [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2], [-7.4,11.2]]; ctx.beginPath(); ctx.moveTo(pts[0][0], pts[0][1]); for (var i = 0; i < pts.length; ++i) ctx.lineTo(pts[i][0], pts[i][1]); ctx.fill(); @assert pixel 21,11 == 0,255,0,255; @assert pixel 79,11 == 0,255,0,255; @assert pixel 21,39 == 0,255,0,255; @assert pixel 79,39 == 0,255,0,255; @assert pixel 39,19 == 0,255,0,255; @assert pixel 61,19 == 0,255,0,255; @assert pixel 39,31 == 0,255,0,255; @assert pixel 61,31 == 0,255,0,255; expected: green - name: 2d.transformation.setTransform.multiple testing: - 2d.transformation.setTransform.identity code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.setTransform(1/2,0, 0,1/2, 0,0); ctx.setTransform(2,0, 0,2, 0,0); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 25); @assert pixel 75,35 == 0,255,0,255; expected: green - name: 2d.composite.globalAlpha.range testing: - 2d.composite.globalAlpha.range code: | ctx.globalAlpha = 0.5; var a = ctx.globalAlpha; // might not be exactly 0.5, if it is rounded/quantised, so remember for future comparisons ctx.globalAlpha = 1.1; @assert ctx.globalAlpha == a; ctx.globalAlpha = -0.1; @assert ctx.globalAlpha == a; ctx.globalAlpha = 0; @assert ctx.globalAlpha == 0; ctx.globalAlpha = 1; @assert ctx.globalAlpha == 1; - name: 2d.composite.globalAlpha.invalid mozilla: { disabled } # TODO: report bug? testing: - 2d.composite.globalAlpha.range code: | ctx.globalAlpha = 0.5; var a = ctx.globalAlpha; // might not be exactly 0.5, if it is rounded/quantised, so remember for future comparisons @assert throws NOT_SUPPORTED_ERR ctx.globalAlpha = Infinity; @assert ctx.globalAlpha == a; @assert throws NOT_SUPPORTED_ERR ctx.globalAlpha = -Infinity; @assert ctx.globalAlpha == a; @assert throws NOT_SUPPORTED_ERR ctx.globalAlpha = NaN; @assert ctx.globalAlpha == a; - name: 2d.composite.globalAlpha.default testing: - 2d.composite.globalAlpha.default code: | @assert ctx.globalAlpha === 1.0; - name: 2d.composite.globalAlpha.fill testing: - 2d.composite.globalAlpha.shape code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 2,253,0,255; expected: green - name: 2d.composite.globalAlpha.image testing: - 2d.composite.globalAlpha.image images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations ctx.drawImage(document.getElementById('red.png'), 0, 0); @assert pixel 50,25 ==~ 2,253,0,255; expected: green - name: 2d.composite.globalAlpha.canvas testing: - 2d.composite.globalAlpha.image code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations ctx.drawImage(canvas2, 0, 0); @assert pixel 50,25 ==~ 2,253,0,255; expected: green - name: 2d.composite.globalAlpha.imagepattern mozilla: { bug: 401790 } testing: - 2d.composite.globalAlpha.image images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = ctx.createPattern(document.getElementById('red.png'), 'no-repeat'); ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 2,253,0,255; @moz-todo expected: green - name: 2d.composite.globalAlpha.canvaspattern mozilla: { bug: 401790 } testing: - 2d.composite.globalAlpha.image code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = ctx.createPattern(canvas2, 'no-repeat'); ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 2,253,0,255; @moz-todo expected: green - meta: | # Proposed definition - http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2007-March/010608.html ops = [ # name FA FB ('source-over', '1', '1-aA'), ('destination-over', '1-aB', '1'), ('source-in', 'aB', '0'), ('destination-in', '0', 'aA'), ('source-out', '1-aB', '0'), ('destination-out', '0', '1-aA'), ('source-atop', 'aB', '1-aA'), ('destination-atop', '1-aB', 'aA'), ('xor', '1-aB', '1-aA'), ('copy', '1', '0'), ('lighter', '1', '1'), ] # The ones that change the output when src = (0,0,0,0) ops_trans = [ 'source-in', 'destination-in', 'source-out', 'destination-atop', 'copy' ]; def calc_output((RA, GA, BA, aA), (RB, GB, BB, aB), FA_code, FB_code): rA, gA, bA = RA*aA, GA*aA, BA*aA rB, gB, bB = RB*aB, GB*aB, BB*aB FA = eval(FA_code) FB = eval(FB_code) rO = rA*FA + rB*FB gO = gA*FA + gB*FB bO = bA*FA + bB*FB aO = aA*FA + aB*FB rO = min(255, rO) gO = min(255, gO) bO = min(255, bO) aO = min(1, aO) if aO: RO = rO / aO GO = gO / aO BO = bO / aO else: RO = GO = BO = 0 return (RO, GO, BO, aO) def to_css((r,g,b,a)): return 'rgba(%d,%d,%d,%f)' % (r, g, b, a) def to_test((r,g,b,a)): return '%d,%d,%d,%d' % (r, g, b, int(a*255)) def to_cairo((r,g,b,a)): return '%f,%f,%f,%f' % (r/255., g/255., b/255., a) for (name, src, dest) in [ ('solid', (255, 255, 0, 1.0), (0, 255, 255, 1.0)), ('transparent', (0, 0, 255, 0.75), (0, 255, 0, 0.5)), # catches the atop, xor and lighter bugs in Opera 9.10 ]: for op, FA_code, FB_code in ops: expected = calc_output(src, dest, FA_code, FB_code) tests.append( { 'name': '2d.composite.%s.%s' % (name, op), 'notes': 'Assumes this definition.', 'testing': [ '2d.composite.%s' % op ], 'code': """ ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = '%s'; ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ %s +/- 5; """ % (dest, op, src, to_test(expected)), 'expected': """size 100 50 cr.set_source_rgba(%s) cr.rectangle(0, 0, 100, 50) cr.fill() """ % to_cairo(expected), } ) for (name, src, dest) in [ ('image', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]: for op, FA_code, FB_code in ops: expected = calc_output(src, dest, FA_code, FB_code) tests.append( { 'name': '2d.composite.%s.%s' % (name, op), 'notes': 'Assumes this definition.', 'testing': [ '2d.composite.%s' % op ], 'images': [ 'yellow75.png' ], 'code': """ ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = '%s'; ctx.drawImage(document.getElementById('yellow75.png'), 0, 0); @assert pixel 50,25 ==~ %s +/- 5; """ % (dest, op, to_test(expected)), 'expected': """size 100 50 cr.set_source_rgba(%s) cr.rectangle(0, 0, 100, 50) cr.fill() """ % to_cairo(expected), } ) notes = """Pixels not covered by the source object should be drawn as (0,0,0,0), not left unchanged. Assumes this definition of the operations.""" for (name, src, dest) in [ ('uncovered.fill', (0, 0, 255, 0.75), (0, 255, 0, 0.5)) ]: for op, FA_code, FB_code in ops: if op not in ops_trans: continue expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) expected1 = calc_output(src, dest, FA_code, FB_code) tests.append( { 'name': '2d.composite.%s.%s' % (name, op), 'notes': notes, 'testing': [ '2d.composite.%s' % op ], 'code': """ ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = '%s'; ctx.fillStyle = 'rgba%s'; ctx.translate(0, 25); ctx.fillRect(0, 50, 100, 50); @assert pixel 50,25 ==~ %s +/- 5; """ % (dest, op, src, to_test(expected0)), 'expected': """size 100 50 cr.set_source_rgba(%s) cr.rectangle(0, 0, 100, 50) cr.fill() """ % (to_cairo(expected0)), } ) for (name, src, dest) in [ ('uncovered.image', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]: for op, FA_code, FB_code in ops: if op not in ops_trans: continue expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) expected1 = calc_output(src, dest, FA_code, FB_code) tests.append( { 'name': '2d.composite.%s.%s' % (name, op), 'notes': notes, 'testing': [ '2d.composite.%s' % op ], 'images': [ 'yellow.png' ], 'code': """ ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = '%s'; ctx.drawImage(document.getElementById('yellow.png'), 0, 50) @assert pixel 50,25 ==~ %s +/- 5; """ % (dest, op, to_test(expected0)), 'expected': """size 100 50 cr.set_source_rgba(%s) cr.rectangle(0, 0, 100, 50) cr.fill() """ % (to_cairo(expected0)), } ) for (name, src, dest) in [ ('uncovered.pattern', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]: for op, FA_code, FB_code in ops: if op not in ops_trans: continue expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) expected1 = calc_output(src, dest, FA_code, FB_code) tests.append( { 'name': '2d.composite.%s.%s' % (name, op), 'notes': notes, 'testing': [ '2d.composite.%s' % op ], 'images': [ 'yellow.png' ], 'code': """ ctx.fillStyle = 'rgba%s'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = '%s'; ctx.fillStyle = ctx.createPattern(document.getElementById('yellow.png'), 'no-repeat'); ctx.fillRect(0, 50, 100, 50); @assert pixel 50,25 ==~ %s +/- 5; """ % (dest, op, to_test(expected0)), 'expected': """size 100 50 cr.set_source_rgba(%s) cr.rectangle(0, 0, 100, 50) cr.fill() """ % (to_cairo(expected0)), } ) - name: 2d.composite.operation.get testing: - 2d.composite.operation code: | var modes = ['source-atop', 'source-in', 'source-out', 'source-over', 'destination-atop', 'destination-in', 'destination-out', 'destination-over', 'lighter', 'copy', 'xor']; for (var i = 0; i < modes.length; ++i) { ctx.globalCompositeOperation = modes[i]; @assert ctx.globalCompositeOperation == modes[i]; } - name: 2d.composite.operation.unrecognised mozilla: { disabled, bug: 401788 } testing: - 2d.composite.operation.unrecognised code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'nonexistent'; @assert ctx.globalCompositeOperation == 'xor'; - name: 2d.composite.operation.darker #mozilla: { bug: TODO } testing: - 2d.composite.operation.unrecognised code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'darker'; @assert ctx.globalCompositeOperation == 'xor'; @moz-todo - name: 2d.composite.operation.over #mozilla: { bug: TODO } testing: - 2d.composite.operation.unrecognised code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'over'; @assert ctx.globalCompositeOperation == 'xor'; @moz-todo - name: 2d.composite.operation.clear #mozilla: { bug: TODO } testing: - 2d.composite.operation.unrecognised code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'clear'; @assert ctx.globalCompositeOperation == 'xor'; @moz-todo - name: 2d.composite.operation.highlight mozilla: { disabled, bug: 401788 } testing: - 2d.composite.operation.unrecognised code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'highlight'; @assert ctx.globalCompositeOperation == 'xor'; - name: 2d.composite.operation.nullsuffix mozilla: { disabled, bug: 401788 } testing: - 2d.composite.operation.exact code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'source-over\0'; @assert ctx.globalCompositeOperation == 'xor'; - name: 2d.composite.operation.casesensitive mozilla: { disabled, bug: 401788 } testing: - 2d.composite.operation.casesensitive code: | ctx.globalCompositeOperation = 'xor'; ctx.globalCompositeOperation = 'Source-over'; @assert ctx.globalCompositeOperation == 'xor'; - name: 2d.composite.operation.default testing: - 2d.composite.operation.default code: | @assert ctx.globalCompositeOperation == 'source-over'; - meta: | # Try most of the CSS3 Color values - http://www.w3.org/TR/css3-color/#colorunits for name, string, r,g,b,a, notes in [ ('html4', 'limE', 0,255,0,255, ""), ('hex3', '#0f0', 0,255,0,255, ""), ('hex6', '#00fF00', 0,255,0,255, ""), ('rgb-num', 'rgb(0,255,0)', 0,255,0,255, ""), ('rgb-clamp-1', 'rgb(-1000, 1000, -1000)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'), ('rgb-clamp-2', 'rgb(-200%, 200%, -200%)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'), ('rgb-percent', 'rgb(0% ,100% ,0%)', 0,255,0,255, 'CSS3 Color says "The integer value 255 corresponds to 100%". (In particular, it is not 254...)'), ('rgba-solid-1', 'rgba( 0 , 255 , 0 , 1 )', 0,255,0,255, ""), ('rgba-solid-2', 'rgba( 0 , 255 , 0 , 1.0 )', 0,255,0,255, ""), ('rgba-num-1', 'rgba( 0 , 255 , 0 , .499 )', 0,255,0,127, ""), ('rgba-num-2', 'rgba( 0 , 255 , 0 , 0.499 )', 0,255,0,127, ""), ('rgba-percent', 'rgba(0%,100%,0%,0.499)', 0,255,0,127, ""), # 0.499*255 rounds to 127, both down and nearest, so it should be safe ('rgba-clamp-1', 'rgba(0, 255, 0, -2)', 0,0,0,0, ""), ('rgba-clamp-2', 'rgba(0, 255, 0, 2)', 0,255,0,255, ""), ('transparent-1', 'transparent', 0,0,0,0, ""), ('transparent-2', 'TrAnSpArEnT', 0,0,0,0, ""), ('hsl-1', 'hsl(120, 100%, 50%)', 0,255,0,255, ""), ('hsl-2', 'hsl( -240 , 100% , 50% )', 0,255,0,255, ""), ('hsl-3', 'hsl(360120, 100%, 50%)', 0,255,0,255, ""), ('hsl-4', 'hsl(-360240, 100%, 50%)', 0,255,0,255, ""), ('hsl-5', 'hsl(120.0, 100.0%, 50.0%)', 0,255,0,255, ""), ('hsla-1', 'hsla(120, 100%, 50%, 0.499)', 0,255,0,127, ""), ('hsla-2', 'hsla( 120.0 , 100.0% , 50.0% , 1 )', 0,255,0,255, ""), ('svg-1', 'gray', 128,128,128,255, ""), ('svg-2', 'grey', 128,128,128,255, ""), ('current', 'currentColor', 0,255,0,255, ""), ]: # TODO: test by retrieving fillStyle, instead of actually drawing test = { 'name': '2d.fillStyle.parse.%s' % name, 'testing': [ '2d.colours.parse' ], 'notes': notes, 'code': """ ctx.fillStyle = '#f00'; ctx.fillStyle = '%s'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == %d,%d,%d,%d; """ % (string, r,g,b,a), 'expected': """size 100 50 cr.set_source_rgba(%f, %f, %f, %f) cr.rectangle(0, 0, 100, 50) cr.fill() """ % (r/255., g/255., b/255., a/255.), } if name == 'current': test['canvas'] = 'width="100" height="50" style="color:#0f0"' test['mozilla'] = { 'disabled': None } # TODO: report bug? tests.append(test) # Also test that invalid colours are ignored for name, string in [ ('hex3', '#g00'), ('hex6', '#fg0000'), ('rgb-1', 'rgb(255.0, 0, 0)'), ('rgb-2', 'rgb(255, 0.0, 0)'), ('rgb-3', 'rgb(255.0, 0, 0,)'), ('rgb-4', 'rgb(100%, 0, 0)'), ('rgb-5', 'rgb(255 0 0)'), ('rgb-6', 'rgb(255, - 1, 0)'), ('rgb-7', 'rgb(255, 0, 0, 1)'), ('rgba-1', 'rgba(255, 0, 0)'), ('rgba-2', 'rgba(255.0, 0, 0, 1)'), ('rgba-3', 'rgba(100%, 0, 0, 1)'), ('rgba-4', 'rgba(255, 0, 0, 100%)'), ('rgba-5', 'rgba(255, 0, 0, 1. 0)'), ('hsl-1', 'hsl(0%, 100%, 50%)'), ('hsl-2', 'hsl(z, 100%, 50%)'), ('hsl-3', 'hsl(0, 0, 50%)'), ('hsl-4', 'hsl(0, 100%, 0)'), ('hsl-5', 'hsl(0, 100%, 100%, 1)'), ('hsla-1', 'hsla(0%, 100%, 50%, 1)'), ('hsla-2', 'hsla(0, 0, 50%, 1)'), ]: test = { 'name': '2d.fillStyle.parse.invalid.%s' % name, 'testing': [ '2d.colours.parse' ], 'code': """ ctx.fillStyle = '#0f0'; try { ctx.fillStyle = '%s'; } catch (e) { } // this shouldn't throw, but it shouldn't matter here if it does ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; """ % string, 'expected': 'green' } tests.append(test) # Some can't have positive tests, only negative tests, because we don't know what colour they're meant to be for name, string in [ ('system', 'ThreeDDarkShadow'), ('flavor', 'flavor'), ]: test = { 'name': '2d.fillStyle.parse.%s' % name, 'testing': [ '2d.colours.parse' ], 'code': """ ctx.fillStyle = '#f00'; ctx.fillStyle = '%s'; @assert ctx.fillStyle =~ /^#(?!(FF0000|ff0000|f00)$)/; // test that it's not red """ % (string,), } tests.append(test) - name: 2d.fillStyle.invalidstring testing: - 2d.colours.invalidstring code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillStyle = 'invalid'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillStyle.invalidtype testing: - 2d.colours.invalidtype code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillStyle = null; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillStyle.get.solid testing: - 2d.colours.getcolour.solid code: | ctx.fillStyle = '#fa0'; @assert ctx.fillStyle === '#ffaa00'; - name: 2d.fillStyle.get.semitransparent testing: - 2d.colours.getcolour.transparent code: | ctx.fillStyle = 'rgba(255,255,255,0.45)'; @assert ctx.fillStyle =~ /^rgba\(255, 255, 255, 0\.4\d+\)$/; - name: 2d.fillStyle.get.transparent testing: - 2d.colours.getcolour.transparent code: | ctx.fillStyle = 'rgba(0,0,0,0)'; @assert ctx.fillStyle == 'rgba(0, 0, 0, 0.0)'; - name: 2d.fillStyle.default testing: - 2d.colours.default code: | @assert ctx.fillStyle == '#000000'; - name: 2d.strokeStyle.default testing: - 2d.colours.default code: | @assert ctx.strokeStyle == '#000000'; - name: 2d.gradient.object.return testing: - 2d.gradient.return.linear - 2d.gradient.return.radial code: | var g1 = ctx.createLinearGradient(0, 0, 100, 0); @assert Object.prototype.toString.call(g1) === '[object CanvasGradient]'; @assert g1.addColorStop !== undefined; var g2 = ctx.createRadialGradient(0, 0, 10, 0, 0, 20); @assert Object.prototype.toString.call(g2) === '[object CanvasGradient]'; @assert g2.addColorStop !== undefined; - name: 2d.gradient.interpolate.solid testing: - 2d.gradient.interpolate.linear code: | var g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.gradient.interpolate.colour testing: - 2d.gradient.interpolate.linear code: | var g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, '#ff0'); g.addColorStop(1, '#00f'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 25,25 ==~ 191,191,63,255; @assert pixel 50,25 ==~ 127,127,127,255; @assert pixel 75,25 ==~ 63,63,191,255; expected: | size 100 50 g = cairo.LinearGradient(0, 0, 100, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.gradient.interpolate.alpha testing: - 2d.gradient.interpolate.linear code: | ctx.fillStyle = '#ff0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, 'rgba(0,0,255, 0)'); g.addColorStop(1, 'rgba(0,0,255, 1)'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 25,25 ==~ 191,191,63,255; @assert pixel 50,25 ==~ 127,127,127,255; @assert pixel 75,25 ==~ 63,63,191,255; expected: | size 100 50 g = cairo.LinearGradient(0, 0, 100, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.gradient.interpolate.colouralpha testing: - 2d.gradient.interpolate.alpha code: | var g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, 'rgba(255,255,0, 0)'); g.addColorStop(1, 'rgba(0,0,255, 1)'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 25,25 ==~ 191,191,63,63; @assert pixel 50,25 ==~ 127,127,127,127; @assert pixel 75,25 ==~ 63,63,191,191; expected: | size 100 50 g = cairo.LinearGradient(0, 0, 100, 0) g.add_color_stop_rgba(0, 1,1,0, 0) g.add_color_stop_rgba(1, 0,0,1, 1) cr.set_source(g) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.gradient.interpolate.outside testing: - 2d.gradient.outside.first - 2d.gradient.outside.last code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createLinearGradient(25, 0, 75, 0); g.addColorStop(0.4, '#0f0'); g.addColorStop(0.6, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 20,25 ==~ 0,255,0,255; @assert pixel 50,25 ==~ 0,255,0,255; @assert pixel 80,25 ==~ 0,255,0,255; expected: green - name: 2d.gradient.interpolate.zerosize testing: - 2d.gradient.zerosize #mozilla: { bug: TODO } code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction) g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 40,20 ==~ 0,255,0,255; @moz-todo expected: green - name: 2d.gradient.interpolate.vertical testing: - 2d.gradient.interpolate.linear code: | var g = ctx.createLinearGradient(0, 0, 0, 50); g.addColorStop(0, '#ff0'); g.addColorStop(1, '#00f'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,12 ==~ 191,191,63,255 +/- 10; @assert pixel 50,25 ==~ 127,127,127,255 +/- 5; @assert pixel 50,37 ==~ 63,63,191,255 +/- 10; expected: | size 100 50 g = cairo.LinearGradient(0, 0, 0, 50) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.gradient.interpolate.multiple testing: - 2d.gradient.interpolate.linear code: | canvas.width = 200; var g = ctx.createLinearGradient(0, 0, 200, 0); g.addColorStop(0, '#ff0'); g.addColorStop(0.5, '#0ff'); g.addColorStop(1, '#f0f'); ctx.fillStyle = g; ctx.fillRect(0, 0, 200, 50); @assert pixel 50,25 ==~ 127,255,127,255; @assert pixel 100,25 ==~ 0,255,255,255; @assert pixel 150,25 ==~ 127,127,255,255; expected: | size 200 50 g = cairo.LinearGradient(0, 0, 200, 0) g.add_color_stop_rgb(0.0, 1,1,0) g.add_color_stop_rgb(0.5, 0,1,1) g.add_color_stop_rgb(1.0, 1,0,1) cr.set_source(g) cr.rectangle(0, 0, 200, 50) cr.fill() - name: 2d.gradient.interpolate.overlap testing: - 2d.gradient.interpolate.overlap code: | canvas.width = 200; var g = ctx.createLinearGradient(0, 0, 200, 0); g.addColorStop(0, '#f00'); g.addColorStop(0, '#ff0'); g.addColorStop(0.25, '#00f'); g.addColorStop(0.25, '#0f0'); g.addColorStop(0.25, '#0f0'); g.addColorStop(0.25, '#0f0'); g.addColorStop(0.25, '#ff0'); g.addColorStop(0.5, '#00f'); g.addColorStop(0.5, '#0f0'); g.addColorStop(0.75, '#00f'); g.addColorStop(0.75, '#f00'); g.addColorStop(0.75, '#ff0'); g.addColorStop(0.5, '#0f0'); g.addColorStop(0.5, '#0f0'); g.addColorStop(0.5, '#ff0'); g.addColorStop(1, '#00f'); ctx.fillStyle = g; ctx.fillRect(0, 0, 200, 50); @assert pixel 49,25 ==~ 0,0,255,255 +/- 16; @assert pixel 51,25 ==~ 255,255,0,255 +/- 16; @assert pixel 99,25 ==~ 0,0,255,255 +/- 16; @assert pixel 101,25 ==~ 255,255,0,255 +/- 16; @assert pixel 149,25 ==~ 0,0,255,255 +/- 16; @assert pixel 151,25 ==~ 255,255,0,255 +/- 16; expected: | size 200 50 g = cairo.LinearGradient(0, 0, 50, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(0, 0, 50, 50) cr.fill() g = cairo.LinearGradient(50, 0, 100, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(50, 0, 50, 50) cr.fill() g = cairo.LinearGradient(100, 0, 150, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(100, 0, 50, 50) cr.fill() g = cairo.LinearGradient(150, 0, 200, 0) g.add_color_stop_rgb(0, 1,1,0) g.add_color_stop_rgb(1, 0,0,1) cr.set_source(g) cr.rectangle(150, 0, 50, 50) cr.fill() - name: 2d.gradient.interpolate.overlap2 testing: - 2d.gradient.interpolate.overlap code: | var g = ctx.createLinearGradient(0, 0, 100, 0); var ps = [ 0, 1/10, 1/4, 1/3, 1/2, 3/4, 1 ]; for (var p = 0; p < ps.length; ++p) { g.addColorStop(ps[p], '#0f0'); for (var i = 0; i < 15; ++i) g.addColorStop(ps[p], '#f00'); g.addColorStop(ps[p], '#0f0'); } ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,25 == 0,255,0,255; @assert pixel 30,25 == 0,255,0,255; @assert pixel 40,25 == 0,255,0,255; @assert pixel 60,25 == 0,255,0,255; @assert pixel 80,25 == 0,255,0,255; expected: green - name: 2d.gradient.empty testing: - 2d.gradient.empty code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createLinearGradient(0, 0, 0, 50); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.gradient.object.update testing: - 2d.gradient.update code: | var g = ctx.createLinearGradient(-100, 0, 200, 0); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; g.addColorStop(0.1, '#0f0'); g.addColorStop(0.9, '#0f0'); ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.gradient.object.compare testing: - 2d.gradient.object code: | var g1 = ctx.createLinearGradient(0, 0, 100, 0); var g2 = ctx.createLinearGradient(0, 0, 100, 0); @assert g1 !== g2; ctx.fillStyle = g1; @assert ctx.fillStyle === g1; - name: 2d.gradient.object.crosscanvas code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 100, 0); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.gradient.object.invalidoffset testing: - 2d.gradient.invalidoffset #mozilla: { bug: TODO } code: | var g = ctx.createLinearGradient(0, 0, 100, 0); @assert throws INDEX_SIZE_ERR g.addColorStop(-1, '#000'); @assert throws INDEX_SIZE_ERR g.addColorStop(2, '#000'); @assert throws NOT_SUPPORTED_ERR g.addColorStop(Infinity, '#000'); @moz-todo @assert throws NOT_SUPPORTED_ERR g.addColorStop(-Infinity, '#000'); @moz-todo @assert throws NOT_SUPPORTED_ERR g.addColorStop(NaN, '#000'); @moz-todo - name: 2d.gradient.object.invalidcolour testing: - 2d.gradient.invalidcolour code: | var g = ctx.createLinearGradient(0, 0, 100, 0); @assert throws SYNTAX_ERR g.addColorStop(0, ""); @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined'); - name: 2d.gradient.radial.negative testing: - 2d.gradient.radial.negative #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1); @moz-todo - name: 2d.gradient.radial.invalid #mozilla: { bug: TODO } code: | @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(Infinity, 0, 1, 0, 0, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, Infinity, 1, 0, 0, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, Infinity, 0, 0, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, 1, Infinity, 0, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, 1, 0, Infinity, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, 1, 0, 0, Infinity); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, -Infinity, 0, 0, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.createRadialGradient(0, 0, NaN, 0, 0, 1); @moz-todo - name: 2d.gradient.radial.inside1 testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(50, 25, 100, 50, 25, 200); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.inside2 testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100); g.addColorStop(0, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.inside3 testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100); g.addColorStop(0, '#f00'); g.addColorStop(0.993, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.outside1 testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(200, 25, 10, 200, 25, 20); g.addColorStop(0, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.outside2 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.outside3 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10); g.addColorStop(0, '#0f0'); g.addColorStop(0.001, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.touch1 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(150, 25, 50, 200, 25, 100); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.touch2 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150); g.addColorStop(0, '#f00'); g.addColorStop(0.01, '#0f0'); g.addColorStop(0.99, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.touch3 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(120, -15, 25, 140, -30, 50); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.equal testing: - 2d.gradient.radial.equal mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(50, 25, 20, 50, 25, 20); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.behind testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(120, 25, 10, 211, 25, 100); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.front testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(311, 25, 10, 210, 25, 100); g.addColorStop(0, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.bottom testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 101); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.top testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(230, 25, 100, 100, 25, 101); g.addColorStop(0, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.beside testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(0, 100, 40, 100, 100, 50); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.cylinder testing: - 2d.gradient.radial.rendering code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 100); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.shape1 testing: - 2d.gradient.radial.rendering code: | var tol = 1; // tolerance to avoid antialiasing artifacts ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.moveTo(30+tol, 40); ctx.lineTo(110, -20+tol); ctx.lineTo(110, 100-tol); ctx.fill(); var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.gradient.radial.cone.shape2 testing: - 2d.gradient.radial.rendering mozilla: { disabled } # TODO: report bug? code: | var tol = 1; // tolerance to avoid antialiasing artifacts ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4); g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(30-tol, 40); ctx.lineTo(110, -20-tol); ctx.lineTo(110, 100+tol); ctx.fill(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.basic.type testing: - 2d.pattern.return images: - green.png code: | var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); @assert Object.prototype.toString.call(pattern) === '[object CanvasPattern]'; - name: 2d.pattern.basic.image testing: - 2d.pattern.painting images: - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.basic.canvas testing: - 2d.pattern.painting code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#0f0'; ctx2.fillRect(0, 0, 100, 50); var pattern = ctx.createPattern(canvas2, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.basic.zerocanvas notes: The behaviour here is unspecified - I'll assume it's not meant to draw anything. mozilla: { disabled } # unspecified code: | var canvas2 = document.createElement('canvas'); canvas2.width = 0; canvas2.height = 0; @assert canvas2.width === 0; @assert canvas2.height === 0; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); var pattern = ctx.createPattern(canvas2, 'repeat'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.basic.nocontext testing: - 2d.pattern.painting code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var pattern = ctx.createPattern(canvas2, 'no-repeat'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.image.undefined testing: - 2d.pattern.wrongtype #mozilla: { bug: TODO } code: | @assert throws TYPE_MISMATCH_ERR ctx.createPattern(undefined, 'repeat'); @moz-todo - name: 2d.pattern.image.null testing: - 2d.pattern.wrongtype #mozilla: { bug: TODO } code: | @assert throws TYPE_MISMATCH_ERR ctx.createPattern(null, 'repeat'); @moz-todo - name: 2d.pattern.image.string testing: - 2d.pattern.wrongtype #mozilla: { bug: TODO } code: | @assert throws TYPE_MISMATCH_ERR ctx.createPattern('../images/green.png', 'repeat'); @moz-todo - name: 2d.pattern.image.incomplete testing: - 2d.pattern.incomplete #mozilla: { bug: TODO } code: | var img = new Image(); @assert img.complete === false; @moz-todo @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); @moz-todo - name: 2d.pattern.image.incomplete2 DISABLED: Depends on unspecified 'complete' behaviour testing: - 2d.pattern.incomplete code: | var img = new Image(); img.src = 'http://www.google.com/images/logo.gif'; @assert img.complete === false; // FIXME: it is not (yet) specified whether cached image loads can set 'complete' immediately @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); img.src = ""; - name: 2d.pattern.image.incomplete3 DISABLED: Depends on unspecified 'complete' behaviour testing: - 2d.pattern.incomplete images: - green.png code: | var img = document.getElementById('green.png'); img.src = ""; @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); - name: 2d.pattern.image.incomplete4 DISABLED: Depends on unspecified 'complete' behaviour testing: - 2d.pattern.incomplete images: - green.png code: | var img = document.getElementById('green.png'); img.src = '../images/red.png'; @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); - name: 2d.pattern.image.broken testing: - 2d.pattern.incomplete #mozilla: { bug: TODO } images: - broken.png code: | var img = document.getElementById('broken.png'); @assert img.complete === false; @moz-todo @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); @moz-todo - name: 2d.pattern.repeat.empty testing: - 2d.pattern.missing images: - green-1x1.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green-1x1.png'); var pattern = ctx.createPattern(img, ""); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 200, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.repeat.null testing: - 2d.pattern.missing images: - green-1x1.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green-1x1.png'); var pattern = ctx.createPattern(img, null); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.repeat.undefined testing: - 2d.pattern.unrecognised code: | @assert throws SYNTAX_ERR ctx.createPattern(canvas, undefined); - name: 2d.pattern.repeat.missing #mozilla: { bug: TODO } testing: - 2d.pattern.unrecognised code: | @assert throws SYNTAX_ERR ctx.createPattern(canvas); @moz-todo - name: 2d.pattern.repeat.unrecognised testing: - 2d.pattern.unrecognised code: | @assert throws SYNTAX_ERR ctx.createPattern(canvas, "invalid"); - name: 2d.pattern.repeat.case testing: - 2d.pattern.exact code: | @assert throws SYNTAX_ERR ctx.createPattern(canvas, "Repeat"); - name: 2d.pattern.repeat.nullsuffix testing: - 2d.pattern.exact code: | @assert throws SYNTAX_ERR ctx.createPattern(canvas, "repeat\0"); - name: 2d.pattern.modify.image1 testing: - 2d.pattern.modify images: - green.png code: | var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); deferTest(); img.onload = wrapFunction(function () { ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; }); img.src = '../images/red.png'; expected: green - name: 2d.pattern.modify.image2 testing: - 2d.pattern.modify images: - green.png code: | var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#00f'; ctx.fillRect(0, 0, 100, 50); deferTest(); img.onload = wrapFunction(function () { ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; }); img.src = '../images/red.png'; expected: green - name: 2d.pattern.modify.canvas1 testing: - 2d.pattern.modify code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#0f0'; ctx2.fillRect(0, 0, 100, 50); var pattern = ctx.createPattern(canvas2, 'no-repeat'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.modify.canvas2 testing: - 2d.pattern.modify code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#0f0'; ctx2.fillRect(0, 0, 100, 50); var pattern = ctx.createPattern(canvas2, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.crosscanvas code: | images: - green.png code: | var img = document.getElementById('green.png'); var pattern = document.createElement('canvas').getContext('2d').createPattern(img, 'no-repeat'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.pattern.paint.norepeat.basic testing: - 2d.pattern.painting images: - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.norepeat.outside testing: - 2d.pattern.painting images: - red.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = pattern; ctx.fillRect(0, -50, 100, 50); ctx.fillRect(-100, 0, 100, 50); ctx.fillRect(0, 50, 100, 50); ctx.fillRect(100, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.norepeat.coord1 testing: - 2d.pattern.painting images: - green.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.translate(50, 0); ctx.fillRect(-50, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.norepeat.coord2 testing: - 2d.pattern.painting images: - green.png code: | var img = document.getElementById('green.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); ctx.fillStyle = pattern; ctx.translate(50, 0); ctx.fillRect(-50, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.coord3 testing: - 2d.pattern.painting images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red.png'); var pattern = ctx.createPattern(img, 'no-repeat'); ctx.fillStyle = pattern; ctx.translate(50, 25); ctx.fillRect(-50, -25, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 25); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeat.basic testing: - 2d.pattern.painting images: - green-16x16.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green-16x16.png'); var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeat.outside testing: - 2d.pattern.painting images: - green-16x16.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('green-16x16.png'); var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.translate(50, 25); ctx.fillRect(-50, -25, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeat.coord1 testing: - 2d.pattern.painting images: - rgrg-256x256.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('rgrg-256x256.png'); var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.translate(-128, -78); ctx.fillRect(128, 78, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeat.coord2 testing: - 2d.pattern.painting images: - ggrr-256x256.png code: | var img = document.getElementById('ggrr-256x256.png'); var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeat.coord3 testing: - 2d.pattern.painting #mozilla: { bug: TODO } images: - rgrg-256x256.png code: | var img = document.getElementById('rgrg-256x256.png'); var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); ctx.translate(-128, -78); ctx.fillRect(128, 78, 100, 50); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 98,1 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @moz-todo @assert pixel 98,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.pattern.paint.repeatx.basic testing: - 2d.pattern.painting images: - green-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 16); var img = document.getElementById('green-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-x'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeatx.outside testing: - 2d.pattern.painting #mozilla: { bug: TODO } images: - red-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-x'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 16); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @moz-todo @assert pixel 98,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.pattern.paint.repeatx.coord1 testing: - 2d.pattern.painting #mozilla: { bug: TODO } images: - red-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-x'); ctx.fillStyle = pattern; ctx.translate(0, 16); ctx.fillRect(0, -16, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 16); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 98,1 == 0,255,0,255; @moz-todo @assert pixel 1,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @moz-todo @assert pixel 98,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.pattern.paint.repeaty.basic testing: - 2d.pattern.painting images: - green-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 16, 50); var img = document.getElementById('green-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-y'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.pattern.paint.repeaty.outside testing: - 2d.pattern.painting #mozilla: { bug: TODO } images: - red-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-y'); ctx.fillStyle = pattern; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 50); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.pattern.paint.repeaty.coord1 testing: - 2d.pattern.painting #mozilla: { bug: TODO } images: - red-16x16.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var img = document.getElementById('red-16x16.png'); var pattern = ctx.createPattern(img, 'repeat-y'); ctx.fillStyle = pattern; ctx.translate(48, 0); ctx.fillRect(-48, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 50); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 50,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @moz-todo @assert pixel 50,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.line.defaults testing: - 2d.lineWidth.default - 2d.lineCap.default - 2d.lineJoin.default - 2d.miterLimit.default code: | @assert ctx.lineWidth === 1; @assert ctx.lineCap === 'butt'; @assert ctx.lineJoin === 'miter'; @assert ctx.miterLimit === 10; expected: none - name: 2d.line.invalid.lineWidth testing: - 2d.lineWidth.invalid #mozilla: { bug: TODO } code: | ctx.lineWidth = 1.5; @assert ctx.lineWidth === 1.5; ctx.lineWidth = 1.5; ctx.lineWidth = 0; @assert ctx.lineWidth === 1.5; @moz-todo ctx.lineWidth = 1.5; ctx.lineWidth = -1; @assert ctx.lineWidth === 1.5; @moz-todo ctx.lineWidth = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.lineWidth = Infinity; @moz-todo @assert ctx.lineWidth === 1.5; ctx.lineWidth = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.lineWidth = -Infinity; @moz-todo @assert ctx.lineWidth === 1.5; ctx.lineWidth = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.lineWidth = NaN; @moz-todo @assert ctx.lineWidth === 1.5; expected: none - name: 2d.line.invalid.lineCap testing: - 2d.lineCap.invalid mozilla: { disabled, bug: 401788 } code: | ctx.lineCap = 'butt' @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = 'invalid'; @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = 'ROUND'; @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = 'round\0'; @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = 'round '; @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = ""; @assert ctx.lineCap === 'butt'; ctx.lineCap = 'butt'; ctx.lineCap = 'bevel'; @assert ctx.lineCap === 'butt'; expected: none - name: 2d.line.invalid.lineJoin mozilla: { disabled, bug: 401788 } testing: - 2d.lineJoin.invalid code: | ctx.lineJoin = 'bevel' @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = 'invalid'; @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = 'ROUND'; @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = 'round\0'; @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = 'round '; @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = ""; @assert ctx.lineJoin === 'bevel'; ctx.lineJoin = 'bevel'; ctx.lineJoin = 'butt'; @assert ctx.lineJoin === 'bevel'; expected: none - name: 2d.line.invalid.miterLimit testing: - 2d.miterLimit.invalid #mozilla: { bug: TODO } code: | ctx.miterLimit = 1.5; @assert ctx.miterLimit === 1.5; ctx.miterLimit = 1.5; ctx.miterLimit = 0; @assert ctx.miterLimit === 1.5; @moz-todo ctx.miterLimit = 1.5; ctx.miterLimit = -1; @assert ctx.miterLimit === 1.5; @moz-todo ctx.miterLimit = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.miterLimit = Infinity; @moz-todo @assert ctx.miterLimit === 1.5; ctx.miterLimit = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.miterLimit = -Infinity; @moz-todo @assert ctx.miterLimit === 1.5; ctx.miterLimit = 1.5; @assert throws NOT_SUPPORTED_ERR ctx.miterLimit = NaN; @moz-todo @assert ctx.miterLimit === 1.5; expected: none - name: 2d.line.lineWidth.basic testing: - 2d.lineWidth code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 20; // Draw a green line over a red box, to check the line is not too small ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(15, 15, 20, 20); ctx.beginPath(); ctx.moveTo(25, 15); ctx.lineTo(25, 35); ctx.stroke(); // Draw a green box over a red line, to check the line is not too large ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(75, 15); ctx.lineTo(75, 35); ctx.stroke(); ctx.fillRect(65, 15, 20, 20); @assert pixel 14,25 == 0,255,0,255; @assert pixel 15,25 == 0,255,0,255; @assert pixel 16,25 == 0,255,0,255; @assert pixel 25,25 == 0,255,0,255; @assert pixel 34,25 == 0,255,0,255; @assert pixel 35,25 == 0,255,0,255; @assert pixel 36,25 == 0,255,0,255; @assert pixel 64,25 == 0,255,0,255; @assert pixel 65,25 == 0,255,0,255; @assert pixel 66,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; @assert pixel 84,25 == 0,255,0,255; @assert pixel 85,25 == 0,255,0,255; @assert pixel 86,25 == 0,255,0,255; expected: green - name: 2d.line.lineWidth.transformed testing: - 2d.lineWidth code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 4; // Draw a green line over a red box, to check the line is not too small ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(15, 15, 20, 20); ctx.save(); ctx.scale(5, 1); ctx.beginPath(); ctx.moveTo(5, 15); ctx.lineTo(5, 35); ctx.stroke(); ctx.restore(); // Draw a green box over a red line, to check the line is not too large ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.save(); ctx.scale(-5, 1); ctx.beginPath(); ctx.moveTo(-15, 15); ctx.lineTo(-15, 35); ctx.stroke(); ctx.restore(); ctx.fillRect(65, 15, 20, 20); @assert pixel 14,25 == 0,255,0,255; @assert pixel 15,25 == 0,255,0,255; @assert pixel 16,25 == 0,255,0,255; @assert pixel 25,25 == 0,255,0,255; @assert pixel 34,25 == 0,255,0,255; @assert pixel 35,25 == 0,255,0,255; @assert pixel 36,25 == 0,255,0,255; @assert pixel 64,25 == 0,255,0,255; @assert pixel 65,25 == 0,255,0,255; @assert pixel 66,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; @assert pixel 84,25 == 0,255,0,255; @assert pixel 85,25 == 0,255,0,255; @assert pixel 86,25 == 0,255,0,255; expected: green - name: 2d.line.lineCap.butt testing: - 2d.lineCap.butt code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineCap = 'butt'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(15, 15, 20, 20); ctx.beginPath(); ctx.moveTo(25, 15); ctx.lineTo(25, 35); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(75, 15); ctx.lineTo(75, 35); ctx.stroke(); ctx.fillRect(65, 15, 20, 20); @assert pixel 25,14 == 0,255,0,255; @assert pixel 25,15 == 0,255,0,255; @assert pixel 25,16 == 0,255,0,255; @assert pixel 25,34 == 0,255,0,255; @assert pixel 25,35 == 0,255,0,255; @assert pixel 25,36 == 0,255,0,255; @assert pixel 75,14 == 0,255,0,255; @assert pixel 75,15 == 0,255,0,255; @assert pixel 75,16 == 0,255,0,255; @assert pixel 75,34 == 0,255,0,255; @assert pixel 75,35 == 0,255,0,255; @assert pixel 75,36 == 0,255,0,255; expected: green - name: 2d.line.lineCap.round testing: - 2d.lineCap.round code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var tol = 1; // tolerance to avoid antialiasing artifacts ctx.lineCap = 'round'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(35-tol, 15); ctx.arc(25, 15, 10-tol, 0, Math.PI, true); ctx.arc(25, 35, 10-tol, Math.PI, 0, true); ctx.fill(); ctx.beginPath(); ctx.moveTo(25, 15); ctx.lineTo(25, 35); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(75, 15); ctx.lineTo(75, 35); ctx.stroke(); ctx.beginPath(); ctx.moveTo(85+tol, 15); ctx.arc(75, 15, 10+tol, 0, Math.PI, true); ctx.arc(75, 35, 10+tol, Math.PI, 0, true); ctx.fill(); @assert pixel 17,6 == 0,255,0,255; @assert pixel 25,6 == 0,255,0,255; @assert pixel 32,6 == 0,255,0,255; @assert pixel 17,43 == 0,255,0,255; @assert pixel 25,43 == 0,255,0,255; @assert pixel 32,43 == 0,255,0,255; @assert pixel 67,6 == 0,255,0,255; @assert pixel 75,6 == 0,255,0,255; @assert pixel 82,6 == 0,255,0,255; @assert pixel 67,43 == 0,255,0,255; @assert pixel 75,43 == 0,255,0,255; @assert pixel 82,43 == 0,255,0,255; expected: green - name: 2d.line.lineCap.square testing: - 2d.lineCap.square code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineCap = 'square'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(15, 5, 20, 40); ctx.beginPath(); ctx.moveTo(25, 15); ctx.lineTo(25, 35); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(75, 15); ctx.lineTo(75, 35); ctx.stroke(); ctx.fillRect(65, 5, 20, 40); @assert pixel 25,4 == 0,255,0,255; @assert pixel 25,5 == 0,255,0,255; @assert pixel 25,6 == 0,255,0,255; @assert pixel 25,44 == 0,255,0,255; @assert pixel 25,45 == 0,255,0,255; @assert pixel 25,46 == 0,255,0,255; @assert pixel 75,4 == 0,255,0,255; @assert pixel 75,5 == 0,255,0,255; @assert pixel 75,6 == 0,255,0,255; @assert pixel 75,44 == 0,255,0,255; @assert pixel 75,45 == 0,255,0,255; @assert pixel 75,46 == 0,255,0,255; expected: green - name: 2d.line.lineJoin.bevel testing: - 2d.lineJoin.bevel code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var tol = 1; // tolerance to avoid antialiasing artifacts ctx.lineJoin = 'bevel'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(10, 10, 20, 20); ctx.fillRect(20, 20, 20, 20); ctx.beginPath(); ctx.moveTo(30, 20); ctx.lineTo(40-tol, 20); ctx.lineTo(30, 10+tol); ctx.fill(); ctx.beginPath(); ctx.moveTo(10, 20); ctx.lineTo(30, 20); ctx.lineTo(30, 40); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(60, 20); ctx.lineTo(80, 20); ctx.lineTo(80, 40); ctx.stroke(); ctx.fillRect(60, 10, 20, 20); ctx.fillRect(70, 20, 20, 20); ctx.beginPath(); ctx.moveTo(80, 20); ctx.lineTo(90+tol, 20); ctx.lineTo(80, 10-tol); ctx.fill(); @assert pixel 34,16 == 0,255,0,255; @assert pixel 34,15 == 0,255,0,255; @assert pixel 35,15 == 0,255,0,255; @assert pixel 36,15 == 0,255,0,255; @assert pixel 36,14 == 0,255,0,255; @assert pixel 84,16 == 0,255,0,255; @assert pixel 84,15 == 0,255,0,255; @assert pixel 85,15 == 0,255,0,255; @assert pixel 86,15 == 0,255,0,255; @assert pixel 86,14 == 0,255,0,255; expected: green - name: 2d.line.lineJoin.round testing: - 2d.lineJoin.round code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); var tol = 1; // tolerance to avoid antialiasing artifacts ctx.lineJoin = 'round'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(10, 10, 20, 20); ctx.fillRect(20, 20, 20, 20); ctx.beginPath(); ctx.moveTo(30, 20); ctx.arc(30, 20, 10-tol, 0, 2*Math.PI, true); ctx.fill(); ctx.beginPath(); ctx.moveTo(10, 20); ctx.lineTo(30, 20); ctx.lineTo(30, 40); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(60, 20); ctx.lineTo(80, 20); ctx.lineTo(80, 40); ctx.stroke(); ctx.fillRect(60, 10, 20, 20); ctx.fillRect(70, 20, 20, 20); ctx.beginPath(); ctx.moveTo(80, 20); ctx.arc(80, 20, 10+tol, 0, 2*Math.PI, true); ctx.fill(); @assert pixel 36,14 == 0,255,0,255; @assert pixel 36,13 == 0,255,0,255; @assert pixel 37,13 == 0,255,0,255; @assert pixel 38,13 == 0,255,0,255; @assert pixel 38,12 == 0,255,0,255; @assert pixel 86,14 == 0,255,0,255; @assert pixel 86,13 == 0,255,0,255; @assert pixel 87,13 == 0,255,0,255; @assert pixel 88,13 == 0,255,0,255; @assert pixel 88,12 == 0,255,0,255; expected: green - name: 2d.line.lineJoin.miter testing: - 2d.lineJoin.miter code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'miter'; ctx.lineWidth = 20; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(10, 10, 30, 20); ctx.fillRect(20, 10, 20, 30); ctx.beginPath(); ctx.moveTo(10, 20); ctx.lineTo(30, 20); ctx.lineTo(30, 40); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(60, 20); ctx.lineTo(80, 20); ctx.lineTo(80, 40); ctx.stroke(); ctx.fillRect(60, 10, 30, 20); ctx.fillRect(70, 10, 20, 30); @assert pixel 38,12 == 0,255,0,255; @assert pixel 39,11 == 0,255,0,255; @assert pixel 40,10 == 0,255,0,255; @assert pixel 41,9 == 0,255,0,255; @assert pixel 42,8 == 0,255,0,255; @assert pixel 88,12 == 0,255,0,255; @assert pixel 89,11 == 0,255,0,255; @assert pixel 90,10 == 0,255,0,255; @assert pixel 91,9 == 0,255,0,255; @assert pixel 92,8 == 0,255,0,255; expected: green - name: 2d.line.join.open code: | ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'miter'; ctx.lineWidth = 200; ctx.beginPath(); ctx.moveTo(100, 50); ctx.lineTo(100, 1000); ctx.lineTo(1000, 1000); ctx.lineTo(1000, 50); ctx.lineTo(100, 50); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.join.closed code: | ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'miter'; ctx.lineWidth = 200; ctx.beginPath(); ctx.moveTo(100, 50); ctx.lineTo(100, 1000); ctx.lineTo(1000, 1000); ctx.lineTo(1000, 50); ctx.closePath(); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.join.zeroline.corner code: | ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'miter'; ctx.lineWidth = 200; ctx.beginPath(); ctx.moveTo(1000, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 1000); ctx.closePath(); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.join.zeroline.join code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 150; ctx.lineJoin = 'round'; ctx.beginPath(); ctx.moveTo(50, 25); ctx.lineTo(50, 25); ctx.lineTo(50, 25); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.join.parallel code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 300; ctx.lineJoin = 'round'; ctx.beginPath(); ctx.moveTo(-100, 25); ctx.lineTo(0, 25); ctx.lineTo(-100, 25); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.cap.open code: | ctx.fillStyle = '#f00'; ctx.strokeStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'bevel'; ctx.lineCap = 'square'; ctx.lineWidth = 400; ctx.beginPath(); ctx.moveTo(200, 200); ctx.lineTo(200, 1000); ctx.lineTo(1000, 1000); ctx.lineTo(1000, 200); ctx.lineTo(200, 200); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.cap.closed code: | ctx.fillStyle = '#0f0'; ctx.strokeStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.lineJoin = 'bevel'; ctx.lineCap = 'square'; ctx.lineWidth = 400; ctx.beginPath(); ctx.moveTo(200, 200); ctx.lineTo(200, 1000); ctx.lineTo(1000, 1000); ctx.lineTo(1000, 200); ctx.closePath(); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.cap.zeroline.round #mozilla: { bug: TODO } code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 150; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(50, 25); ctx.lineTo(50, 25); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 48,1 == 0,255,0,255; @moz-todo @assert pixel 48,48 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.line.cap.zeroline.square code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 100; ctx.lineCap = 'square'; ctx.beginPath(); ctx.moveTo(50, 25); ctx.lineTo(50, 25); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.cap.zerobezier.round code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 150; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(50, 25); ctx.bezierCurveTo(50, 25, 50, 25, 50, 25); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.miter.exceeded code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 400; ctx.lineJoin = 'miter'; ctx.strokeStyle = '#f00'; ctx.miterLimit = 1.414; ctx.beginPath(); ctx.moveTo(200, 1000); ctx.lineTo(200, 200); ctx.lineTo(1000, 201); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.miter.rightangle mozilla: { bug: 401791 } code: | // In FF3, this works if you do something like ctx.rotate(0.001); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 400; ctx.lineJoin = 'miter'; ctx.strokeStyle = '#f00'; ctx.miterLimit = 1.414; ctx.beginPath(); ctx.moveTo(200, 1000); ctx.lineTo(200, 200); ctx.lineTo(1000, 200); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 48,1 == 0,255,0,255; @moz-todo @assert pixel 48,48 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.line.miter.lineedge mozilla: { bug: 401791 } code: | // In Safari/FF3, this works if you do something like ctx.rotate(0.001); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 200; ctx.lineJoin = 'miter'; ctx.strokeStyle = '#f00'; ctx.miterLimit = 1.414; ctx.beginPath(); ctx.strokeRect(100, 25, 200, 0); @assert pixel 1,1 == 0,255,0,255; @moz-todo @assert pixel 48,1 == 0,255,0,255; @moz-todo @assert pixel 48,48 == 0,255,0,255; @moz-todo @assert pixel 1,48 == 0,255,0,255; @moz-todo expected: green - name: 2d.line.miter.within code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 400; ctx.lineJoin = 'miter'; ctx.strokeStyle = '#0f0'; ctx.miterLimit = 1.416; ctx.beginPath(); ctx.moveTo(200, 1000); ctx.lineTo(200, 200); ctx.lineTo(1000, 201); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.cross code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 200; ctx.lineJoin = 'bevel'; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.moveTo(110, 50); ctx.lineTo(110, 60); ctx.lineTo(100, 60); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; expected: green - name: 2d.line.union code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 100; ctx.lineCap = 'round'; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(0, 24); ctx.lineTo(100, 25); ctx.lineTo(0, 26); ctx.closePath(); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 25,1 == 0,255,0,255; @assert pixel 48,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 25,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; expected: green - name: 2d.clearRect.negative mozilla: { disabled } # TODO: report bug? testing: - 2d.rect.negative code: | @assert throws INDEX_SIZE_ERR ctx.clearRect(0, 0, -1, 1); @assert throws INDEX_SIZE_ERR ctx.clearRect(0, 0, 1, -1); - name: 2d.clearRect.basic testing: - 2d.clearRect background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.clearRect(0, 0, 100, 50); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.clearRect.path testing: - 2d.clearRect background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.rect(0, 0, 100, 50); ctx.clearRect(0, 0, 16, 16); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.clearRect.zero testing: - 2d.clearRect background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.clearRect(0, 0, 100, 0); ctx.clearRect(0, 0, 0, 50); ctx.clearRect(0, 0, 0, 0); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.clearRect.transform testing: - 2d.clearRect background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(10, 10); ctx.translate(0, 5); ctx.clearRect(0, -5, 10, 5); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.clearRect.globalalpha testing: - 2d.clearRect background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.globalAlpha = 0.1; ctx.clearRect(0, 0, 100, 50); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.clearRect.globalcomposite testing: - 2d.clearRect background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = 'destination-atop'; ctx.clearRect(0, 0, 100, 50); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.clearRect.clip testing: - 2d.clearRect background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(0, 0, 16, 16); ctx.clip(); ctx.clearRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 16); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.clearRect.shadow testing: - 2d.clearRect background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#f00'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 50; ctx.clearRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillRect.negative testing: - 2d.rect.negative #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.fillRect(0, 0, -1, 1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.fillRect(0, 0, 1, -1); @moz-todo - name: 2d.fillRect.basic testing: - 2d.fillRect background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillRect.path testing: - 2d.fillRect background: "#f00" code: | ctx.beginPath(); ctx.rect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 16, 16); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillRect.zero testing: - 2d.fillRect background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 0); ctx.fillRect(0, 0, 0, 50); ctx.fillRect(0, 0, 0, 0); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.fillRect.transform testing: - 2d.fillRect background: "#f00" code: | ctx.scale(10, 10); ctx.translate(0, 5); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -5, 10, 5); @assert pixel 50,25 == 0,255,0,255; expected: green # don't bother testing globalalpha, globalcomposite because they're already heavily used by other test cases - name: 2d.fillRect.clip testing: - 2d.fillRect code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(0, 0, 16, 16); ctx.clip(); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 16); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.fillRect.shadow testing: - 2d.fillRect code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 50; // Shadows are optional, so just test that if they apply to fill() then they apply to fillRect() too ctx.beginPath(); ctx.rect(0, -50, 100, 50); ctx.shadowColor = '#f00'; ctx.fill(); ctx.shadowColor = '#0f0'; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.negative testing: - 2d.rect.negative #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.strokeRect(0, 0, -1, 1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.strokeRect(0, 0, 1, -1); @moz-todo - name: 2d.strokeRect.basic testing: - 2d.strokeRect background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.strokeRect(25, 24, 50, 2); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.path testing: - 2d.strokeRect background: "#f00" code: | ctx.beginPath(); ctx.rect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 5; ctx.strokeRect(0, 0, 16, 16); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.zero.1 testing: - 2d.strokeRect background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 250; ctx.strokeRect(50, 25, 0, 0); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.strokeRect.zero.2 testing: - 2d.strokeRect #mozilla: { bug: TODO } background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 250; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeRect(50, 25, 0, 0); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.strokeRect.zero.3 testing: - 2d.strokeRect background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.strokeRect(0, 25, 100, 0); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.zero.4 testing: - 2d.strokeRect background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 250; ctx.lineCap = 'round'; ctx.strokeRect(100, 25, 100, 0); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.strokeRect.zero.5 notes: This doesn't really follow the spec - it's assuming the line is closed. See message. testing: - 2d.strokeRect background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 250; ctx.lineJoin = 'round'; ctx.strokeRect(100, 25, 100, 0); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.transform testing: - 2d.strokeRect background: "#f00" code: | ctx.scale(10, 10); ctx.translate(0, 5); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 5; ctx.strokeRect(2.5, -2.6, 5, 0.2); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.globalalpha testing: - 2d.strokeRect background: "#0f0" code: | ctx.globalAlpha = 0; ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.strokeRect(25, 24, 50, 2); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.strokeRect.globalcomposite testing: - 2d.strokeRect background: "#0f0" code: | ctx.globalCompositeOperation = 'source-in'; ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.strokeRect(25, 24, 50, 2); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.strokeRect.clip testing: - 2d.strokeRect code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(0, 0, 16, 16); ctx.clip(); ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.strokeRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 16); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.strokeRect.shadow testing: - 2d.strokeRect code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 50; // Shadows are optional, so just test that if they apply to fill() then they apply to strokeRect() too ctx.beginPath(); ctx.rect(0, -50, 100, 50); ctx.shadowColor = '#f00'; ctx.fill(); ctx.shadowColor = '#0f0'; ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.strokeRect(0, -75, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.initial testing: - 2d.path.initial #mozilla: { bug: TODO } background: "#0f0" code: | ctx.lineTo(0, 0); ctx.lineTo(100, 0); ctx.lineTo(100, 50); ctx.lineTo(0, 50); ctx.closePath(); ctx.fillStyle = '#f00'; ctx.fill(); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.path.beginPath testing: - 2d.path.beginPath background: "#0f0" code: | ctx.rect(0, 0, 100, 50); ctx.beginPath(); ctx.fillStyle = '#f00'; ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.moveTo.basic testing: - 2d.path.moveTo background: "#f00" code: | ctx.rect(0, 0, 10, 50); ctx.moveTo(100, 0); ctx.lineTo(10, 0); ctx.lineTo(10, 50); ctx.lineTo(100, 50); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 90,25 == 0,255,0,255; expected: green - name: 2d.path.moveTo.newsubpath testing: - 2d.path.moveTo background: "#0f0" code: | ctx.beginPath(); ctx.moveTo(0, 0); ctx.moveTo(100, 0); ctx.moveTo(100, 50); ctx.moveTo(0, 50); ctx.fillStyle = '#f00'; ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.moveTo.multiple testing: - 2d.path.moveTo background: "#f00" code: | ctx.moveTo(0, 25); ctx.moveTo(100, 25); ctx.moveTo(0, 25); ctx.lineTo(100, 25); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.closePath.empty testing: - 2d.path.closePath.empty background: "#0f0" code: | ctx.closePath(); ctx.fillStyle = '#f00'; ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.closePath.newline testing: - 2d.path.closePath.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.moveTo(-100, 25); ctx.lineTo(-100, -100); ctx.lineTo(200, -100); ctx.lineTo(200, 25); ctx.closePath(); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.closePath.nextpoint testing: - 2d.path.closePath.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.moveTo(-100, 25); ctx.lineTo(-100, -1000); ctx.closePath(); ctx.lineTo(1000, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.lineTo.emptysubpath testing: - 2d.path.lineTo.empty #mozilla: { bug: TODO } background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.beginPath(); ctx.lineTo(0, 25); ctx.lineTo(100, 25); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.path.lineTo.basic testing: - 2d.path.lineTo.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.lineTo(100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.lineTo.nextpoint testing: - 2d.path.lineTo.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(-100, -100); ctx.lineTo(0, 25); ctx.lineTo(100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.quadraticCurveTo.emptysubpath testing: - 2d.path.quadratic.empty #mozilla: { bug: TODO } background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.beginPath(); ctx.quadraticCurveTo(0, 25, 0, 25); ctx.quadraticCurveTo(100, 25, 100, 25); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.path.quadraticCurveTo.basic testing: - 2d.path.quadratic.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.quadraticCurveTo(100, 25, 100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.quadraticCurveTo.shape testing: - 2d.path.quadratic.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 55; ctx.beginPath(); ctx.moveTo(-1000, 1050); ctx.quadraticCurveTo(0, -1000, 1200, 1050); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.quadraticCurveTo.scaled testing: - 2d.path.quadratic.nonempty background: "#f00" code: | ctx.scale(1000, 1000); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 0.055; ctx.beginPath(); ctx.moveTo(-1, 1.05); ctx.quadraticCurveTo(0, -1, 1.2, 1.05); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.bezierCurveTo.emptysubpath testing: - 2d.path.bezier.empty #mozilla: { bug: TODO } background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.beginPath(); ctx.bezierCurveTo(0, 25, 0, 25, 0, 25); ctx.bezierCurveTo(100, 25, 100, 25, 100, 25); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.path.bezierCurveTo.basic testing: - 2d.path.bezier.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.bezierCurveTo(100, 25, 100, 25, 100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.bezierCurveTo.shape testing: - 2d.path.bezier.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 55; ctx.beginPath(); ctx.moveTo(-2000, 3100); ctx.bezierCurveTo(-2000, -1000, 2100, -1000, 2100, 3100); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.bezierCurveTo.scaled testing: - 2d.path.bezier.nonempty background: "#f00" code: | ctx.scale(1000, 1000); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 0.055; ctx.beginPath(); ctx.moveTo(-2, 3.1); ctx.bezierCurveTo(-2, -1, 2.1, -1, 2.1, 3.1); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.arcTo.emptysubpath testing: - 2d.path.arcTo.empty background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.beginPath(); ctx.arcTo(0, 25, 0, 25, 0.1); ctx.arcTo(100, 25, 100, 25, 0.1); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arcTo.coincide.1 notes: &arcto Disagrees with spec - see suggestion background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.arcTo(0, 25, 50, 1000, 1); ctx.lineTo(100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.coincide.2 notes: *arcto background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.arcTo(100, 25, 100, 25, 1); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.collinear.1 notes: *arcto background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.arcTo(100, 25, 200, 25, 1); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.collinear.2 notes: *arcto background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(100, 25); ctx.arcTo(200, 25, 150, 25, 1); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.collinear.3 notes: *arcto background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(150, 25); ctx.arcTo(200, 25, 100, 25, 1); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.shape.curve1 testing: - 2d.path.arcTo.nonempty code: | var tol = 1; // tolerance to avoid antialiasing artifacts ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(10, 25); ctx.arcTo(75, 25, 75, 60, 20); ctx.stroke(); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.rect(10, 20, 45, 10); ctx.moveTo(80, 45); ctx.arc(55, 45, 25+tol, 0, -Math.PI/2, true); ctx.arc(55, 45, 15-tol, -Math.PI/2, 0, false); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 55,19 == 0,255,0,255; @assert pixel 55,20 == 0,255,0,255; @assert pixel 55,21 == 0,255,0,255; @assert pixel 64,22 == 0,255,0,255; @assert pixel 65,21 == 0,255,0,255; @assert pixel 72,28 == 0,255,0,255; @assert pixel 73,27 == 0,255,0,255; @assert pixel 78,36 == 0,255,0,255; @assert pixel 79,35 == 0,255,0,255; @assert pixel 80,44 == 0,255,0,255; @assert pixel 80,45 == 0,255,0,255; @assert pixel 80,46 == 0,255,0,255; expected: green - name: 2d.path.arcTo.shape.curve2 testing: - 2d.path.arcTo.nonempty code: | var tol = 1; // tolerance to avoid antialiasing artifacts ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.rect(10, 20, 45, 10); ctx.moveTo(80, 45); ctx.arc(55, 45, 25-tol, 0, -Math.PI/2, true); ctx.arc(55, 45, 15+tol, -Math.PI/2, 0, false); ctx.fill(); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(10, 25); ctx.arcTo(75, 25, 75, 60, 20); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 55,19 == 0,255,0,255; @assert pixel 55,20 == 0,255,0,255; @assert pixel 55,21 == 0,255,0,255; @assert pixel 64,22 == 0,255,0,255; @assert pixel 65,21 == 0,255,0,255; @assert pixel 72,28 == 0,255,0,255; @assert pixel 73,27 == 0,255,0,255; @assert pixel 78,36 == 0,255,0,255; @assert pixel 79,35 == 0,255,0,255; @assert pixel 80,44 == 0,255,0,255; @assert pixel 80,45 == 0,255,0,255; @assert pixel 80,46 == 0,255,0,255; expected: green - name: 2d.path.arcTo.shape.start testing: - 2d.path.arcTo.nonempty background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(0, 25); ctx.arcTo(200, 25, 200, 50, 10); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arcTo.shape.end testing: - 2d.path.arcTo.nonempty background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.beginPath(); ctx.moveTo(-100, -100); ctx.arcTo(-100, 25, 200, 25, 10); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arcTo.negative testing: - 2d.path.arcTo.nonpositive code: | @assert throws INDEX_SIZE_ERR ctx.arcTo(0, 0, 0, 0, -1); - name: 2d.path.arcTo.zero notes: &arcto I think the spec should change for this - see suggestion testing: - 2d.path.arcTo.nonpositive code: | @assert throws INDEX_SIZE_ERR ctx.arcTo(0, 0, 0, 0, 0); - name: 2d.path.arc.empty testing: - 2d.path.arc.nonempty background: "#0f0" code: | ctx.lineWidth = 50; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.arc(200, 25, 5, 0, 2*Math.PI, true); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.nonempty testing: - 2d.path.arc.nonempty background: "#f00" code: | ctx.lineWidth = 50; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(0, 25); ctx.arc(200, 25, 5, 0, 2*Math.PI, true); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arc.end testing: - 2d.path.arc.draw background: "#f00" code: | ctx.lineWidth = 50; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(-100, 0); ctx.arc(-100, 0, 25, -Math.PI/2, Math.PI/2, true); ctx.lineTo(100, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arc.angle.1 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.moveTo(100, 0); ctx.arc(100, 0, 150, Math.PI/2, -Math.PI, true); ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.angle.2 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.moveTo(100, 0); ctx.arc(100, 0, 150, -3*Math.PI/2, -Math.PI, true); ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.angle.3 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.moveTo(100, 0); ctx.arc(100, 0, 150, (512+1/2)*Math.PI, (1024-1)*Math.PI, true); ctx.fill(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.angle.4 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(100, 0); ctx.arc(100, 0, 150, (512+1/2)*Math.PI, (1024-1)*Math.PI, false); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arc.zero.1 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 0, true); ctx.stroke(); @assert pixel 50,20 == 0,0,0,0; expected: green - name: 2d.path.arc.zero.2 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 0, false); ctx.stroke(); @assert pixel 50,20 == 0,0,0,0; expected: green - name: 2d.path.arc.zero.3 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, true); ctx.stroke(); @assert pixel 50,20 == 0,0,0,0; expected: green - name: 2d.path.arc.zero.4 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, false); ctx.stroke(); @assert pixel 50,20 == 0,255,0,255; expected: green - name: 2d.path.arc.zero.5 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, true); ctx.stroke(); @assert pixel 50,20 == 0,255,0,255; expected: green - name: 2d.path.arc.zero.6 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.beginPath(); ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, false); ctx.stroke(); @assert pixel 50,20 == 0,255,0,255; expected: green - name: 2d.path.arc.shape.1 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.lineWidth = 50; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.arc(50, 50, 50, 0, Math.PI, false); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; @assert pixel 1,1 == 0,0,0,0; @assert pixel 98,1 == 0,0,0,0; @assert pixel 1,48 == 0,0,0,0; @assert pixel 20,48 == 0,0,0,0; @assert pixel 98,48 == 0,0,0,0; expected: green - name: 2d.path.arc.shape.2 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.lineWidth = 100; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.arc(50, 50, 50, 0, Math.PI, true); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 20,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.arc.shape.3 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.lineWidth = 100; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.arc(0, 50, 50, 0, -Math.PI/2, false); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.shape.4 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.lineWidth = 150; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.arc(-50, 50, 100, 0, -Math.PI/2, true); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.arc.shape.5 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.lineWidth = 200; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.arc(300, 0, 100, 0, 5*Math.PI, false); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.selfintersect.1 testing: - 2d.path.arc.draw background: "#0f0" code: | ctx.lineWidth = 200; ctx.strokeStyle = '#f00'; ctx.beginPath(); ctx.arc(100, 50, 25, 0, -Math.PI/2, true); ctx.stroke(); ctx.beginPath(); ctx.arc(0, 0, 25, 0, -Math.PI/2, true); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.arc.selfintersect.2 testing: - 2d.path.arc.draw background: "#f00" code: | ctx.lineWidth = 180; ctx.strokeStyle = '#0f0'; ctx.beginPath(); ctx.arc(-50, 50, 25, 0, -Math.PI/2, true); ctx.stroke(); ctx.beginPath(); ctx.arc(100, 0, 25, 0, -Math.PI/2, true); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @assert pixel 90,10 == 0,255,0,255; @assert pixel 97,1 == 0,255,0,255; @assert pixel 97,2 == 0,255,0,255; @assert pixel 97,3 == 0,255,0,255; @assert pixel 2,48 == 0,255,0,255; expected: green - name: 2d.path.arc.negative testing: - 2d.path.arc.nonpositive #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.arc(0, 0, -1, 0, 0, true); @moz-todo - name: 2d.path.arc.zero testing: - 2d.path.arc.nonpositive #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.arc(0, 0, 0, 0, 0, true); @moz-todo - name: 2d.path.arc.scale desc: Scaled arcs are the right size testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.scale(2, 0.5); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.arc(25, 50, 56, 0, 2*Math.PI, false); ctx.fill(); ctx.fillStyle = '#f00'; ctx.beginPath(); ctx.moveTo(-25, 50); ctx.arc(-25, 50, 24, 0, 2*Math.PI, false); ctx.moveTo(75, 50); ctx.arc(75, 50, 24, 0, 2*Math.PI, false); ctx.moveTo(25, -25); ctx.arc(25, -25, 24, 0, 2*Math.PI, false); ctx.moveTo(25, 125); ctx.arc(25, 125, 24, 0, 2*Math.PI, false); ctx.fill(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.rect.basic testing: - 2d.path.rect.subpath background: "#f00" code: | ctx.fillStyle = '#0f0'; ctx.rect(0, 0, 100, 50); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.newsubpath testing: - 2d.path.rect.subpath background: "#0f0" code: | ctx.beginPath(); ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.moveTo(-100, 25); ctx.lineTo(-50, 25); ctx.rect(200, 25, 1, 1); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.rect.closed testing: - 2d.path.rect.closed background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 200; ctx.lineJoin = 'miter'; ctx.rect(100, 50, 100, 100); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.end.1 testing: - 2d.path.rect.newsubpath background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.rect(200, 100, 400, 1000); ctx.lineTo(-2000, -1000); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.end.2 testing: - 2d.path.rect.newsubpath background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 450; ctx.lineCap = 'round'; ctx.lineJoin = 'bevel'; ctx.rect(150, 150, 2000, 2000); ctx.lineTo(160, 160); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 98,1 == 0,255,0,255; @assert pixel 1,48 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.path.rect.zero.1 testing: - 2d.path.rect.subpath background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.beginPath(); ctx.rect(0, 50, 100, 0); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.zero.2 testing: - 2d.path.rect.subpath background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 100; ctx.beginPath(); ctx.rect(50, -100, 0, 250); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.zero.3 testing: - 2d.path.rect.subpath background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 100; ctx.beginPath(); ctx.rect(50, 25, 0, 0); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.rect.zero.4 testing: - 2d.path.rect.subpath background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 50; ctx.rect(100, 25, 0, 0); ctx.lineTo(0, 25); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.rect.zero.5 testing: - 2d.path.rect.subpath background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineWidth = 50; ctx.moveTo(0, 0); ctx.rect(100, 25, 0, 0); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; expected: green - name: 2d.path.rect.zero.6 testing: - 2d.path.rect.subpath #mozilla: { bug: TODO } background: "#0f0" code: | ctx.strokeStyle = '#f00'; ctx.lineJoin = 'miter'; ctx.miterLimit = 1.5; ctx.lineWidth = 200; ctx.beginPath(); ctx.rect(100, 25, 1000, 0); ctx.stroke(); @assert pixel 50,25 == 0,0,0,0; @moz-todo expected: green - name: 2d.path.rect.negative testing: - 2d.path.rect.negative #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.rect(0, 0, -1, 10); @moz-todo @assert throws INDEX_SIZE_ERR ctx.rect(0, 0, 10, -1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.rect(0, 0, -1, -1); @moz-todo - name: 2d.path.rect.selfintersect #mozilla: { bug: TODO } background: "#f00" code: | ctx.strokeStyle = '#0f0'; ctx.lineWidth = 90; ctx.beginPath(); ctx.rect(45, 20, 10, 10); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; @moz-todo expected: green - name: 2d.path.fill.winding.add testing: - 2d.path.fill.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.lineTo(-10, -10); ctx.lineTo(0, 0); ctx.lineTo(100, 0); ctx.lineTo(100, 50); ctx.lineTo(0, 50); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.fill.winding.subtract.1 testing: - 2d.path.fill.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.lineTo(-10, -10); ctx.lineTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.fill.winding.subtract.2 testing: - 2d.path.fill.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.moveTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.fill.winding.subtract.3 testing: - 2d.path.fill.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.lineTo(-10, -10); ctx.lineTo(-20, -20); ctx.lineTo(120, -20); ctx.lineTo(120, 70); ctx.lineTo(-20, 70); ctx.lineTo(-20, -20); ctx.lineTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.fill.closed.basic testing: - 2d.path.fill.closed code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.moveTo(0, 0); ctx.lineTo(100, 0); ctx.lineTo(100, 50); ctx.lineTo(0, 50); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.fill.closed.unaffected testing: - 2d.path.fill.closed code: | ctx.fillStyle = '#00f'; ctx.fillRect(0, 0, 100, 50); ctx.moveTo(0, 0); ctx.lineTo(100, 0); ctx.lineTo(100, 50); ctx.fillStyle = '#f00'; ctx.fill(); ctx.lineTo(0, 50); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 90,10 == 0,255,0,255; @assert pixel 10,40 == 0,255,0,255; expected: green - name: 2d.path.stroke.union desc: Strokes in opposite directions are unioned, not subtracted testing: - 2d.path.stroke.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#0f0'; ctx.lineWidth = 40; ctx.moveTo(0, 10); ctx.lineTo(100, 10); ctx.moveTo(100, 40); ctx.lineTo(0, 40); ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.stroke.unaffected desc: Stroking does not start a new path or subpath testing: - 2d.path.stroke.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.lineWidth = 50; ctx.moveTo(-100, 25); ctx.lineTo(-100, -100); ctx.lineTo(200, -100); ctx.lineTo(200, 25); ctx.strokeStyle = '#f00'; ctx.stroke(); ctx.closePath(); ctx.strokeStyle = '#0f0'; ctx.stroke(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.stroke.scale1 desc: Stroke line widths are scaled by the current transformation matrix testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(25, 12.5, 50, 25); ctx.save(); ctx.scale(50, 25); ctx.strokeStyle = '#0f0'; ctx.stroke(); ctx.restore(); ctx.beginPath(); ctx.rect(-25, -12.5, 150, 75); ctx.save(); ctx.scale(50, 25); ctx.strokeStyle = '#f00'; ctx.stroke(); ctx.restore(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.stroke.scale2 desc: Stroke line widths are scaled by the current transformation matrix testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(25, 12.5, 50, 25); ctx.save(); ctx.rotate(Math.PI/2); ctx.scale(25, 50); ctx.strokeStyle = '#0f0'; ctx.stroke(); ctx.restore(); ctx.beginPath(); ctx.rect(-25, -12.5, 150, 75); ctx.save(); ctx.rotate(Math.PI/2); ctx.scale(25, 50); ctx.strokeStyle = '#f00'; ctx.stroke(); ctx.restore(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.stroke.skew desc: Strokes lines are skewed by the current transformation matrix testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.save(); ctx.beginPath(); ctx.moveTo(49, -50); ctx.lineTo(201, -50); ctx.rotate(Math.PI/4); ctx.scale(1, 283); ctx.strokeStyle = '#0f0'; ctx.stroke(); ctx.restore(); ctx.save(); ctx.beginPath(); ctx.translate(-150, 0); ctx.moveTo(49, -50); ctx.lineTo(199, -50); ctx.rotate(Math.PI/4); ctx.scale(1, 142); ctx.strokeStyle = '#f00'; ctx.stroke(); ctx.restore(); ctx.save(); ctx.beginPath(); ctx.translate(-150, 0); ctx.moveTo(49, -50); ctx.lineTo(199, -50); ctx.rotate(Math.PI/4); ctx.scale(1, 142); ctx.strokeStyle = '#f00'; ctx.stroke(); ctx.restore(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.arcTo.transformation desc: arcTo joins up to the last subpath point correctly code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(0, 50); ctx.translate(100, 0); ctx.arcTo(50, 50, 50, 0, 50); ctx.lineTo(-100, 0); ctx.fill(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.arcTo.scale desc: arcTo scales the curve, not just the control points code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.moveTo(0, 50); ctx.translate(100, 0); ctx.scale(0.1, 1); ctx.arcTo(50, 50, 50, 0, 50); ctx.lineTo(-1000, 0); ctx.fill(); @assert pixel 0,0 == 0,255,0,255; @assert pixel 50,0 == 0,255,0,255; @assert pixel 99,0 == 0,255,0,255; @assert pixel 0,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 99,25 == 0,255,0,255; @assert pixel 0,49 == 0,255,0,255; @assert pixel 50,49 == 0,255,0,255; @assert pixel 99,49 == 0,255,0,255; expected: green - name: 2d.path.transformation.basic testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.translate(-100, 0); ctx.rect(100, 0, 100, 50); ctx.translate(0, -100); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.transformation.multiple testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rect(0, 0, 100, 50); ctx.fill(); ctx.translate(-100, 0); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.transformation.changing desc: Transformations are applied while building paths, not when drawing testing: - 2d.path.transformation code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.moveTo(0, 0); ctx.translate(100, 0); ctx.lineTo(0, 0); ctx.translate(0, 50); ctx.lineTo(0, 0); ctx.translate(-100, 0); ctx.lineTo(0, 0); ctx.translate(1000, 1000); ctx.rotate(Math.PI/2); ctx.scale(0.1, 0.1); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.empty testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.clip(); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.basic.1 testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(0, 0, 100, 50); ctx.clip(); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.basic.2 testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(-100, 0, 100, 50); ctx.clip(); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.intersect testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.rect(0, 0, 50, 50); ctx.clip(); ctx.beginPath(); ctx.rect(50, 0, 50, 50) ctx.clip(); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.winding.1 testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.lineTo(-10, -10); ctx.lineTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.clip(); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.winding.2 testing: - 2d.path.clip.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.beginPath(); ctx.moveTo(-10, -10); ctx.lineTo(110, -10); ctx.lineTo(110, 60); ctx.lineTo(-10, 60); ctx.lineTo(-10, -10); ctx.clip(); ctx.beginPath(); ctx.lineTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.lineTo(0, 0); ctx.clip(); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.clip.unaffected testing: - 2d.path.clip.closed code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.beginPath(); ctx.lineTo(0, 0); ctx.lineTo(0, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 0); ctx.clip(); ctx.lineTo(0, 0); ctx.fill(); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.path.isPointInPath.basic.1 testing: - 2d.path.isPointInPath code: | ctx.rect(0, 0, 20, 20); @assert ctx.isPointInPath(10, 10) === true; - name: 2d.path.isPointInPath.basic.2 testing: - 2d.path.isPointInPath code: | ctx.rect(20, 0, 20, 20); @assert ctx.isPointInPath(10, 10) === false; - name: 2d.path.isPointInPath.empty testing: - 2d.path.isPointInPath code: | @assert ctx.isPointInPath(0, 0) === false; - name: 2d.path.isPointInPath.unclosed testing: - 2d.path.isPointInPath code: | ctx.moveTo(0, 0); ctx.lineTo(20, 0); ctx.lineTo(20, 20); ctx.lineTo(0, 20); @assert ctx.isPointInPath(10, 10) === true; - name: 2d.path.isPointInPath.winding testing: - 2d.path.isPointInPath code: | ctx.moveTo(0, 0); ctx.lineTo(50, 0); ctx.lineTo(50, 50); ctx.lineTo(0, 50); ctx.lineTo(0, 0); ctx.lineTo(10, 10); ctx.lineTo(10, 40); ctx.lineTo(40, 40); ctx.lineTo(40, 10); ctx.lineTo(10, 10); @assert ctx.isPointInPath(5, 5) === true; @assert ctx.isPointInPath(25, 5) === true; @assert ctx.isPointInPath(45, 5) === true; @assert ctx.isPointInPath(5, 25) === true; @assert ctx.isPointInPath(25, 25) === false; @assert ctx.isPointInPath(45, 25) === true; @assert ctx.isPointInPath(5, 45) === true; @assert ctx.isPointInPath(25, 45) === true; @assert ctx.isPointInPath(45, 45) === true; - name: 2d.path.isPointInPath.transform.1 testing: - 2d.path.isPointInPath mozilla: { bug: 405300 } code: | ctx.translate(50, 0); ctx.rect(0, 0, 20, 20); @assert ctx.isPointInPath(-40, 10) === false; @assert ctx.isPointInPath(10, 10) === false; @moz-todo @assert ctx.isPointInPath(49, 10) === false; @assert ctx.isPointInPath(51, 10) === true; @moz-todo @assert ctx.isPointInPath(69, 10) === true; @moz-todo @assert ctx.isPointInPath(71, 10) === false; - name: 2d.path.isPointInPath.transform.2 testing: - 2d.path.isPointInPath mozilla: { bug: 405300 } code: | ctx.rect(0, 0, 20, 20); ctx.translate(50, 0); @assert ctx.isPointInPath(-40, 10) === false; @moz-todo @assert ctx.isPointInPath(10, 10) === false; @assert ctx.isPointInPath(49, 10) === false; @assert ctx.isPointInPath(51, 10) === true; @moz-todo @assert ctx.isPointInPath(69, 10) === true; @moz-todo @assert ctx.isPointInPath(71, 10) === false; - name: 2d.path.isPointInPath.transform.3 testing: - 2d.path.isPointInPath mozilla: { bug: 405300 } code: | ctx.scale(-1, 1); ctx.rect(-70, 0, 20, 20); @assert ctx.isPointInPath(-40, 10) === false; @assert ctx.isPointInPath(10, 10) === false; @assert ctx.isPointInPath(49, 10) === false; @assert ctx.isPointInPath(51, 10) === true; @moz-todo @assert ctx.isPointInPath(69, 10) === true; @moz-todo @assert ctx.isPointInPath(71, 10) === false; - name: 2d.drawImage.3arg testing: - 2d.drawImage.defaultsource - 2d.drawImage.defaultdest images: - red.png - green.png code: | ctx.drawImage(document.getElementById('green.png'), 0, 0); ctx.drawImage(document.getElementById('red.png'), -100, 0); ctx.drawImage(document.getElementById('red.png'), 100, 0); ctx.drawImage(document.getElementById('red.png'), 0, -50); ctx.drawImage(document.getElementById('red.png'), 0, 50); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.5arg testing: - 2d.drawImage.defaultsource images: - red.png - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('green.png'), 50, 0, 50, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.9arg.basic testing: - 2d.drawImage.paint images: - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('green.png'), 0, 0, 100, 50, 0, 0, 100, 50); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.9arg.sourcepos testing: - 2d.drawImage.paint images: - rgrg-256x256.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('rgrg-256x256.png'), 140, 20, 100, 50, 0, 0, 100, 50); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.9arg.sourcesize testing: - 2d.drawImage.paint images: - rgrg-256x256.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('rgrg-256x256.png'), 0, 0, 256, 256, 0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 51, 26); ctx.fillRect(49, 24, 51, 26); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; @assert pixel 20,20 ==~ 0,255,0,255; @assert pixel 80,20 ==~ 0,255,0,255; @assert pixel 20,30 ==~ 0,255,0,255; @assert pixel 80,30 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.9arg.destpos testing: - 2d.drawImage.paint images: - red.png - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('green.png'), 0, 0, 100, 50, 0, 0, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, -100, 0, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 100, 0, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, -50, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, 50, 100, 50); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.9arg.destsize testing: - 2d.drawImage.paint images: - red.png - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('green.png'), 1, 1, 1, 1, 0, 0, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, -50, 0, 50, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 100, 0, 50, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, -25, 100, 25); ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, 50, 100, 25); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.canvas testing: - 2d.drawImage.paint code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#0f0'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.drawImage(canvas2, 0, 0); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.self.1 code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); ctx.drawImage(canvas, 50, 0); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.self.2 code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 1, 100, 49); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 1); ctx.drawImage(canvas, 0, 1); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 2); @assert pixel 0,0 ==~ 0,255,0,255; @assert pixel 99,0 ==~ 0,255,0,255; @assert pixel 0,49 ==~ 0,255,0,255; @assert pixel 99,49 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.null #mozilla: { bug: TODO } testing: - 2d.drawImage.type code: | @assert throws TYPE_MISMATCH_ERR ctx.drawImage(null, 0, 0); @moz-todo - name: 2d.drawImage.wrongtype #mozilla: { bug: TODO } testing: - 2d.drawImage.type code: | @assert throws TYPE_MISMATCH_ERR ctx.drawImage(undefined, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.drawImage(0, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.drawImage("", 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.drawImage(document.createElement('p'), 0, 0); @moz-todo - name: 2d.drawImage.floatsource testing: - 2d.drawImage.paint images: - green.png code: | ctx.drawImage(document.getElementById('green.png'), 10.1, 10.1, 0.1, 0.1, 0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.zerosource notes: Unspecified behaviour #mozilla: { bug: TODO } images: - green.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('green.png'), 10, 10, 0, 1, 0, 0, 30, 50); ctx.drawImage(document.getElementById('green.png'), 10, 10, 1, 0, 30, 0, 40, 50); ctx.drawImage(document.getElementById('green.png'), 10, 10, 0, 0, 70, 0, 30, 50); @assert pixel 15,25 ==~ 0,255,0,255; @moz-todo @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo @assert pixel 85,25 ==~ 0,255,0,255; @moz-todo expected: green - name: 2d.drawImage.negativesource notes: Unspecified behaviour images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, -1, 1, 0, 0, 100, 50); expected: green - name: 2d.drawImage.negativedest testing: - 2d.drawImage.negativedest images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 1, 1, 0, 50, -100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 1, 1, 0, 50, 100, -50); expected: green - name: 2d.drawImage.outsidesource testing: - 2d.drawImage.outsidesource #mozilla: { bug: TODO } images: - green.png - red.png code: | ctx.drawImage(document.getElementById('green.png'), 10.5, 10.5, 89.5, 39.5, 0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), -0.001, 0, 100, 50, 0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, -0.001, 100, 50, 0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 100.001, 50, 0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50.001, 0, 0, 100, 50); @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 50, 0, 50.001, 50, 0, 0, 100, 50); @moz-todo @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo expected: green - name: 2d.drawImage.incomplete testing: - 2d.drawImage.incomplete #mozilla: { bug: TODO } code: | var img = new Image(); @assert img.complete === false; @moz-todo @assert throws INVALID_STATE_ERR ctx.drawImage(img, 0, 0); @moz-todo # TODO: see 2d.pattern.image.incomplete2,3,4 and repeat them here once they're fixed - name: 2d.drawImage.broken testing: - 2d.drawImage.incomplete #mozilla: { bug: TODO } images: - broken.png code: | var img = document.getElementById('broken.png'); @assert img.complete === false; @moz-todo @assert throws INVALID_STATE_ERR ctx.drawImage(img, 0, 0); @moz-todo - name: 2d.drawImage.path testing: - 2d.drawImage.unaffect images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.rect(0, 0, 100, 50); ctx.drawImage(document.getElementById('red.png'), 0, 0); ctx.fill(); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.transform testing: - 2d.drawImage.subject images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.translate(100, 0); ctx.drawImage(document.getElementById('red.png'), 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green # TODO: drawImage shadows - name: 2d.drawImage.alpha testing: - 2d.drawImage.subject images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.globalAlpha = 0; ctx.drawImage(document.getElementById('red.png'), 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.clip testing: - 2d.drawImage.subject images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.rect(-10, -10, 1, 1); ctx.clip(); ctx.drawImage(document.getElementById('red.png'), 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.composite testing: - 2d.drawImage.subject images: - red.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = 'destination-over'; ctx.drawImage(document.getElementById('red.png'), 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.drawImage.nowrap desc: Stretched images do not get pixels wrapping around the edges images: - redtransparent.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.drawImage(document.getElementById('redtransparent.png'), -1950, 0, 2000, 50); @assert pixel 45,25 ==~ 0,255,0,255; @assert pixel 50,25 ==~ 0,255,0,255; @assert pixel 55,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.get.basic testing: - 2d.imageData.get.basic code: | @assert ctx.getImageData(0, 0, 100, 50) !== null; - name: 2d.imageData.get.sourcepos testing: - 2d.imageData.get.basic code: | ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#fff'; ctx.fillRect(20, 10, 60, 30); var imgdata1 = ctx.getImageData(10, 5, 1, 1); @assert imgdata1.data[0] < 50; var imgdata2 = ctx.getImageData(30, 20, 1, 1); @assert imgdata2.data[0] > 200; - name: 2d.imageData.get.values testing: - 2d.imageData.get.range code: | ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#fff'; ctx.fillRect(20, 10, 60, 30); var imgdata1 = ctx.getImageData(10, 5, 1, 1); @assert imgdata1.data[0] === 0; var imgdata2 = ctx.getImageData(30, 20, 1, 1); @assert imgdata2.data[0] === 255; - name: 2d.imageData.get.sourcesize testing: - 2d.imageData.get.basic code: | var imgdata1 = ctx.getImageData(0, 0, 10, 10); var imgdata2 = ctx.getImageData(0, 0, 20, 20); @assert imgdata2.width > imgdata1.width; @assert imgdata2.height > imgdata1.height; - name: 2d.imageData.get.properties testing: - 2d.imageData.get.properties code: | var imgdata = ctx.getImageData(0, 0, 100, 50); @assert typeof(imgdata.width) == 'number'; @assert typeof(imgdata.height) == 'number'; @assert typeof(imgdata.data) == 'object'; @assert imgdata.data.length === imgdata.width*imgdata.height*4; - name: 2d.imageData.get.dataarray desc: ImageData.data acts enough like an Array testing: - 2d.imageData.get.properties code: | var imgdata = ctx.getImageData(0, 0, 1, 1); var data = imgdata.data.join(';'); @assert data =~ /^0;0;0;0/; - name: 2d.imageData.get.outside.1 testing: - 2d.imageData.get.outside mozilla: { disabled } # TODO: report bug? code: | var imgdata = ctx.getImageData(-5, 20, 10, 10); @assert imgdata.data[0] === 0; @assert imgdata.data[1] === 0; @assert imgdata.data[2] === 0; @assert imgdata.data[3] === 0; - name: 2d.imageData.get.outside.2 testing: - 2d.imageData.get.outside mozilla: { disabled } # TODO: report bug? code: | var imgdata1 = ctx.getImageData(-20, 20, 10, 10); @assert imgdata1.data[0] === 0; @assert imgdata1.data[1] === 0; @assert imgdata1.data[2] === 0; @assert imgdata1.data[3] === 0; var imgdata2 = ctx.getImageData(40, -20, 10, 10); @assert imgdata2.data[0] === 0; @assert imgdata2.data[1] === 0; @assert imgdata2.data[2] === 0; @assert imgdata2.data[3] === 0; var imgdata3 = ctx.getImageData(110, 20, 10, 10); @assert imgdata3.data[0] === 0; @assert imgdata3.data[1] === 0; @assert imgdata3.data[2] === 0; @assert imgdata3.data[3] === 0; var imgdata4 = ctx.getImageData(40, 60, 10, 10); @assert imgdata4.data[0] === 0; @assert imgdata4.data[1] === 0; @assert imgdata4.data[2] === 0; @assert imgdata4.data[3] === 0; - name: 2d.imageData.get.nonpremul testing: - 2d.imageData.get.premul code: | ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; ctx.fillRect(0, 0, 100, 50); var imgdata = ctx.getImageData(10, 10, 10, 10); @assert imgdata.data[0] > 200; @assert imgdata.data[1] > 200; @assert imgdata.data[2] > 200; @assert imgdata.data[3] > 100; @assert imgdata.data[3] < 200; - name: 2d.imageData.get.order.cols testing: - 2d.imageData.get.pixelorder code: | ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 2, 50); var imgdata = ctx.getImageData(0, 0, 10, 10); @assert imgdata.data[0] === 0; @assert imgdata.data[Math.floor(imgdata.width/2*4)] === 255; @assert imgdata.data[(imgdata.height/2)*imgdata.width*4] === 0; - name: 2d.imageData.get.order.rows testing: - 2d.imageData.get.pixelorder code: | ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 100, 2); var imgdata = ctx.getImageData(0, 0, 10, 10); @assert imgdata.data[0] === 0; @assert imgdata.data[Math.floor(imgdata.width/2*4)] === 0; @assert imgdata.data[(imgdata.height/2)*imgdata.width*4] === 255; - name: 2d.imageData.get.order.rgb testing: - 2d.imageData.get.pixelorder code: | ctx.fillStyle = '#48c'; ctx.fillRect(0, 0, 100, 50); var imgdata = ctx.getImageData(0, 0, 10, 10); @assert imgdata.data[0] === 0x44; @assert imgdata.data[1] === 0x88; @assert imgdata.data[2] === 0xCC; @assert imgdata.data[3] === 255; - name: 2d.imageData.get.order.alpha testing: - 2d.imageData.get.pixelorder code: | ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.fillRect(0, 0, 100, 50); var imgdata = ctx.getImageData(0, 0, 10, 10); @assert imgdata.data[3] < 200; @assert imgdata.data[3] > 100; - name: 2d.imageData.get.smallest testing: - 2d.imageData.get.smallest code: | var imgdata = ctx.getImageData(0, 0, 1, 1); @assert imgdata.width > 0; @assert imgdata.height > 0; @assert imgdata.data.length === imgdata.width*imgdata.height*4; - name: 2d.imageData.get.nonpositive testing: - 2d.imageData.get.nonpositive #mozilla: { bug: TODO } code: | @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, 1, 0); @moz-todo @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, 0, 1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, 0, 0); @moz-todo @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, 1, -1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, -1, 1); @moz-todo @assert throws INDEX_SIZE_ERR ctx.getImageData(10, 10, -1, -1); @moz-todo - name: 2d.imageData.get.nonfinite #mozilla: { bug: TODO } code: | @assert throws NOT_SUPPORTED_ERR ctx.getImageData(Infinity, 10, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, Infinity, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, Infinity, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, 1, Infinity); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(-Infinity, 10, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, -Infinity, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, -Infinity, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, 1, -Infinity); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(NaN, 10, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, NaN, 1, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, NaN, 1); @moz-todo @assert throws NOT_SUPPORTED_ERR ctx.getImageData(10, 10, 1, NaN); @moz-todo - name: 2d.imageData.put.basic testing: - 2d.imageData.put.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) var imgdata = ctx.getImageData(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50) ctx.putImageData(imgdata, 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.alpha testing: - 2d.imageData.put.basic code: | ctx.fillStyle = 'rgba(0, 255, 0, 0.25)'; ctx.fillRect(0, 0, 100, 50) var imgdata = ctx.getImageData(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50) ctx.putImageData(imgdata, 0, 0); @assert pixel 50,25 ==~ 0,255,0,64; expected: | size 100 50 cr.set_source_rgba(0, 1, 0, 0.25) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.imageData.put.modified testing: - 2d.imageData.put.basic code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) ctx.fillStyle = '#f00'; ctx.fillRect(45, 20, 10, 10) var imgdata = ctx.getImageData(45, 20, 10, 10); for (var i = 0, len = imgdata.width*imgdata.height*4; i < len; i += 4) { imgdata.data[i] = 0; imgdata.data[i+1] = 255; } ctx.putImageData(imgdata, 45, 20); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.outside testing: - 2d.imageData.put.basic mozilla: { disabled } # TODO: report bug? code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50) var imgdata = ctx.getImageData(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) ctx.putImageData(imgdata, -100, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.type.correct desc: putImageData accepts a correctly-constructed image data object testing: - 2d.imageData.put.type code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) var imgdata1 = ctx.getImageData(45, 20, 10, 10); ctx.fillStyle = '#f00'; ctx.fillRect(45, 20, 10, 10) var data = []; for (var i = 0; i < imgdata1.data.length; ++i) data[i] = imgdata1.data[i]; var imgdata2 = { width: imgdata1.width, height: imgdata1.height, data: data }; ctx.putImageData(imgdata2, 45, 20); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.type.onepixel desc: putImageData accepts a correctly-constructed 1x1 image data object testing: - 2d.imageData.put.type code: | ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 0] }, 0, 0); @assert true; // no exception - name: 2d.imageData.put.type.extra desc: putImageData accepts an image data object with extra attributes testing: - 2d.imageData.put.type code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) var imgdata1 = ctx.getImageData(45, 20, 10, 10); ctx.fillStyle = '#f00'; ctx.fillRect(45, 20, 10, 10) var data = []; for (var i = 0; i < imgdata1.data.length; ++i) data[i] = imgdata1.data[i]; var imgdata2 = { width: imgdata1.width, height: imgdata1.height, data: data, extra: 123 }; ctx.putImageData(imgdata2, 45, 20); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.type.missing desc: putImageData does not accept an image data object with missing attributes testing: - 2d.imageData.put.type #mozilla: { bug: TODO } code: | var imgdata1 = ctx.getImageData(0, 0, 10, 10); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ height: imgdata1.height, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: imgdata1.width, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: imgdata1.width, height: imgdata1.height }, 0, 0); @moz-todo - name: 2d.imageData.put.type.invalidsize desc: putImageData does not accept an image data object with incorrect sizes testing: - 2d.imageData.put.type #mozilla: { bug: TODO } code: | var imgdata1 = ctx.getImageData(0, 0, 10, 10); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 0, height: imgdata1.height, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: -1, height: imgdata1.height, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: NaN, height: imgdata1.height, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: imgdata1.width, height: 0, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: imgdata1.width, height: -1, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: imgdata1.width, height: NaN, data: imgdata1.data }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1, data: [] }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1, data: [0] }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1, data: [0,0] }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1, data: [0,0,0] }, 0, 0); @moz-todo @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1, data: [0,0,0,0,0] }, 0, 0); @moz-todo - name: 2d.imageData.put.type.zerosize desc: putImageData does not accept an image data object with zero size testing: - 2d.imageData.put.type code: | @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 0, height: 1, data: [] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 0, data: [] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 0.1, height: 1, data: [] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 0.1, data: [] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 0, height: 0, data: [] }, 0, 0); - name: 2d.imageData.put.type.noninteger desc: putImageData does not accept an image data object with non-integer size testing: - 2d.imageData.put.type code: | @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1.1, height: 1, data: [0, 0, 0, 0] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1, height: 1.1, data: [0, 0, 0, 0] }, 0, 0); @assert throws TYPE_MISMATCH_ERR ctx.putImageData({ width: 1.1, height: 1.1, data: [0, 0, 0, 0] }, 0, 0); - name: 2d.imageData.put.clamp code: | ctx.putImageData({ width: 1, height: 1, data: [-1, 0, 1, 255] }, 0, 0); ctx.putImageData({ width: 1, height: 1, data: [254, 255, 256, 255] }, 1, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, -1] }, 2, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 0] }, 3, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 1] }, 4, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 254] }, 5, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 255] }, 6, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 256] }, 7, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, Infinity] }, 0, 1); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, -Infinity] }, 1, 1); ctx.putImageData({ width: 1, height: 1, data: [Infinity, Infinity, Infinity, 255] }, 2, 1); ctx.putImageData({ width: 1, height: 1, data: [-Infinity, -Infinity, -Infinity, 255] }, 3, 1); // TODO: what happens with NaN? @assert pixel 0,0 == 0,0,1,255; @assert pixel 1,0 == 254,255,255,255; @assert pixel 2,0 == 0,0,0,0; @assert pixel 3,0 == 0,0,0,0; @assert pixel 4,0 == 0,0,0,1; @assert pixel 5,0 == 0,0,0,254; @assert pixel 6,0 == 0,0,0,255; @assert pixel 7,0 == 0,0,0,255; @assert pixel 0,1 == 0,0,0,255; @assert pixel 1,1 == 0,0,0,0; @assert pixel 2,1 == 255,255,255,255; @assert pixel 3,1 == 0,0,0,255; # TODO: create a useful 'expected' image here - name: 2d.imageData.put.round code: | ctx.putImageData({ width: 1, height: 1, data: [0.1, 0.9, 1.1, 255] }, 0, 0); ctx.putImageData({ width: 1, height: 1, data: [1.1, 1.9, 2.1, 255] }, 1, 0); ctx.putImageData({ width: 1, height: 1, data: [0.5, 1.5, 2.5, 255] }, 2, 0); ctx.putImageData({ width: 1, height: 1, data: [252.5, 253.5, 254.5, 255] }, 3, 0); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 254.5] }, 0, 1); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 253.5] }, 1, 1); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 252.5] }, 2, 1); ctx.putImageData({ width: 1, height: 1, data: [0, 0, 0, 251.5] }, 3, 1); @assert pixel 0,0 == 0,1,1,255; @assert pixel 1,0 == 1,2,2,255; @assert pixel 2,0 == 0,2,2,255; @assert pixel 3,0 == 252,254,254,255; @assert pixel 0,1 == 0,0,0,254; @assert pixel 1,1 == 0,0,0,254; @assert pixel 2,1 == 0,0,0,252; @assert pixel 3,1 == 0,0,0,252; # TODO: create a useful 'expected' image here - name: 2d.imageData.put.unchanged testing: - 2d.imageData.unchanged code: | var i = 0; for (var y = 0; y < 16; ++y) { for (var x = 0; x < 16; ++x, ++i) { ctx.fillStyle = 'rgba(' + i + ',' + (Math.floor(i*1.5) % 256) + ',' + (Math.floor(i*23.3) % 256) + ',' + (i/256) + ')'; ctx.fillRect(x, y, 1, 1); } } var imgdata1 = ctx.getImageData(0.1, 0.2, 15.8, 15.9); var olddata = []; for (var i = 0; i < imgdata1.data.length; ++i) olddata[i] = imgdata1.data[i]; ctx.putImageData(imgdata1, 0.1, 0.2); var imgdata2 = ctx.getImageData(0.1, 0.2, 15.8, 15.9); for (var i = 0; i < imgdata2.data.length; ++i) { @assert olddata[i] === imgdata2.data[i]; } - name: 2d.imageData.put.unaffected testing: - 2d.imageData.transform code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50) var imgdata = ctx.getImageData(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50) ctx.globalAlpha = 0.1; ctx.globalCompositeOperation = 'destination-atop'; ctx.shadowColor = '#f00'; ctx.translate(100, 50); ctx.scale(0.1, 0.1); ctx.putImageData(imgdata, 0, 0); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.imageData.put.path testing: - 2d.imageData.put.basic code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50) ctx.rect(0, 0, 100, 50); var imgdata = ctx.getImageData(0, 0, 100, 50); ctx.putImageData(imgdata, 0, 0); ctx.fillStyle = '#0f0'; ctx.fill(); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.attributes.shadowBlur.1 code: | ctx.shadowBlur = 1; @assert ctx.shadowBlur === 1; ctx.shadowBlur = 0.5; @assert ctx.shadowBlur === 0.5; ctx.shadowBlur = 1e6; @assert ctx.shadowBlur === 1e6; ctx.shadowBlur = 1; ctx.shadowBlur = -2; @assert ctx.shadowBlur === 1; ctx.shadowBlur = 0; @assert ctx.shadowBlur === 0; - name: 2d.shadow.attributes.shadowBlur.2 code: | @assert throws NOT_SUPPORTED_ERR ctx.shadowBlur = Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowBlur = -Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowBlur = NaN; - name: 2d.shadow.attributes.shadowOffset.1 code: | ctx.shadowOffsetX = 1; ctx.shadowOffsetY = 2; @assert ctx.shadowOffsetX === 1; @assert ctx.shadowOffsetY === 2; ctx.shadowOffsetX = 0.5; ctx.shadowOffsetY = 0.25; @assert ctx.shadowOffsetX === 0.5; @assert ctx.shadowOffsetY === 0.25; ctx.shadowOffsetX = -0.5; ctx.shadowOffsetY = -0.25; @assert ctx.shadowOffsetX === -0.5; @assert ctx.shadowOffsetY === -0.25; ctx.shadowOffsetX = 1e6; ctx.shadowOffsetY = 1e6; @assert ctx.shadowOffsetX === 1e6; @assert ctx.shadowOffsetY === 1e6; - name: 2d.shadow.attributes.shadowOffset.2 code: | @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetX = Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetX = -Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetX = NaN; @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetY = Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetY = -Infinity; @assert throws NOT_SUPPORTED_ERR ctx.shadowOffsetY = NaN; - name: 2d.shadow.attributes.shadowColor.1 code: | ctx.shadowColor = 'lime'; @assert ctx.shadowColor === '#00ff00'; ctx.shadowColor = 'RGBA(0,255, 0,0)'; @assert ctx.shadowColor === 'rgba(0, 255, 0, 0.0)'; - name: 2d.shadow.attributes.shadowColor.2 code: | ctx.shadowColor = '#00ff00'; ctx.shadowColor = 'bogus'; @assert ctx.shadowColor === '#00ff00'; ctx.shadowColor = ctx; @assert ctx.shadowColor === '#00ff00'; ctx.shadowColor = undefined; @assert ctx.shadowColor === '#00ff00'; - name: 2d.shadow.basic.1 notes: &shadow Assumes this definition. code: | ctx.shadowColor = '#f00'; ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.basic.2 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.shadowColor = '#f00'; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.offset.positiveX notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 50; ctx.fillRect(0, 0, 50, 50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.offset.negativeX notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = -50; ctx.fillRect(50, 0, 50, 50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.offset.positiveY notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 25; ctx.fillRect(0, 0, 100, 25); @assert pixel 50,12 == 0,255,0,255; @assert pixel 50,37 == 0,255,0,255; expected: green - name: 2d.shadow.offset.negativeY notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = -25; ctx.fillRect(0, 25, 100, 25); @assert pixel 50,12 == 0,255,0,255; @assert pixel 50,37 == 0,255,0,255; expected: green - name: 2d.shadow.outside notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 100; ctx.fillRect(-100, 0, 25, 50); ctx.shadowOffsetX = -100; ctx.fillRect(175, 0, 25, 50); ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 100; ctx.fillRect(25, -100, 50, 25); ctx.shadowOffsetY = -100; ctx.fillRect(25, 125, 50, 25); @assert pixel 12,25 == 0,255,0,255; @assert pixel 87,25 == 0,255,0,255; @assert pixel 50,12 == 0,255,0,255; @assert pixel 50,37 == 0,255,0,255; expected: green - name: 2d.shadow.clip.1 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); ctx.save(); ctx.beginPath(); ctx.rect(50, 0, 50, 50); ctx.clip(); ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 50; ctx.fillRect(0, 0, 50, 50); ctx.restore(); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.clip.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 50); ctx.save(); ctx.beginPath(); ctx.rect(0, 0, 50, 50); ctx.clip(); ctx.shadowColor = '#f00'; ctx.shadowOffsetX = 50; ctx.fillRect(0, 0, 50, 50); ctx.restore(); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.clip.3 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 50); ctx.save(); ctx.beginPath(); ctx.rect(0, 0, 50, 50); ctx.clip(); ctx.fillStyle = '#f00'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 50; ctx.fillRect(-50, 0, 50, 50); ctx.restore(); @assert pixel 25,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.basic notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.beginPath(); ctx.lineWidth = 50; ctx.moveTo(0, -25); ctx.lineTo(100, -25); ctx.stroke(); @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.cap.1 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#f00'; ctx.shadowOffsetY = 50; ctx.beginPath(); ctx.lineWidth = 50; ctx.lineCap = 'butt'; ctx.moveTo(-50, -25); ctx.lineTo(0, -25); ctx.moveTo(100, -25); ctx.lineTo(150, -25); ctx.stroke(); @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.cap.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.beginPath(); ctx.lineWidth = 50; ctx.lineCap = 'square'; ctx.moveTo(25, -25); ctx.lineTo(75, -25); ctx.stroke(); @assert pixel 1,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,25 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.join.1 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#f00'; ctx.shadowOffsetX = 100; ctx.lineWidth = 200; ctx.lineJoin = 'bevel'; ctx.beginPath(); ctx.moveTo(-200, -50); ctx.lineTo(-150, -50); ctx.lineTo(-151, -100); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.join.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 100; ctx.lineWidth = 200; ctx.lineJoin = 'miter'; ctx.beginPath(); ctx.moveTo(-200, -50); ctx.lineTo(-150, -50); ctx.lineTo(-151, -100); ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.shadow.stroke.join.3 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.strokeStyle = '#f00'; ctx.shadowColor = '#f00'; ctx.shadowOffsetX = 100; ctx.lineWidth = 200; ctx.lineJoin = 'miter'; ctx.miterLimit = 0.1; ctx.beginPath(); ctx.moveTo(-200, -50); ctx.lineTo(-150, -50); ctx.lineTo(-151, -100); // (not an exact right angle, to avoid some other bug in Firefox 3) ctx.stroke(); @assert pixel 1,1 == 0,255,0,255; @assert pixel 48,48 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 98,48 == 0,255,0,255; expected: green - name: 2d.shadow.image.basic notes: *shadow images: - red.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.drawImage(document.getElementById('red.png'), 0, -50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.image.transparent.1 notes: *shadow images: - transparent.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#f00'; ctx.shadowOffsetY = 50; ctx.drawImage(document.getElementById('transparent.png'), 0, -50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.image.transparent.2 notes: *shadow images: - redtransparent.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.drawImage(document.getElementById('redtransparent.png'), 50, -50); ctx.shadowColor = '#f00'; ctx.drawImage(document.getElementById('redtransparent.png'), -50, -50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.image.alpha notes: *shadow images: - transparent50.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#00f'; ctx.drawImage(document.getElementById('transparent50.png'), 0, -50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.image.section notes: *shadow images: - redtransparent.png code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#f00'; ctx.drawImage(document.getElementById('redtransparent.png'), 50, 0, 50, 50, 0, -50, 50, 50); @assert pixel 25,25 ==~ 0,255,0,255; @assert pixel 50,25 ==~ 0,255,0,255; @assert pixel 75,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.image.scale notes: *shadow images: - redtransparent.png code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.drawImage(document.getElementById('redtransparent.png'), 0, 0, 100, 50, -10, -50, 240, 50); @assert pixel 25,25 ==~ 0,255,0,255; @assert pixel 50,25 ==~ 0,255,0,255; @assert pixel 75,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.canvas.basic notes: *shadow code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.drawImage(canvas2, 0, -50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.canvas.transparent.1 notes: *shadow code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#f00'; ctx.shadowOffsetY = 50; ctx.drawImage(canvas2, 0, -50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.canvas.transparent.2 notes: *shadow code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#f00'; ctx2.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#f00'; ctx.fillRect(50, 0, 50, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.drawImage(canvas2, 50, -50); ctx.shadowColor = '#f00'; ctx.drawImage(canvas2, -50, -50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.canvas.alpha notes: *shadow images: - transparent50.png code: | var canvas2 = document.createElement('canvas'); canvas2.width = 100; canvas2.height = 50; var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = 'rgba(255, 0, 0, 0.5)'; ctx2.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#00f'; ctx.drawImage(canvas2, 0, -50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.pattern.basic # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow images: - red.png code: | var pattern = ctx.createPattern(document.getElementById('red.png'), 'repeat'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.fillStyle = pattern; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.pattern.transparent.1 # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow images: - transparent.png code: | var pattern = ctx.createPattern(document.getElementById('transparent.png'), 'repeat'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#f00'; ctx.shadowOffsetY = 50; ctx.fillStyle = pattern; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.pattern.transparent.2 # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow images: - redtransparent.png code: | var pattern = ctx.createPattern(document.getElementById('redtransparent.png'), 'repeat'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.fillStyle = pattern; ctx.fillRect(0, -50, 100, 50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.pattern.alpha # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow images: - transparent50.png code: | var pattern = ctx.createPattern(document.getElementById('transparent50.png'), 'repeat'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#00f'; ctx.fillStyle = pattern; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.gradient.basic # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow code: | var gradient = ctx.createLinearGradient(0, 0, 100, 0); gradient.addColorStop(0, '#f00'); gradient.addColorStop(1, '#f00'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#0f0'; ctx.shadowOffsetY = 50; ctx.fillStyle = gradient; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.gradient.transparent.1 # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow code: | var gradient = ctx.createLinearGradient(0, 0, 100, 0); gradient.addColorStop(0, 'rgba(0,0,0,0)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#f00'; ctx.shadowOffsetY = 50; ctx.fillStyle = gradient; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.gradient.transparent.2 # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow code: | var gradient = ctx.createLinearGradient(0, 0, 100, 0); gradient.addColorStop(0, '#f00'); gradient.addColorStop(0.499, '#f00'); gradient.addColorStop(0.5, 'rgba(0,0,0,0)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 50, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(50, 0, 50, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.fillStyle = gradient; ctx.fillRect(0, -50, 100, 50); @assert pixel 25,25 == 0,255,0,255; @assert pixel 50,25 == 0,255,0,255; @assert pixel 75,25 == 0,255,0,255; expected: green - name: 2d.shadow.gradient.alpha # http://bugs.webkit.org/show_bug.cgi?id=15266 notes: *shadow code: | var gradient = ctx.createLinearGradient(0, 0, 100, 0); gradient.addColorStop(0, 'rgba(255,0,0,0.5)'); gradient.addColorStop(1, 'rgba(255,0,0,0.5)'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#00f'; ctx.fillStyle = gradient; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.transform.1 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.translate(100, 100); ctx.fillRect(-100, -150, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.transform.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowOffsetY = 50; ctx.shadowColor = '#0f0'; ctx.rotate(Math.PI) ctx.fillRect(-100, 0, 100, 50); @assert pixel 50,25 == 0,255,0,255; expected: green - name: 2d.shadow.blur.low notes: *shadow code: | ctx.fillStyle = '#ff0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#00f'; ctx.shadowOffsetY = 25; for (var x = 0; x < 100; ++x) { ctx.save(); ctx.beginPath(); ctx.rect(x, 0, 1, 50); ctx.clip(); ctx.shadowBlur = x; ctx.fillRect(-200, -200, 500, 200); ctx.restore(); } expected: | size 100 50 import math cr.set_source_rgb(0, 0, 1) cr.rectangle(0, 0, 1, 25) cr.fill() cr.set_source_rgb(1, 1, 0) cr.rectangle(0, 25, 1, 25) cr.fill() for x in range(1, 100): if x < 8: sigma = x/2.0 else: sigma = math.sqrt(x*2) filter = [math.exp(-i*i / (2*sigma*sigma)) / (math.sqrt(2*math.pi)*sigma) for i in range(-24, 26)] accum = [0] for f in filter: accum.append(accum[-1] + f) for y in range(0, 50): cr.set_source_rgb(accum[y], accum[y], 1-accum[y]) cr.rectangle(x, y, 1, 1) cr.fill() - name: 2d.shadow.blur.high notes: *shadow code: | ctx.fillStyle = '#ff0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = '#00f'; ctx.shadowOffsetY = 0; ctx.shadowBlur = 555.6; ctx.fillRect(-200, -200, 200, 400); expected: | size 100 50 import math sigma = math.sqrt(555.6*2) filter = [math.exp(-i*i / (2*sigma*sigma)) / (math.sqrt(2*math.pi)*sigma) for i in range(-200, 100)] accum = [0] for f in filter: accum.append(accum[-1] + f) for x in range(0, 100): cr.set_source_rgb(accum[x+200], accum[x+200], 1-accum[x+200]) cr.rectangle(x, 0, 1, 50) cr.fill() - name: 2d.shadow.alpha.1 notes: *shadow code: | ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = 'rgba(255, 0, 0, 0.01)'; ctx.shadowOffsetY = 50; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255 +/- 4; expected: green - name: 2d.shadow.alpha.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.shadowColor = 'rgba(0, 0, 255, 0.5)'; ctx.shadowOffsetY = 50; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.alpha.3 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching) ctx.shadowColor = '#00f'; ctx.shadowOffsetY = 50; ctx.globalAlpha = 0.5; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.alpha.4 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching) ctx.shadowColor = 'rgba(0, 0, 255, 0.707)'; ctx.shadowOffsetY = 50; ctx.globalAlpha = 0.707; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.alpha.5 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = 'rgba(64, 0, 0, 0.5)'; ctx.shadowColor = '#00f'; ctx.shadowOffsetY = 50; ctx.fillRect(0, -50, 100, 50); @assert pixel 50,25 ==~ 127,0,127,255; expected: | size 100 50 cr.set_source_rgb(0.5, 0, 0.5) cr.rectangle(0, 0, 100, 50) cr.fill() - name: 2d.shadow.composite.1 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = 'xor'; ctx.shadowColor = '#f00'; ctx.shadowOffsetX = 100; ctx.fillStyle = '#0f0'; ctx.fillRect(-100, 0, 200, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.composite.2 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = 'xor'; ctx.shadowColor = '#f00'; ctx.shadowBlur = 1; ctx.fillStyle = '#0f0'; ctx.fillRect(-10, -10, 120, 70); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.composite.3 # http://bugs.webkit.org/show_bug.cgi?id=15265 notes: *shadow code: | ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.globalCompositeOperation = 'xor'; ctx.shadowColor = '#f00'; ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - name: 2d.shadow.composite.4 # http://bugs.webkit.org/show_bug.cgi?id=15265 notes: *shadow code: | ctx.globalCompositeOperation = 'destination-over'; ctx.shadowColor = '#0f0'; ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); @assert pixel 50,25 ==~ 0,255,0,255; expected: green - meta: | import re for t in tests: n = t['name'] if ( n.startswith('2d.composite.uncovered.') # bug ??? or n.startswith('2d.path.arcTo.') # unreported or n.startswith('2d.shadow.') # bug ??? or n == '2d.composite.solid.xor' # bug ??? or n.startswith('context.') # bug 401788 ): t.setdefault('mozilla', {}) t['mozilla'].setdefault('disabled', None)