| # Copyright (c) 2011 Philip Taylor |
| # Released under the BSD license and W3C Test Suite License: see LICENSE.txt |
| |
| - name: 2d.getcontext.exists |
| desc: The 2D context is implemented |
| testing: |
| - context.2d |
| code: | |
| @assert canvas.getContext('2d') !== null; |
| |
| - name: 2d.getcontext.extraargs |
| desc: The 2D context ignores extra getContext arguments |
| testing: |
| - context.2d.extraargs |
| code: | |
| @assert canvas.getContext('2d', false, {}, [], 1, "2") !== null; |
| |
| - name: 2d.type.exists |
| desc: The 2D context interface is a property of 'window' |
| notes: &bindings Defined in "Web IDL" (draft) |
| testing: |
| - context.2d.type |
| code: | |
| @assert window.CanvasRenderingContext2D; |
| |
| - name: 2d.type.delete |
| desc: window.CanvasRenderingContext2D is Configurable |
| notes: *bindings |
| testing: |
| - context.2d.type |
| code: | |
| @assert window.CanvasRenderingContext2D !== undefined; |
| @assert delete window.CanvasRenderingContext2D === true; |
| @assert window.CanvasRenderingContext2D === undefined; |
| |
| - name: 2d.type.prototype |
| desc: window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]], and its methods are [[Configurable]]. |
| notes: *bindings |
| testing: |
| - context.2d.type |
| 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; |
| |
| - 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.unique |
| code: | |
| @assert canvas.getContext('2d') === canvas.getContext('2d'); |
| |
| - name: 2d.getcontext.shared |
| desc: getContext('2d') returns objects which share canvas state |
| testing: |
| - context.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 |
| notes: *bindings |
| 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.fillText) { |
| @assert ctx.fillText('test', 0, 0) === undefined; |
| @assert ctx.strokeText('test', 0, 0) === 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, 1, 1, 0, 0, 0, 0) === undefined; |
| @assert ctx.drawImage(canvas, 0, 0, 1, 1, 0, 0, 0, 0) === undefined; |
| @assert ctx.createLinearGradient(0, 0, 0, 0).addColorStop(0, 'white') === undefined; |
| |
| - name: 2d.missingargs |
| desc: Missing arguments cause TypeError |
| code: | |
| @assert throws TypeError ctx.scale(); |
| @assert throws TypeError ctx.scale(1); |
| @assert throws TypeError ctx.rotate(); |
| @assert throws TypeError ctx.translate(); |
| @assert throws TypeError ctx.translate(0); |
| if (ctx.transform) { // (avoid spurious failures, since the aim here is not to test that all features are supported) |
| @assert throws TypeError ctx.transform(); |
| @assert throws TypeError ctx.transform(1); |
| @assert throws TypeError ctx.transform(1, 0); |
| @assert throws TypeError ctx.transform(1, 0, 0); |
| @assert throws TypeError ctx.transform(1, 0, 0, 1); |
| @assert throws TypeError ctx.transform(1, 0, 0, 1, 0); |
| } |
| if (ctx.setTransform) { |
| @assert throws TypeError ctx.setTransform(); |
| @assert throws TypeError ctx.setTransform(1); |
| @assert throws TypeError ctx.setTransform(1, 0); |
| @assert throws TypeError ctx.setTransform(1, 0, 0); |
| @assert throws TypeError ctx.setTransform(1, 0, 0, 1); |
| @assert throws TypeError ctx.setTransform(1, 0, 0, 1, 0); |
| } |
| @assert throws TypeError ctx.createLinearGradient(); |
| @assert throws TypeError ctx.createLinearGradient(0); |
| @assert throws TypeError ctx.createLinearGradient(0, 0); |
| @assert throws TypeError ctx.createLinearGradient(0, 0, 1); |
| @assert throws TypeError ctx.createRadialGradient(); |
| @assert throws TypeError ctx.createRadialGradient(0); |
| @assert throws TypeError ctx.createRadialGradient(0, 0); |
| @assert throws TypeError ctx.createRadialGradient(0, 0, 1); |
| @assert throws TypeError ctx.createRadialGradient(0, 0, 1, 0); |
| @assert throws TypeError ctx.createRadialGradient(0, 0, 1, 0, 0); |
| @assert throws TypeError ctx.createPattern(canvas); |
| @assert throws TypeError ctx.clearRect(); |
| @assert throws TypeError ctx.clearRect(0); |
| @assert throws TypeError ctx.clearRect(0, 0); |
| @assert throws TypeError ctx.clearRect(0, 0, 0); |
| @assert throws TypeError ctx.fillRect(); |
| @assert throws TypeError ctx.fillRect(0); |
| @assert throws TypeError ctx.fillRect(0, 0); |
| @assert throws TypeError ctx.fillRect(0, 0, 0); |
| @assert throws TypeError ctx.strokeRect(); |
| @assert throws TypeError ctx.strokeRect(0); |
| @assert throws TypeError ctx.strokeRect(0, 0); |
| @assert throws TypeError ctx.strokeRect(0, 0, 0); |
| @assert throws TypeError ctx.moveTo(); |
| @assert throws TypeError ctx.moveTo(0); |
| @assert throws TypeError ctx.lineTo(); |
| @assert throws TypeError ctx.lineTo(0); |
| @assert throws TypeError ctx.quadraticCurveTo(); |
| @assert throws TypeError ctx.quadraticCurveTo(0); |
| @assert throws TypeError ctx.quadraticCurveTo(0, 0); |
| @assert throws TypeError ctx.quadraticCurveTo(0, 0, 0); |
| @assert throws TypeError ctx.bezierCurveTo(); |
| @assert throws TypeError ctx.bezierCurveTo(0); |
| @assert throws TypeError ctx.bezierCurveTo(0, 0); |
| @assert throws TypeError ctx.bezierCurveTo(0, 0, 0); |
| @assert throws TypeError ctx.bezierCurveTo(0, 0, 0, 0); |
| @assert throws TypeError ctx.bezierCurveTo(0, 0, 0, 0, 0); |
| @assert throws TypeError ctx.arcTo(); |
| @assert throws TypeError ctx.arcTo(0); |
| @assert throws TypeError ctx.arcTo(0, 0); |
| @assert throws TypeError ctx.arcTo(0, 0, 0); |
| @assert throws TypeError ctx.arcTo(0, 0, 0, 0); |
| @assert throws TypeError ctx.rect(); |
| @assert throws TypeError ctx.rect(0); |
| @assert throws TypeError ctx.rect(0, 0); |
| @assert throws TypeError ctx.rect(0, 0, 0); |
| @assert throws TypeError ctx.arc(); |
| @assert throws TypeError ctx.arc(0); |
| @assert throws TypeError ctx.arc(0, 0); |
| @assert throws TypeError ctx.arc(0, 0, 1); |
| @assert throws TypeError ctx.arc(0, 0, 1, 0); |
| // (6th argument to arc is optional) |
| if (ctx.isPointInPath) { |
| @assert throws TypeError ctx.isPointInPath(); |
| @assert throws TypeError ctx.isPointInPath(0); |
| } |
| if (ctx.drawFocusRing) { |
| @assert throws TypeError ctx.drawFocusRing(); |
| @assert throws TypeError ctx.drawFocusRing(canvas); |
| @assert throws TypeError ctx.drawFocusRing(canvas, 0); |
| } |
| if (ctx.fillText) { |
| @assert throws TypeError ctx.fillText(); |
| @assert throws TypeError ctx.fillText('test'); |
| @assert throws TypeError ctx.fillText('test', 0); |
| @assert throws TypeError ctx.strokeText(); |
| @assert throws TypeError ctx.strokeText('test'); |
| @assert throws TypeError ctx.strokeText('test', 0); |
| @assert throws TypeError ctx.measureText(); |
| } |
| @assert throws TypeError ctx.drawImage(); |
| @assert throws TypeError ctx.drawImage(canvas); |
| @assert throws TypeError ctx.drawImage(canvas, 0); |
| // TODO: n >= 3 args on drawImage could be either a valid overload, |
| // or too few for another overload, or too many for another |
| // overload - what should happen? |
| if (ctx.createImageData) { |
| @assert throws TypeError ctx.createImageData(); |
| @assert throws TypeError ctx.createImageData(1); |
| } |
| if (ctx.getImageData) { |
| @assert throws TypeError ctx.getImageData(); |
| @assert throws TypeError ctx.getImageData(0); |
| @assert throws TypeError ctx.getImageData(0, 0); |
| @assert throws TypeError ctx.getImageData(0, 0, 1); |
| } |
| if (ctx.putImageData) { |
| var imgdata = ctx.getImageData(0, 0, 1, 1); |
| @assert throws TypeError ctx.putImageData(); |
| @assert throws TypeError ctx.putImageData(imgdata); |
| @assert throws TypeError ctx.putImageData(imgdata, 0); |
| } |
| var g = ctx.createLinearGradient(0, 0, 0, 0); |
| @assert throws TypeError g.addColorStop(); @moz-todo |
| @assert throws TypeError g.addColorStop(0); @moz-todo |
| |
| - name: 2d.coordinatespace |
| desc: Coordinate space goes from top-left to bottom-right |
| notes: This should not be upside down. |
| manual: We can't tell that getPixelData isn't using the wrong coordinate space too. |
| 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; |
| 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.scaled |
| desc: CSS-scaled canvases get drawn correctly |
| canvas: 'width="50" height="25" style="width: 100px; height: 50px"' |
| manual: |
| code: | |
| ctx.fillStyle = '#00f'; |
| ctx.fillRect(0, 0, 50, 25); |
| ctx.fillStyle = '#0ff'; |
| ctx.fillRect(0, 0, 25, 10); |
| 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, 20) |
| 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; |
| ctx.canvas = c; |
| @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"'), |
| ('font', '"25px serif"'), |
| ('textAlign', '"center"'), |
| ('textBaseline', '"bottom"'), |
| ] |
| 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 'old' 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 |
| 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(); |
| |
| canvas.toDataURL(); |
| |
| @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.nonfinite |
| desc: scale() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.translate(100, 10); |
| @nonfinite ctx.scale(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -10, 100, 50); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - 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 |
| desc: rotate() by 0 does nothing |
| 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 |
| desc: rotate() uses radians |
| testing: |
| - 2d.transformation.rotate.radians |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.rotate(Math.PI); // should fail obviously if this is 3.1 degrees |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -50, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.transformation.rotate.direction |
| desc: rotate() is clockwise |
| 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 |
| desc: rotate() wraps large positive values correctly |
| 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 |
| desc: rotate() wraps large negative values correctly |
| 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.nonfinite |
| desc: rotate() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.translate(100, 10); |
| @nonfinite ctx.rotate(<0.1 Infinity -Infinity NaN>); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -10, 100, 50); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.transformation.translate.basic |
| desc: translate() works |
| 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.nonfinite |
| desc: translate() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.translate(100, 10); |
| @nonfinite ctx.translate(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -10, 100, 50); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.transformation.transform.identity |
| desc: transform() with the identity matrix does nothing |
| 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 |
| desc: transform() with skewy matrix transforms correctly |
| 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 |
| desc: transform() multiplies the CTM |
| 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.nonfinite |
| desc: transform() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.translate(100, 10); |
| @nonfinite ctx.transform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -10, 100, 50); |
| |
| @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.transformation.setTransform.nonfinite |
| desc: setTransform() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.translate(100, 10); |
| @nonfinite ctx.setTransform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(-100, -10, 100, 50); |
| |
| @assert pixel 50,25 == 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 |
| 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 = Infinity; |
| @assert ctx.globalAlpha === a; |
| ctx.globalAlpha = -Infinity; |
| @assert ctx.globalAlpha === a; |
| 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 |
| 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; |
| expected: green |
| |
| - name: 2d.composite.globalAlpha.canvaspattern |
| 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; |
| expected: green |
| |
| |
| - meta: | |
| # Composite operation tests |
| # <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_test((r,g,b,a)): |
| return '%d,%d,%d,%d' % (round(r), round(g), round(b), round(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), |
| '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), |
| '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), |
| } ) |
| |
| for (name, src, dest) in [ ('canvas', (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), |
| 'testing': [ '2d.composite.%s' % op ], |
| 'images': [ 'yellow75.png' ], |
| 'code': """ |
| var canvas2 = document.createElement('canvas'); |
| canvas2.width = canvas.width; |
| canvas2.height = canvas.height; |
| var ctx2 = canvas2.getContext('2d'); |
| ctx2.drawImage(document.getElementById('yellow75.png'), 0, 0); |
| ctx.fillStyle = 'rgba%s'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.globalCompositeOperation = '%s'; |
| ctx.drawImage(canvas2, 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), |
| } ) |
| |
| |
| 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) |
| tests.append( { |
| 'name': '2d.composite.%s.%s' % (name, op), |
| 'desc': 'fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', |
| '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) |
| tests.append( { |
| 'name': '2d.composite.%s.%s' % (name, op), |
| 'desc': 'drawImage() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', |
| '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'), 40, 40, 10, 10, 40, 50, 10, 10); |
| @assert pixel 15,15 ==~ %s +/- 5; |
| @assert pixel 50,25 ==~ %s +/- 5; |
| """ % (dest, op, to_test(expected0), 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.nocontext', (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) |
| tests.append( { |
| 'name': '2d.composite.%s.%s' % (name, op), |
| 'desc': 'drawImage() of a canvas with no context draws pixels as (0,0,0,0), and does not leave the pixels unchanged.', |
| 'testing': [ '2d.composite.%s' % op ], |
| 'code': """ |
| ctx.fillStyle = 'rgba%s'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.globalCompositeOperation = '%s'; |
| var canvas2 = document.createElement('canvas'); |
| ctx.drawImage(canvas2, 0, 0); |
| @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) |
| tests.append( { |
| 'name': '2d.composite.%s.%s' % (name, op), |
| 'desc': 'Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', |
| '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)), |
| } ) |
| |
| for op, FA_code, FB_code in ops: |
| tests.append( { |
| 'name': '2d.composite.clip.%s' % (op), |
| 'desc': 'fill() does not affect pixels outside the clip region.', |
| 'testing': [ '2d.composite.%s' % op ], |
| 'code': """ |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.globalCompositeOperation = '%s'; |
| ctx.rect(-20, -20, 10, 10); |
| ctx.clip(); |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 50, 50); |
| @assert pixel 25,25 == 0,255,0,255; |
| @assert pixel 75,25 == 0,255,0,255; |
| """ % (op), |
| 'expected': 'green' |
| } ) |
| |
| - 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 |
| testing: |
| - 2d.composite.operation.unrecognised |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'nonexistent'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.darker |
| testing: |
| - 2d.composite.operation.unrecognised |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'darker'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.over |
| testing: |
| - 2d.composite.operation.unrecognised |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'over'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.clear |
| testing: |
| - 2d.composite.operation.unrecognised |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'clear'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.highlight |
| testing: |
| - 2d.composite.operation.unrecognised |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'highlight'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.nullsuffix |
| testing: |
| - 2d.composite.operation.exact |
| code: | |
| ctx.globalCompositeOperation = 'xor'; |
| ctx.globalCompositeOperation = 'source-over\0'; |
| @assert ctx.globalCompositeOperation === 'xor'; |
| |
| - name: 2d.composite.operation.casesensitive |
| 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: | |
| # Colour parsing tests |
| |
| # Try most of the CSS3 Color <color> values - http://www.w3.org/TR/css3-color/#colorunits |
| big_float = '1' + ('0' * 39) |
| big_double = '1' + ('0' * 310) |
| for name, string, r,g,b,a, notes in [ |
| ('html4', 'limE', 0,255,0,255, ""), |
| ('hex3', '#0f0', 0,255,0,255, ""), |
| ('hex4', '#0f0f', 0,255,0,255, ""), |
| ('hex6', '#00fF00', 0,255,0,255, ""), |
| ('hex8', '#00ff00ff', 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-clamp-3', 'rgb(-2147483649, 4294967298, -18446744073709551619)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'), |
| ('rgb-clamp-4', 'rgb(-'+big_float+', '+big_float+', -'+big_float+')', 0,255,0,255, 'Assumes colours are clamped to [0,255].'), |
| ('rgb-clamp-5', 'rgb(-'+big_double+', '+big_double+', -'+big_double+')', 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...)'), |
| ('rgb-eof', 'rgb(0, 255, 0', 0,255,0,255, ""), # see CSS2.1 4.2 "Unexpected end of style sheet" |
| ('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-solid-3', 'rgba( 0 , 255 , 0 , +1 )', 0,255,0,255, ""), |
| ('rgba-solid-4', 'rgba( -0 , 255 , +0 , 1 )', 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, ""), |
| ('rgba-eof', 'rgba(0, 255, 0, 1', 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, ""), |
| ('hsl-6', 'hsl(+120, +100%, +50%)', 0,255,0,255, ""), |
| ('hsl-clamp-1', 'hsl(120, 200%, 50%)', 0,255,0,255, ""), |
| ('hsl-clamp-2', 'hsl(120, -200%, 49.9%)', 127,127,127,255, ""), |
| ('hsl-clamp-3', 'hsl(120, 100%, 200%)', 255,255,255,255, ""), |
| ('hsl-clamp-4', 'hsl(120, 100%, -200%)', 0,0,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, ""), |
| ('hsla-clamp-1', 'hsla(120, 200%, 50%, 1)', 0,255,0,255, ""), |
| ('hsla-clamp-2', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""), |
| ('hsla-clamp-3', 'hsla(120, 100%, 200%, 1)', 255,255,255,255, ""), |
| ('hsla-clamp-4', 'hsla(120, 100%, -200%, 1)', 0,0,0,255, ""), |
| ('hsla-clamp-5', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""), |
| ('hsla-clamp-6', 'hsla(120, 100%, 0%, -2)', 0,0,0,0, ""), |
| ('svg-1', 'gray', 128,128,128,255, ""), |
| ('svg-2', 'grey', 128,128,128,255, ""), |
| # currentColor is handled later |
| ]: |
| # TODO: test by retrieving fillStyle, instead of actually drawing? |
| # TODO: test strokeStyle, shadowColor in the same way |
| 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.), |
| } |
| tests.append(test) |
| |
| # Also test that invalid colours are ignored |
| for name, string in [ |
| ('hex1', '#f'), |
| ('hex2', '#f0'), |
| ('hex3', '#g00'), |
| ('hex4', '#fg00'), |
| ('hex5', '#ff000'), |
| ('hex6', '#fg0000'), |
| ('hex7', '#ff0000f'), |
| ('hex8', '#fg0000ff'), |
| ('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)'), |
| ('rgba-6', 'rgba(255, 0, 0, 1.)'), |
| ('rgba-7', 'rgba(255, 0, 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)'), |
| ('hsl-6', 'hsl(0, 100.%, 50%)'), |
| ('hsla-1', 'hsla(0%, 100%, 50%, 1)'), |
| ('hsla-2', 'hsla(0, 0, 50%, 1)'), |
| ('name-1', 'darkbrown'), |
| ('name-2', 'firebrick1'), |
| ('name-3', 'red blue'), |
| ('name-4', '"red"'), |
| ('name-5', '"red'), |
| ]: |
| 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'), # removed from latest CSS3 Color drafts |
| ]: |
| 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.parse.current.basic |
| desc: currentColor is computed from the canvas element |
| testing: |
| - 2d.colours.parse |
| - 2d.currentColor.onset |
| code: | |
| canvas.setAttribute('style', 'color: #0f0'); |
| ctx.fillStyle = '#f00'; |
| ctx.fillStyle = 'currentColor'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.fillStyle.parse.current.changed |
| desc: currentColor is computed when the attribute is set, not when it is painted |
| testing: |
| - 2d.colours.parse |
| - 2d.currentColor.onset |
| code: | |
| canvas.setAttribute('style', 'color: #0f0'); |
| ctx.fillStyle = '#f00'; |
| ctx.fillStyle = 'currentColor'; |
| canvas.setAttribute('style', 'color: #f00'); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.fillStyle.parse.current.removed |
| desc: currentColor is solid black when the canvas element is not in a document |
| testing: |
| - 2d.colours.parse |
| - 2d.currentColor.outofdoc |
| code: | |
| // Try not to let it undetectably incorrectly pick up opaque-black |
| // from other parts of the document: |
| document.body.parentNode.setAttribute('style', 'color: #f00'); |
| document.body.setAttribute('style', 'color: #f00'); |
| canvas.setAttribute('style', 'color: #f00'); |
| |
| var canvas2 = document.createElement('canvas'); |
| var ctx2 = canvas2.getContext('2d'); |
| ctx2.fillStyle = '#f00'; |
| ctx2.fillStyle = 'currentColor'; |
| ctx2.fillRect(0, 0, 100, 50); |
| ctx.drawImage(canvas2, 0, 0); |
| |
| document.body.parentNode.removeAttribute('style'); |
| document.body.removeAttribute('style'); |
| |
| @assert pixel 50,25 == 0,0,0,255; |
| expected: | |
| size 100 50 |
| cr.set_source_rgb(0, 0, 0) |
| cr.rectangle(0, 0, 100, 50) |
| cr.fill() |
| |
| - 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 |
| - 2d.serializecolour.solid |
| code: | |
| ctx.fillStyle = '#fa0'; |
| @assert ctx.fillStyle === '#ffaa00'; |
| |
| - name: 2d.fillStyle.get.semitransparent |
| testing: |
| - 2d.colours.getcolour |
| - 2d.serializecolour.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 |
| - 2d.serializecolour.transparent |
| code: | |
| ctx.fillStyle = 'rgba(0,0,0,0)'; |
| @assert ctx.fillStyle === 'rgba(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.type |
| desc: window.CanvasGradient exists and has the right properties |
| testing: |
| - 2d.canvasGradient.type |
| notes: *bindings |
| code: | |
| @assert window.CanvasGradient !== undefined; |
| @assert window.CanvasGradient.prototype.addColorStop !== undefined; |
| |
| - name: 2d.gradient.object.return |
| desc: createLinearGradient() and createRadialGradient() returns objects implementing CanvasGradient |
| testing: |
| - 2d.gradient.linear.return |
| - 2d.gradient.radial.return |
| code: | |
| window.CanvasGradient.prototype.thisImplementsCanvasGradient = true; |
| |
| var g1 = ctx.createLinearGradient(0, 0, 100, 0); |
| @assert g1.addColorStop !== undefined; |
| @assert g1.thisImplementsCanvasGradient === true; |
| |
| var g2 = ctx.createRadialGradient(0, 0, 10, 0, 0, 20); |
| @assert g2.addColorStop !== undefined; |
| @assert g2.thisImplementsCanvasGradient === true; |
| |
| - 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 +/- 3; |
| @assert pixel 50,25 ==~ 127,127,127,255 +/- 3; |
| @assert pixel 75,25 ==~ 63,63,191,255 +/- 3; |
| 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 +/- 3; |
| @assert pixel 50,25 ==~ 127,127,127,255 +/- 3; |
| @assert pixel 75,25 ==~ 63,63,191,255 +/- 3; |
| 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 +/- 3; |
| @assert pixel 50,25 ==~ 127,127,127,127 +/- 3; |
| @assert pixel 75,25 ==~ 63,63,191,191 +/- 3; |
| 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.fill |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.rect(0, 0, 100, 50); |
| ctx.fill(); |
| @assert pixel 40,20 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.gradient.interpolate.zerosize.stroke |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.strokeStyle = g; |
| ctx.rect(20, 20, 60, 10); |
| ctx.stroke(); |
| @assert pixel 19,19 == 0,255,0,255; |
| @assert pixel 20,19 == 0,255,0,255; |
| @assert pixel 21,19 == 0,255,0,255; |
| @assert pixel 19,20 == 0,255,0,255; |
| @assert pixel 20,20 == 0,255,0,255; |
| @assert pixel 21,20 == 0,255,0,255; |
| @assert pixel 19,21 == 0,255,0,255; |
| @assert pixel 20,21 == 0,255,0,255; |
| @assert pixel 21,21 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.gradient.interpolate.zerosize.fillRect |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.zerosize.strokeRect |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.strokeStyle = g; |
| ctx.strokeRect(20, 20, 60, 10); |
| @assert pixel 19,19 == 0,255,0,255; |
| @assert pixel 20,19 == 0,255,0,255; |
| @assert pixel 21,19 == 0,255,0,255; |
| @assert pixel 19,20 == 0,255,0,255; |
| @assert pixel 20,20 == 0,255,0,255; |
| @assert pixel 21,20 == 0,255,0,255; |
| @assert pixel 19,21 == 0,255,0,255; |
| @assert pixel 20,21 == 0,255,0,255; |
| @assert pixel 21,21 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.gradient.interpolate.zerosize.fillText |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.font = '100px sans-serif'; |
| ctx.fillText("AA", 0, 50); |
| _assertGreen(ctx, 100, 50); |
| expected: green |
| |
| - name: 2d.gradient.interpolate.zerosize.strokeText |
| testing: |
| - 2d.gradient.linear.zerosize |
| 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.strokeStyle = g; |
| ctx.font = '100px sans-serif'; |
| ctx.strokeText("AA", 0, 50); |
| _assertGreen(ctx, 100, 50); |
| 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 +/- 3; |
| @assert pixel 100,25 ==~ 0,255,255,255 +/- 3; |
| @assert pixel 150,25 ==~ 127,127,255,255 +/- 3; |
| 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.current |
| testing: |
| - 2d.currentColor.gradient |
| code: | |
| canvas.setAttribute('style', 'color: #f00'); |
| |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| var g = ctx.createLinearGradient(0, 0, 100, 0); |
| g.addColorStop(0, 'currentColor'); |
| g.addColorStop(1, 'currentColor'); |
| ctx.fillStyle = g; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 ==~ 0,0,0,255; |
| expected: | |
| size 100 50 |
| cr.set_source_rgb(0, 0, 0) |
| cr.rectangle(0, 0, 100, 50) |
| cr.fill() |
| |
| - name: 2d.gradient.object.invalidoffset |
| testing: |
| - 2d.gradient.invalidoffset |
| 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 TypeError g.addColorStop(Infinity, '#000'); |
| @assert throws TypeError g.addColorStop(-Infinity, '#000'); |
| @assert throws TypeError g.addColorStop(NaN, '#000'); |
| |
| - 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, 'null'); |
| @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined'); |
| @assert throws SYNTAX_ERR g.addColorStop(0, null); |
| @assert throws SYNTAX_ERR g.addColorStop(0, undefined); |
| |
| |
| - name: 2d.gradient.linear.nonfinite |
| desc: createLinearGradient() throws TypeError if arguments are not finite |
| notes: *bindings |
| testing: |
| - 2d.gradient.linear.nonfinite |
| code: | |
| @nonfinite @assert throws TypeError ctx.createLinearGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); |
| |
| - name: 2d.gradient.linear.transform.1 |
| desc: Linear gradient coordinates are relative to the coordinate space at the time of filling |
| testing: |
| - 2d.gradient.linear.transform |
| code: | |
| var g = ctx.createLinearGradient(0, 0, 200, 0); |
| g.addColorStop(0, '#f00'); |
| g.addColorStop(0.25, '#0f0'); |
| g.addColorStop(0.75, '#0f0'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.translate(-50, 0); |
| ctx.fillRect(50, 0, 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.gradient.linear.transform.2 |
| desc: Linear gradient coordinates are relative to the coordinate space at the time of filling |
| testing: |
| - 2d.gradient.linear.transform |
| code: | |
| ctx.translate(100, 0); |
| var g = ctx.createLinearGradient(0, 0, 200, 0); |
| g.addColorStop(0, '#f00'); |
| g.addColorStop(0.25, '#0f0'); |
| g.addColorStop(0.75, '#0f0'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.translate(-150, 0); |
| ctx.fillRect(50, 0, 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.gradient.linear.transform.3 |
| desc: Linear gradient transforms do not experience broken caching effects |
| testing: |
| - 2d.gradient.linear.transform |
| code: | |
| var g = ctx.createLinearGradient(0, 0, 200, 0); |
| g.addColorStop(0, '#f00'); |
| g.addColorStop(0.25, '#0f0'); |
| g.addColorStop(0.75, '#0f0'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.translate(-50, 0); |
| ctx.fillRect(50, 0, 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.gradient.radial.negative |
| desc: createRadialGradient() throws INDEX_SIZE_ERR if either radius is negative |
| testing: |
| - 2d.gradient.radial.negative |
| code: | |
| @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1); |
| @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1); |
| @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1); |
| |
| - name: 2d.gradient.radial.nonfinite |
| desc: createRadialGradient() throws TypeError if arguments are not finite |
| notes: *bindings |
| testing: |
| - 2d.gradient.radial.nonfinite |
| code: | |
| @nonfinite @assert throws TypeError ctx.createRadialGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>); |
| |
| - 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 |
| 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 |
| 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 |
| 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; @moz-todo |
| @assert pixel 50,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; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| @assert pixel 98,25 == 0,255,0,255; @moz-todo |
| @assert pixel 1,48 == 0,255,0,255; @moz-todo |
| @assert pixel 50,48 == 0,255,0,255; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.gradient.radial.touch2 |
| testing: |
| - 2d.gradient.radial.rendering |
| 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 |
| 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; @moz-todo |
| @assert pixel 50,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; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| @assert pixel 98,25 == 0,255,0,255; @moz-todo |
| @assert pixel 1,48 == 0,255,0,255; @moz-todo |
| @assert pixel 50,48 == 0,255,0,255; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.gradient.radial.equal |
| testing: |
| - 2d.gradient.radial.equal |
| 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; @moz-todo |
| @assert pixel 50,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; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| @assert pixel 98,25 == 0,255,0,255; @moz-todo |
| @assert pixel 1,48 == 0,255,0,255; @moz-todo |
| @assert pixel 50,48 == 0,255,0,255; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.gradient.radial.cone.behind |
| testing: |
| - 2d.gradient.radial.rendering |
| 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; @moz-todo |
| @assert pixel 50,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; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| @assert pixel 98,25 == 0,255,0,255; @moz-todo |
| @assert pixel 1,48 == 0,255,0,255; @moz-todo |
| @assert pixel 50,48 == 0,255,0,255; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; @moz-todo |
| 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 |
| 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; @moz-todo |
| @assert pixel 50,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; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| @assert pixel 98,25 == 0,255,0,255; @moz-todo |
| @assert pixel 1,48 == 0,255,0,255; @moz-todo |
| @assert pixel 50,48 == 0,255,0,255; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; @moz-todo |
| 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 |
| 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; @moz-todo |
| @assert pixel 50,1 == 0,255,0,255; @moz-todo |
| @assert pixel 98,1 == 0,255,0,255; |
| @assert pixel 1,25 == 0,255,0,255; @moz-todo |
| @assert pixel 50,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 50,48 == 0,255,0,255; |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.gradient.radial.transform.1 |
| desc: Radial gradient coordinates are relative to the coordinate space at the time of filling |
| testing: |
| - 2d.gradient.radial.transform |
| code: | |
| var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2); |
| g.addColorStop(0, '#0f0'); |
| g.addColorStop(0.5, '#0f0'); |
| g.addColorStop(0.51, '#f00'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.translate(50, 25); |
| ctx.scale(10, 10); |
| ctx.fillRect(-5, -2.5, 10, 5); |
| @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.gradient.radial.transform.2 |
| desc: Radial gradient coordinates are relative to the coordinate space at the time of filling |
| testing: |
| - 2d.gradient.radial.transform |
| code: | |
| ctx.translate(100, 0); |
| var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2); |
| g.addColorStop(0, '#0f0'); |
| g.addColorStop(0.5, '#0f0'); |
| g.addColorStop(0.51, '#f00'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.translate(-50, 25); |
| ctx.scale(10, 10); |
| ctx.fillRect(-5, -2.5, 10, 5); |
| @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.gradient.radial.transform.3 |
| desc: Radial gradient transforms do not experience broken caching effects |
| testing: |
| - 2d.gradient.radial.transform |
| code: | |
| var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2); |
| g.addColorStop(0, '#0f0'); |
| g.addColorStop(0.5, '#0f0'); |
| g.addColorStop(0.51, '#f00'); |
| g.addColorStop(1, '#f00'); |
| ctx.fillStyle = g; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.translate(50, 25); |
| ctx.scale(10, 10); |
| ctx.fillRect(-5, -2.5, 10, 5); |
| @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.pattern.basic.type |
| testing: |
| - 2d.pattern.return |
| images: |
| - green.png |
| code: | |
| @assert window.CanvasPattern !== undefined; |
| |
| window.CanvasPattern.prototype.thisImplementsCanvasPattern = true; |
| |
| var img = document.getElementById('green.png'); |
| var pattern = ctx.createPattern(img, 'no-repeat'); |
| @assert pattern.thisImplementsCanvasPattern; |
| |
| - 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 |
| testing: |
| - 2d.pattern.zerocanvas |
| code: | |
| canvas.width = 0; |
| canvas.height = 10; |
| @assert canvas.width === 0; |
| @assert canvas.height === 10; |
| @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat'); |
| |
| canvas.width = 10; |
| canvas.height = 0; |
| @assert canvas.width === 10; |
| @assert canvas.height === 0; |
| @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat'); |
| |
| canvas.width = 0; |
| canvas.height = 0; |
| @assert canvas.width === 0; |
| @assert canvas.height === 0; |
| @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat'); |
| |
| - 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 = '#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.image.undefined |
| testing: |
| - 2d.pattern.IDL |
| notes: *bindings |
| code: | |
| @assert throws TypeError ctx.createPattern(undefined, 'repeat'); |
| |
| - name: 2d.pattern.image.null |
| testing: |
| - 2d.pattern.IDL |
| notes: *bindings |
| code: | |
| @assert throws TypeError ctx.createPattern(null, 'repeat'); |
| |
| - name: 2d.pattern.image.string |
| testing: |
| - 2d.pattern.IDL |
| notes: *bindings |
| code: | |
| @assert throws TypeError ctx.createPattern('../images/red.png', 'repeat'); |
| |
| - name: 2d.pattern.image.incomplete.nosrc |
| testing: |
| - 2d.pattern.incomplete.image |
| mozilla: { throws } |
| code: | |
| var img = new Image(); |
| @assert ctx.createPattern(img, 'repeat') === null; |
| |
| - name: 2d.pattern.image.incomplete.immediate |
| testing: |
| - 2d.pattern.incomplete.image |
| images: |
| - red.png |
| code: | |
| var img = new Image(); |
| img.src = '../images/red.png'; |
| // This triggers the "update the image data" algorithm. |
| // The image will not go to the "completely available" state |
| // until a fetch task in the networking task source is processed, |
| // so the image must not be fully decodable yet: |
| @assert ctx.createPattern(img, 'repeat') === null; @moz-todo |
| |
| - name: 2d.pattern.image.incomplete.reload |
| testing: |
| - 2d.pattern.incomplete.image |
| images: |
| - yellow.png |
| - red.png |
| code: | |
| var img = document.getElementById('yellow.png'); |
| img.src = '../images/red.png'; |
| // This triggers the "update the image data" algorithm, |
| // and resets the image to the "unavailable" state. |
| // The image will not go to the "completely available" state |
| // until a fetch task in the networking task source is processed, |
| // so the image must not be fully decodable yet: |
| @assert ctx.createPattern(img, 'repeat') === null; @moz-todo |
| |
| - name: 2d.pattern.image.incomplete.emptysrc |
| testing: |
| - 2d.pattern.incomplete.image |
| images: |
| - red.png |
| mozilla: { throws } |
| code: | |
| var img = document.getElementById('red.png'); |
| img.src = ""; |
| @assert ctx.createPattern(img, 'repeat') === null; |
| |
| - name: 2d.pattern.image.incomplete.removedsrc |
| testing: |
| - 2d.pattern.incomplete.image |
| images: |
| - red.png |
| mozilla: { throws } |
| code: | |
| var img = document.getElementById('red.png'); |
| img.removeAttribute('src'); |
| @assert ctx.createPattern(img, 'repeat') === null; |
| |
| - name: 2d.pattern.image.broken |
| testing: |
| - 2d.pattern.incomplete.image |
| images: |
| - broken.png |
| code: | |
| var img = document.getElementById('broken.png'); |
| @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat'); |
| |
| - 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.unrecognised |
| code: | |
| @assert ctx.createPattern(canvas, null) != null; |
| |
| - name: 2d.pattern.repeat.undefined |
| testing: |
| - 2d.pattern.unrecognised |
| code: | |
| @assert throws SYNTAX_ERR ctx.createPattern(canvas, undefined); |
| |
| - name: 2d.pattern.repeat.unrecognised |
| testing: |
| - 2d.pattern.unrecognised |
| code: | |
| @assert throws SYNTAX_ERR ctx.createPattern(canvas, "invalid"); |
| |
| - name: 2d.pattern.repeat.unrecognisednull |
| testing: |
| - 2d.pattern.unrecognised |
| code: | |
| @assert throws SYNTAX_ERR ctx.createPattern(canvas, "null"); |
| |
| - 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 = t.step_func_done(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 = t.step_func_done(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 |
| 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.norepeat.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 |
| 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; |
| @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.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 |
| 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; |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.pattern.paint.repeatx.coord1 |
| testing: |
| - 2d.pattern.painting |
| 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; |
| @assert pixel 98,1 == 0,255,0,255; |
| @assert pixel 1,25 == 0,255,0,255; |
| @assert pixel 98,25 == 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.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 |
| 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; |
| @assert pixel 1,48 == 0,255,0,255; |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.pattern.paint.repeaty.coord1 |
| testing: |
| - 2d.pattern.painting |
| 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; |
| @assert pixel 50,1 == 0,255,0,255; |
| @assert pixel 98,1 == 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.paint.orientation.image |
| desc: Image patterns do not get flipped when painted |
| testing: |
| - 2d.pattern.painting |
| images: |
| - rrgg-256x256.png |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| var img = document.getElementById('rrgg-256x256.png'); |
| var pattern = ctx.createPattern(img, 'no-repeat'); |
| ctx.fillStyle = pattern; |
| ctx.save(); |
| ctx.translate(0, -103); |
| ctx.fillRect(0, 103, 100, 50); |
| ctx.restore(); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 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.orientation.canvas |
| desc: Canvas patterns do not get flipped when painted |
| 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 = '#f00'; |
| ctx2.fillRect(0, 0, 100, 25); |
| ctx2.fillStyle = '#0f0'; |
| ctx2.fillRect(0, 25, 100, 25); |
| |
| var pattern = ctx.createPattern(canvas2, 'no-repeat'); |
| ctx.fillStyle = pattern; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 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.animated.gif |
| desc: createPattern() of an animated GIF draws the first frame |
| testing: |
| - 2d.pattern.animated.image |
| images: |
| - anim-gr.gif |
| code: | |
| deferTest(); |
| setTimeout(function () { |
| var pattern = ctx.createPattern(document.getElementById('anim-gr.gif'), 'repeat'); |
| ctx.fillStyle = pattern; |
| ctx.fillRect(0, 0, 50, 50); |
| setTimeout(t.step_func_done(function () { |
| ctx.fillRect(50, 0, 50, 50); |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| }), 250); |
| }, 250); |
| 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; |
| |
| - name: 2d.line.width.basic |
| desc: lineWidth determines the width of line strokes |
| 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.width.transformed |
| desc: Line stroke widths are affected by scale transformations |
| 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.width.scaledefault |
| desc: Default lineWidth strokes are affected by scale transformations |
| testing: |
| - 2d.lineWidth |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.scale(50, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.moveTo(0, 0.5); |
| ctx.lineTo(2, 0.5); |
| ctx.stroke(); |
| |
| @assert pixel 25,25 == 0,255,0,255; |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 75,25 == 0,255,0,255; |
| @assert pixel 50,5 == 0,255,0,255; |
| @assert pixel 50,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.line.width.valid |
| desc: Setting lineWidth to valid values works |
| testing: |
| - 2d.lineWidth.set |
| - 2d.lineWidth.get |
| code: | |
| ctx.lineWidth = 1.5; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = "1e1"; |
| @assert ctx.lineWidth === 10; |
| |
| ctx.lineWidth = 1/1024; |
| @assert ctx.lineWidth === 1/1024; |
| |
| ctx.lineWidth = 1000; |
| @assert ctx.lineWidth === 1000; |
| |
| - name: 2d.line.width.invalid |
| desc: Setting lineWidth to invalid values is ignored |
| testing: |
| - 2d.lineWidth.invalid |
| code: | |
| ctx.lineWidth = 1.5; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = 1.5; |
| ctx.lineWidth = 0; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = 1.5; |
| ctx.lineWidth = -1; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = 1.5; |
| ctx.lineWidth = Infinity; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = 1.5; |
| ctx.lineWidth = -Infinity; |
| @assert ctx.lineWidth === 1.5; |
| |
| ctx.lineWidth = 1.5; |
| ctx.lineWidth = NaN; |
| @assert ctx.lineWidth === 1.5; |
| |
| - name: 2d.line.cap.butt |
| desc: lineCap 'butt' is rendered correctly |
| 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.cap.round |
| desc: lineCap 'round' is rendered correctly |
| 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.cap.square |
| desc: lineCap 'square' is rendered correctly |
| 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.cap.open |
| desc: Line caps are drawn at the corners of an unclosed rectangle |
| testing: |
| - 2d.lineCap.end |
| 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 |
| desc: Line caps are not drawn at the corners of an unclosed rectangle |
| testing: |
| - 2d.lineCap.end |
| 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.valid |
| desc: Setting lineCap to valid values works |
| testing: |
| - 2d.lineCap.set |
| - 2d.lineCap.get |
| code: | |
| ctx.lineCap = 'butt' |
| @assert ctx.lineCap === 'butt'; |
| |
| ctx.lineCap = 'round'; |
| @assert ctx.lineCap === 'round'; |
| |
| ctx.lineCap = 'square'; |
| @assert ctx.lineCap === 'square'; |
| |
| - name: 2d.line.cap.invalid |
| desc: Setting lineCap to invalid values is ignored |
| testing: |
| - 2d.lineCap.invalid |
| 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'; |
| |
| - name: 2d.line.join.bevel |
| desc: lineJoin 'bevel' is rendered correctly |
| testing: |
| - 2d.lineJoin.common |
| - 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.join.round |
| desc: lineJoin 'round' is rendered correctly |
| 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.join.miter |
| desc: lineJoin 'miter' is rendered correctly |
| 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 |
| desc: Line joins are not drawn at the corner of an unclosed rectangle |
| testing: |
| - 2d.lineJoin.joins |
| 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 |
| desc: Line joins are drawn at the corner of a closed rectangle |
| testing: |
| - 2d.lineJoin.joinclosed |
| 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.parallel |
| desc: Line joins are drawn at 180-degree joins |
| testing: |
| - 2d.lineJoin.joins |
| 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.join.valid |
| desc: Setting lineJoin to valid values works |
| testing: |
| - 2d.lineJoin.set |
| - 2d.lineJoin.get |
| code: | |
| ctx.lineJoin = 'bevel' |
| @assert ctx.lineJoin === 'bevel'; |
| |
| ctx.lineJoin = 'round'; |
| @assert ctx.lineJoin === 'round'; |
| |
| ctx.lineJoin = 'miter'; |
| @assert ctx.lineJoin === 'miter'; |
| |
| - name: 2d.line.join.invalid |
| desc: Setting lineJoin to invalid values is ignored |
| 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'; |
| |
| - name: 2d.line.miter.exceeded |
| desc: Miter joins are not drawn when the miter limit is exceeded |
| testing: |
| - 2d.lineJoin.miterLimit |
| - 2d.lineJoin.miter |
| 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); // slightly non-right-angle to avoid being a special case |
| 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.acute |
| desc: Miter joins are drawn correctly with acute angles |
| testing: |
| - 2d.lineJoin.miterLimit |
| - 2d.lineJoin.miter |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.lineWidth = 200; |
| ctx.lineJoin = 'miter'; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.miterLimit = 2.614; |
| ctx.beginPath(); |
| ctx.moveTo(100, 1000); |
| ctx.lineTo(100, 100); |
| ctx.lineTo(1000, 1000); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.miterLimit = 2.613; |
| ctx.beginPath(); |
| ctx.moveTo(100, 1000); |
| ctx.lineTo(100, 100); |
| ctx.lineTo(1000, 1000); |
| 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.obtuse |
| desc: Miter joins are drawn correctly with obtuse angles |
| testing: |
| - 2d.lineJoin.miterLimit |
| - 2d.lineJoin.miter |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.lineWidth = 1600; |
| ctx.lineJoin = 'miter'; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.miterLimit = 1.083; |
| ctx.beginPath(); |
| ctx.moveTo(800, 10000); |
| ctx.lineTo(800, 300); |
| ctx.lineTo(10000, -8900); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.miterLimit = 1.082; |
| ctx.beginPath(); |
| ctx.moveTo(800, 10000); |
| ctx.lineTo(800, 300); |
| ctx.lineTo(10000, -8900); |
| 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 |
| desc: Miter joins are not drawn when the miter limit is exceeded, on exact right angles |
| testing: |
| - 2d.lineJoin.miter |
| 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, 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.miter.lineedge |
| desc: Miter joins are not drawn when the miter limit is exceeded at the corners of a zero-height rectangle |
| testing: |
| - 2d.lineJoin.miter |
| code: | |
| 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; |
| @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.within |
| desc: Miter joins are drawn when the miter limit is not quite exceeded |
| testing: |
| - 2d.lineJoin.miter |
| 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.miter.valid |
| desc: Setting miterLimit to valid values works |
| testing: |
| - 2d.miterLimit.set |
| - 2d.miterLimit.get |
| code: | |
| ctx.miterLimit = 1.5; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = "1e1"; |
| @assert ctx.miterLimit === 10; |
| |
| ctx.miterLimit = 1/1024; |
| @assert ctx.miterLimit === 1/1024; |
| |
| ctx.miterLimit = 1000; |
| @assert ctx.miterLimit === 1000; |
| |
| - name: 2d.line.miter.invalid |
| desc: Setting miterLimit to invalid values is ignored |
| testing: |
| - 2d.miterLimit.invalid |
| code: | |
| ctx.miterLimit = 1.5; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = 1.5; |
| ctx.miterLimit = 0; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = 1.5; |
| ctx.miterLimit = -1; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = 1.5; |
| ctx.miterLimit = Infinity; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = 1.5; |
| ctx.miterLimit = -Infinity; |
| @assert ctx.miterLimit === 1.5; |
| |
| ctx.miterLimit = 1.5; |
| ctx.miterLimit = NaN; |
| @assert ctx.miterLimit === 1.5; |
| |
| - 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.shadow.attributes.shadowBlur.initial |
| testing: |
| - 2d.shadow.blur.get |
| - 2d.shadow.blur.initial |
| code: | |
| @assert ctx.shadowBlur === 0; |
| |
| - name: 2d.shadow.attributes.shadowBlur.valid |
| testing: |
| - 2d.shadow.blur.get |
| - 2d.shadow.blur.set |
| 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 = 0; |
| @assert ctx.shadowBlur === 0; |
| |
| - name: 2d.shadow.attributes.shadowBlur.invalid |
| testing: |
| - 2d.shadow.blur.invalid |
| code: | |
| ctx.shadowBlur = 1; |
| ctx.shadowBlur = -2; |
| @assert ctx.shadowBlur === 1; |
| |
| ctx.shadowBlur = 1; |
| ctx.shadowBlur = Infinity; |
| @assert ctx.shadowBlur === 1; |
| |
| ctx.shadowBlur = 1; |
| ctx.shadowBlur = -Infinity; |
| @assert ctx.shadowBlur === 1; |
| |
| ctx.shadowBlur = 1; |
| ctx.shadowBlur = NaN; |
| @assert ctx.shadowBlur === 1; |
| |
| - name: 2d.shadow.attributes.shadowOffset.initial |
| testing: |
| - 2d.shadow.offset.initial |
| code: | |
| @assert ctx.shadowOffsetX === 0; |
| @assert ctx.shadowOffsetY === 0; |
| |
| - name: 2d.shadow.attributes.shadowOffset.valid |
| testing: |
| - 2d.shadow.offset.get |
| - 2d.shadow.offset.set |
| 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 = 0; |
| ctx.shadowOffsetY = 0; |
| @assert ctx.shadowOffsetX === 0; |
| @assert ctx.shadowOffsetY === 0; |
| |
| ctx.shadowOffsetX = 1e6; |
| ctx.shadowOffsetY = 1e6; |
| @assert ctx.shadowOffsetX === 1e6; |
| @assert ctx.shadowOffsetY === 1e6; |
| |
| - name: 2d.shadow.attributes.shadowOffset.invalid |
| testing: |
| - 2d.shadow.offset.invalid |
| code: | |
| ctx.shadowOffsetX = 1; |
| ctx.shadowOffsetY = 2; |
| ctx.shadowOffsetX = Infinity; |
| ctx.shadowOffsetY = Infinity; |
| @assert ctx.shadowOffsetX === 1; |
| @assert ctx.shadowOffsetY === 2; |
| |
| ctx.shadowOffsetX = 1; |
| ctx.shadowOffsetY = 2; |
| ctx.shadowOffsetX = -Infinity; |
| ctx.shadowOffsetY = -Infinity; |
| @assert ctx.shadowOffsetX === 1; |
| @assert ctx.shadowOffsetY === 2; |
| |
| ctx.shadowOffsetX = 1; |
| ctx.shadowOffsetY = 2; |
| ctx.shadowOffsetX = NaN; |
| ctx.shadowOffsetY = NaN; |
| @assert ctx.shadowOffsetX === 1; |
| @assert ctx.shadowOffsetY === 2; |
| |
| - name: 2d.shadow.attributes.shadowColor.initial |
| testing: |
| - 2d.shadow.color.initial |
| code: | |
| @assert ctx.shadowColor === 'rgba(0, 0, 0, 0)'; |
| |
| - name: 2d.shadow.attributes.shadowColor.valid |
| testing: |
| - 2d.shadow.color.get |
| - 2d.shadow.color.set |
| code: | |
| ctx.shadowColor = 'lime'; |
| @assert ctx.shadowColor === '#00ff00'; |
| |
| ctx.shadowColor = 'RGBA(0,255, 0,0)'; |
| @assert ctx.shadowColor === 'rgba(0, 255, 0, 0)'; |
| |
| - name: 2d.shadow.attributes.shadowColor.invalid |
| testing: |
| - 2d.shadow.color.invalid |
| code: | |
| ctx.shadowColor = '#00ff00'; |
| ctx.shadowColor = 'bogus'; |
| @assert ctx.shadowColor === '#00ff00'; |
| |
| ctx.shadowColor = '#00ff00'; |
| ctx.shadowColor = 'red bogus'; |
| @assert ctx.shadowColor === '#00ff00'; |
| |
| ctx.shadowColor = '#00ff00'; |
| ctx.shadowColor = ctx; |
| @assert ctx.shadowColor === '#00ff00'; |
| |
| ctx.shadowColor = '#00ff00'; |
| ctx.shadowColor = undefined; |
| @assert ctx.shadowColor === '#00ff00'; |
| |
| - name: 2d.shadow.enable.off.1 |
| desc: Shadows are not drawn when only shadowColor is set |
| testing: |
| - 2d.shadow.enable |
| - 2d.shadow.render |
| 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.enable.off.2 |
| desc: Shadows are not drawn when only shadowColor is set |
| testing: |
| - 2d.shadow.enable |
| - 2d.shadow.render |
| code: | |
| ctx.globalCompositeOperation = 'destination-atop'; |
| 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.enable.blur |
| desc: Shadows are drawn if shadowBlur is set |
| testing: |
| - 2d.shadow.enable |
| - 2d.shadow.render |
| code: | |
| ctx.globalCompositeOperation = 'destination-atop'; |
| ctx.shadowColor = '#0f0'; |
| ctx.shadowBlur = 0.1; |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.shadow.enable.x |
| desc: Shadows are drawn if shadowOffsetX is set |
| testing: |
| - 2d.shadow.enable |
| - 2d.shadow.render |
| code: | |
| ctx.globalCompositeOperation = 'destination-atop'; |
| ctx.shadowColor = '#0f0'; |
| ctx.shadowOffsetX = 0.1; |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.shadow.enable.y |
| desc: Shadows are drawn if shadowOffsetY is set |
| testing: |
| - 2d.shadow.enable |
| - 2d.shadow.render |
| code: | |
| ctx.globalCompositeOperation = 'destination-atop'; |
| ctx.shadowColor = '#0f0'; |
| ctx.shadowOffsetY = 0.1; |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.shadow.offset.positiveX |
| desc: Shadows can be offset with positive x |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows can be offset with negative x |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows can be offset with positive y |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows can be offset with negative y |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows of shapes outside the visible area can be offset onto the visible area |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows of clipped shapes are still drawn within the clipping region |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn outside the clipping region |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows of clipped shapes are still drawn within the clipping region |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for strokes |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for areas outside stroke caps |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for stroke caps |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for areas outside stroke joins |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for stroke joins |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for stroke joins respecting miter limit |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for images |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for transparent images |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for transparent parts of images |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn correctly for partially-transparent images |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for areas outside image source rectangles |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn correctly for scaled images |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for canvases |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for transparent canvases |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are not drawn for transparent parts of canvases |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn correctly for partially-transparent canvases |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn for fill patterns |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are not drawn for transparent fill patterns |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are not drawn for transparent parts of fill patterns |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are drawn correctly for partially-transparent fill patterns |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are drawn for gradient fills |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are not drawn for transparent gradient fills |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are not drawn for transparent parts of gradient fills |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows are drawn correctly for partially-transparent gradient fills |
| testing: |
| - 2d.shadow.render |
| # http://bugs.webkit.org/show_bug.cgi?id=15266 |
| 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 |
| desc: Shadows take account of transformations |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadow offsets are not affected by transformations |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows look correct for small blurs |
| manual: |
| testing: |
| - 2d.shadow.render |
| 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): |
| sigma = x/2.0 |
| 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 |
| desc: Shadows look correct for large blurs |
| manual: |
| testing: |
| - 2d.shadow.render |
| code: | |
| ctx.fillStyle = '#ff0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.shadowColor = '#00f'; |
| ctx.shadowOffsetY = 0; |
| ctx.shadowBlur = 100; |
| ctx.fillRect(-200, -200, 200, 400); |
| expected: | |
| size 100 50 |
| import math |
| sigma = 100.0/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 |
| desc: Shadow colour alpha components are used |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadow colour alpha components are used |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are affected by globalAlpha |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows with alpha components are correctly affected by globalAlpha |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows of shapes with alpha components are drawn correctly |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn using globalCompositeOperation |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Shadows are drawn using globalCompositeOperation |
| testing: |
| - 2d.shadow.render |
| 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 |
| desc: Areas outside shadows are drawn correctly with destination-out |
| testing: |
| - 2d.shadow.render |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.globalCompositeOperation = 'destination-out'; |
| ctx.shadowColor = '#f00'; |
| ctx.shadowBlur = 10; |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(200, 0, 100, 50); |
| |
| @assert pixel 5,5 ==~ 0,255,0,255; |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| |
| |
| |
| |
| |
| - name: 2d.clearRect.basic |
| desc: clearRect clears to transparent black |
| testing: |
| - 2d.clearRect |
| 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: clear |
| |
| - name: 2d.clearRect.path |
| desc: clearRect does not affect the current path |
| testing: |
| - 2d.clearRect |
| 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 |
| desc: clearRect of zero pixels has no effect |
| testing: |
| - 2d.clearRect |
| 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.negative |
| desc: clearRect of negative sizes works |
| testing: |
| - 2d.clearRect |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.clearRect(0, 0, 50, 25); |
| ctx.clearRect(100, 0, -50, 25); |
| ctx.clearRect(0, 50, 50, -25); |
| ctx.clearRect(100, 50, -50, -25); |
| @assert pixel 25,12 == 0,0,0,0; |
| @assert pixel 75,12 == 0,0,0,0; |
| @assert pixel 25,37 == 0,0,0,0; |
| @assert pixel 75,37 == 0,0,0,0; |
| expected: clear |
| |
| - name: 2d.clearRect.transform |
| desc: clearRect is affected by transforms |
| testing: |
| - 2d.clearRect |
| 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: clear |
| |
| - name: 2d.clearRect.globalalpha |
| desc: clearRect is not affected by globalAlpha |
| testing: |
| - 2d.clearRect |
| 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: clear |
| |
| - name: 2d.clearRect.globalcomposite |
| desc: clearRect is not affected by globalCompositeOperation |
| testing: |
| - 2d.clearRect |
| 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: clear |
| |
| - name: 2d.clearRect.clip |
| desc: clearRect is affected by clipping regions |
| testing: |
| - 2d.clearRect |
| 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 |
| desc: clearRect does not draw shadows |
| testing: |
| - 2d.clearRect |
| 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.clearRect.nonfinite |
| desc: clearRect() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| @nonfinite ctx.clearRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.fillRect.basic |
| desc: fillRect works |
| testing: |
| - 2d.fillRect |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.fillRect.path |
| desc: fillRect does not affect the current path |
| testing: |
| - 2d.fillRect |
| 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 |
| desc: fillRect of zero pixels has no effect |
| testing: |
| - 2d.fillRect |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.fillRect.negative |
| desc: fillRect of negative sizes works |
| testing: |
| - 2d.fillRect |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 50, 25); |
| ctx.fillRect(100, 0, -50, 25); |
| ctx.fillRect(0, 50, 50, -25); |
| ctx.fillRect(100, 50, -50, -25); |
| @assert pixel 25,12 == 0,255,0,255; |
| @assert pixel 75,12 == 0,255,0,255; |
| @assert pixel 25,37 == 0,255,0,255; |
| @assert pixel 75,37 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.fillRect.transform |
| desc: fillRect is affected by transforms |
| testing: |
| - 2d.fillRect |
| 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 |
| desc: fillRect is affected by clipping regions |
| 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 |
| desc: fillRect draws shadows |
| testing: |
| - 2d.fillRect |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.shadowColor = '#0f0'; |
| ctx.shadowBlur = 0; |
| ctx.shadowOffsetX = 0; |
| ctx.shadowOffsetY = 50; |
| ctx.fillRect(0, -50, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.fillRect.nonfinite |
| desc: fillRect() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.fillStyle = '#f00'; |
| @nonfinite ctx.fillRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.strokeRect.basic |
| desc: strokeRect works |
| testing: |
| - 2d.strokeRect |
| 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 |
| desc: strokeRect does not affect the current path |
| testing: |
| - 2d.strokeRect |
| 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 |
| desc: strokeRect of 0x0 pixels draws nothing |
| testing: |
| - 2d.strokeRect |
| code: | |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 250; |
| ctx.strokeRect(50, 25, 0, 0); |
| @assert pixel 50,25 == 0,0,0,0; |
| expected: clear |
| |
| - name: 2d.strokeRect.zero.2 |
| desc: strokeRect of 0x0 pixels draws nothing, including caps and joins |
| testing: |
| - 2d.strokeRect |
| 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; |
| expected: clear |
| |
| - name: 2d.strokeRect.zero.3 |
| desc: strokeRect of Nx0 pixels draws a straight line |
| testing: |
| - 2d.strokeRect |
| 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 |
| desc: strokeRect of Nx0 pixels draws a closed line with no caps |
| testing: |
| - 2d.strokeRect |
| 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: clear |
| |
| - name: 2d.strokeRect.zero.5 |
| desc: strokeRect of Nx0 pixels draws a closed line with joins |
| testing: |
| - 2d.strokeRect |
| 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.negative |
| desc: strokeRect of negative sizes works |
| testing: |
| - 2d.strokeRect |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 25; |
| ctx.strokeRect(12, 12, 26, 1); |
| ctx.strokeRect(88, 12, -26, 1); |
| ctx.strokeRect(12, 38, 26, -1); |
| ctx.strokeRect(88, 38, -26, -1); |
| @assert pixel 25,12 == 0,255,0,255; |
| @assert pixel 75,12 == 0,255,0,255; |
| @assert pixel 25,37 == 0,255,0,255; |
| @assert pixel 75,37 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.strokeRect.transform |
| desc: fillRect is affected by transforms |
| testing: |
| - 2d.strokeRect |
| 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 |
| desc: strokeRect is affected by globalAlpha |
| testing: |
| - 2d.strokeRect |
| 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: clear |
| |
| - name: 2d.strokeRect.globalcomposite |
| desc: strokeRect is not affected by globalCompositeOperation |
| testing: |
| - 2d.strokeRect |
| 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: clear |
| |
| - name: 2d.strokeRect.clip |
| desc: strokeRect is affected by clipping regions |
| 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 |
| desc: strokeRect draws shadows |
| testing: |
| - 2d.strokeRect |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#f00'; |
| ctx.shadowColor = '#0f0'; |
| ctx.shadowBlur = 0; |
| ctx.shadowOffsetX = 0; |
| ctx.shadowOffsetY = 50; |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.strokeRect(0, -75, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.strokeRect.nonfinite |
| desc: strokeRect() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 150; |
| @nonfinite ctx.strokeRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.path.initial |
| testing: |
| - 2d.path.initial |
| #mozilla: { bug: TODO } |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.closePath(); |
| ctx.fillStyle = '#f00'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.beginPath |
| testing: |
| - 2d.path.beginPath |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.rect(0, 0, 100, 50); |
| ctx.beginPath(); |
| ctx.fillStyle = '#f00'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.moveTo.basic |
| testing: |
| - 2d.path.moveTo |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.moveTo.multiple |
| testing: |
| - 2d.path.moveTo |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.moveTo.nonfinite |
| desc: moveTo() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.moveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.closePath.empty |
| testing: |
| - 2d.path.closePath.empty |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.closePath(); |
| ctx.fillStyle = '#f00'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.closePath.newline |
| testing: |
| - 2d.path.closePath.nonempty |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.ensuresubpath.1 |
| desc: If there is no subpath, the point is added and nothing is drawn |
| testing: |
| - 2d.path.lineTo.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.lineTo(100, 50); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.lineTo.ensuresubpath.2 |
| desc: If there is no subpath, the point is added and used for subsequent drawing |
| testing: |
| - 2d.path.lineTo.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.lineTo(0, 25); |
| ctx.lineTo(100, 25); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.lineTo.basic |
| testing: |
| - 2d.path.lineTo.nonempty |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.lineTo.nonfinite |
| desc: lineTo() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.lineTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.quadraticCurveTo.ensuresubpath.1 |
| desc: If there is no subpath, the first control point is added (and nothing is drawn up to it) |
| testing: |
| - 2d.path.quadratic.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.quadraticCurveTo(100, 50, 200, 50); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 95,45 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.quadraticCurveTo.ensuresubpath.2 |
| desc: If there is no subpath, the first control point is added |
| testing: |
| - 2d.path.quadratic.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.quadraticCurveTo(0, 25, 100, 25); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 5,45 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.quadraticCurveTo.basic |
| testing: |
| - 2d.path.quadratic.nonempty |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.quadraticCurveTo.nonfinite |
| desc: quadraticCurveTo() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.quadraticCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.bezierCurveTo.ensuresubpath.1 |
| desc: If there is no subpath, the first control point is added (and nothing is drawn up to it) |
| testing: |
| - 2d.path.bezier.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.bezierCurveTo(100, 50, 200, 50, 200, 50); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 95,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.bezierCurveTo.ensuresubpath.2 |
| desc: If there is no subpath, the first control point is added |
| testing: |
| - 2d.path.bezier.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.bezierCurveTo(0, 25, 100, 25, 100, 25); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 5,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.bezierCurveTo.basic |
| testing: |
| - 2d.path.bezier.nonempty |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.bezierCurveTo.nonfinite |
| desc: bezierCurveTo() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.bezierCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.ensuresubpath.1 |
| desc: If there is no subpath, the first control point is added (and nothing is drawn up to it) |
| testing: |
| - 2d.path.arcTo.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.arcTo(100, 50, 200, 50, 0.1); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.ensuresubpath.2 |
| desc: If there is no subpath, the first control point is added |
| testing: |
| - 2d.path.arcTo.empty |
| - 2d.path.ensure |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.arcTo(0, 25, 50, 250, 0.1); // adds (x1,y1), draws nothing |
| ctx.lineTo(100, 25); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.coincide.1 |
| desc: arcTo() has no effect if P0 = P1 |
| testing: |
| - 2d.path.arcTo.coincide.01 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(0, 25, 50, 1000, 1); |
| ctx.lineTo(100, 25); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.arcTo(50, 25, 100, 25, 1); |
| ctx.stroke(); |
| |
| @assert pixel 50,1 == 0,255,0,255; |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 50,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.coincide.2 |
| desc: arcTo() draws a straight line to P1 if P1 = P2 |
| testing: |
| - 2d.path.arcTo.coincide.12 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| ctx.strokeStyle = '#0f0'; |
| 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 |
| desc: arcTo() with all points on a line, and P1 between P0/P2, draws a straight line to P1 |
| testing: |
| - 2d.path.arcTo.collinear |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(100, 25, 200, 25, 1); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(-100, 25); |
| ctx.arcTo(0, 25, 100, 25, 1); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.collinear.2 |
| desc: arcTo() with all points on a line, and P2 between P0/P1, draws a straight line to P1 |
| testing: |
| - 2d.path.arcTo.collinear |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(100, 25, 10, 25, 1); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(100, 25); |
| ctx.arcTo(200, 25, 110, 25, 1); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.collinear.3 |
| desc: arcTo() with all points on a line, and P0 between P1/P2, draws a straight line to P1 |
| testing: |
| - 2d.path.arcTo.collinear |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(100, 25, -100, 25, 1); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(100, 25); |
| ctx.arcTo(200, 25, 0, 25, 1); |
| ctx.stroke(); |
| |
| ctx.beginPath(); |
| ctx.moveTo(-100, 25); |
| ctx.arcTo(0, 25, -200, 25, 1); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.shape.curve1 |
| desc: arcTo() curves in the right kind of shape |
| testing: |
| - 2d.path.arcTo.shape |
| code: | |
| var tol = 1.5; // 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; |
| @assert pixel 65,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.shape.curve2 |
| desc: arcTo() curves in the right kind of shape |
| testing: |
| - 2d.path.arcTo.shape |
| code: | |
| var tol = 1.5; // 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 |
| desc: arcTo() draws a straight line from P0 to P1 |
| testing: |
| - 2d.path.arcTo.shape |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(200, 25, 200, 50, 10); |
| ctx.stroke(); |
| |
| @assert pixel 1,1 == 0,255,0,255; |
| @assert pixel 1,48 == 0,255,0,255; |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 98,1 == 0,255,0,255; |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.shape.end |
| desc: arcTo() does not draw anything from P1 to P2 |
| testing: |
| - 2d.path.arcTo.shape |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.beginPath(); |
| ctx.moveTo(-100, -100); |
| ctx.arcTo(-100, 25, 200, 25, 10); |
| ctx.stroke(); |
| |
| @assert pixel 1,1 == 0,255,0,255; |
| @assert pixel 1,48 == 0,255,0,255; |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 98,1 == 0,255,0,255; |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.negative |
| desc: arcTo() with negative radius throws an exception |
| testing: |
| - 2d.path.arcTo.negative |
| code: | |
| @assert throws INDEX_SIZE_ERR ctx.arcTo(0, 0, 0, 0, -1); |
| |
| - name: 2d.path.arcTo.zero.1 |
| desc: arcTo() with zero radius draws a straight line from P0 to P1 |
| testing: |
| - 2d.path.arcTo.zeroradius |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(100, 25, 100, 100, 0); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(0, -25); |
| ctx.arcTo(50, -25, 50, 50, 0); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arcTo.zero.2 |
| desc: arcTo() with zero radius draws a straight line from P0 to P1, even when all points are collinear |
| testing: |
| - 2d.path.arcTo.zeroradius |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arcTo(100, 25, -100, 25, 0); |
| ctx.stroke(); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(100, 25); |
| ctx.arcTo(200, 25, 50, 25, 0); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 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.arcTo.nonfinite |
| desc: arcTo() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.arcTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.path.arc.empty |
| desc: arc() with an empty path does not draw a straight line to the start point |
| testing: |
| - 2d.path.arc.nonempty |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.nonempty |
| desc: arc() with a non-empty path does draw a straight line to the start point |
| testing: |
| - 2d.path.arc.nonempty |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| desc: arc() adds the end point of the arc to the subpath |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.default |
| desc: arc() with missing last argument defaults to clockwise |
| testing: |
| - 2d.path.arc.omitted |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(100, 0); |
| ctx.arc(100, 0, 150, -Math.PI, Math.PI/2); |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.angle.1 |
| desc: arc() draws pi/2 .. -pi anticlockwise correctly |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.angle.2 |
| desc: arc() draws -3pi/2 .. -pi anticlockwise correctly |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.angle.3 |
| desc: arc() wraps angles mod 2pi when anticlockwise and end > start+2pi |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.angle.4 |
| desc: arc() draws a full circle when clockwise and end > start+2pi |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.arc(50, 25, 60, (512+1/2)*Math.PI, (1024-1)*Math.PI, false); |
| ctx.fill(); |
| @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.arc.angle.5 |
| desc: arc() wraps angles mod 2pi when clockwise and start > end+2pi |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.moveTo(100, 0); |
| ctx.arc(100, 0, 150, (1024-1)*Math.PI, (512+1/2)*Math.PI, false); |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.angle.6 |
| desc: arc() draws a full circle when anticlockwise and start > end+2pi |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.arc(50, 25, 60, (1024-1)*Math.PI, (512+1/2)*Math.PI, true); |
| ctx.fill(); |
| @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.arc.zero.1 |
| desc: arc() draws nothing when startAngle = endAngle and anticlockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.beginPath(); |
| ctx.arc(50, 25, 50, 0, 0, true); |
| ctx.stroke(); |
| @assert pixel 50,20 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.zero.2 |
| desc: arc() draws nothing when startAngle = endAngle and clockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.beginPath(); |
| ctx.arc(50, 25, 50, 0, 0, false); |
| ctx.stroke(); |
| @assert pixel 50,20 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.twopie.1 |
| desc: arc() draws nothing when end = start + 2pi-e and anticlockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.twopie.2 |
| desc: arc() draws a full circle when end = start + 2pi-e and clockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.twopie.3 |
| desc: arc() draws a full circle when end = start + 2pi+e and anticlockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.twopie.4 |
| desc: arc() draws nothing when end = start + 2pi+e and clockwise |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| desc: arc() from 0 to pi does not draw anything in the wrong half |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| ctx.strokeStyle = '#f00'; |
| ctx.beginPath(); |
| ctx.arc(50, 50, 50, 0, Math.PI, false); |
| 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.2 |
| desc: arc() from 0 to pi draws stuff in the right half |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| desc: arc() from 0 to -pi/2 does not draw anything in the wrong quadrant |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,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; @moz-todo |
| @assert pixel 98,48 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.shape.4 |
| desc: arc() from 0 to -pi/2 draws stuff in the right quadrant |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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; |
| @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.arc.shape.5 |
| desc: arc() from 0 to 5pi does not draw crazy things |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,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.arc.selfintersect.1 |
| desc: arc() with lineWidth > 2*radius is drawn sensibly |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 1,1 == 0,255,0,255; @moz-todo |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.selfintersect.2 |
| desc: arc() with lineWidth > 2*radius is drawn sensibly |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| desc: arc() with negative radius throws INDEX_SIZE_ERR |
| testing: |
| - 2d.path.arc.negative |
| code: | |
| @assert throws INDEX_SIZE_ERR ctx.arc(0, 0, -1, 0, 0, true); |
| |
| - name: 2d.path.arc.zeroradius |
| desc: arc() with zero radius draws a line to the start point |
| testing: |
| - 2d.path.arc.zero |
| code: | |
| ctx.fillStyle = '#f00' |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.lineWidth = 50; |
| ctx.strokeStyle = '#0f0'; |
| ctx.beginPath(); |
| ctx.moveTo(0, 25); |
| ctx.arc(200, 25, 0, 0, Math.PI, true); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.arc.scale.1 |
| desc: Non-uniformly scaled arcs are the right shape |
| 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.arc.scale.2 |
| desc: Highly scaled arcs are the right shape |
| testing: |
| - 2d.path.arc.draw |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.scale(100, 100); |
| ctx.strokeStyle = '#0f0'; |
| ctx.lineWidth = 1.2; |
| ctx.beginPath(); |
| ctx.arc(0, 0, 0.6, 0, Math.PI/2, false); |
| ctx.stroke(); |
| |
| @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.path.arc.nonfinite |
| desc: arc() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.arc(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <2*Math.PI Infinity -Infinity NaN>, <true>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.path.rect.basic |
| testing: |
| - 2d.path.rect.subpath |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; |
| expected: green |
| |
| - name: 2d.path.rect.closed |
| testing: |
| - 2d.path.rect.closed |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.beginPath(); |
| ctx.rect(50, 25, 0, 0); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.rect.zero.4 |
| testing: |
| - 2d.path.rect.subpath |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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 |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.moveTo(0, 0); |
| ctx.rect(100, 25, 0, 0); |
| ctx.stroke(); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.rect.zero.6 |
| testing: |
| - 2d.path.rect.subpath |
| #mozilla: { bug: TODO } |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.rect.negative |
| testing: |
| - 2d.path.rect.subpath |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.beginPath(); |
| ctx.fillStyle = '#0f0'; |
| ctx.rect(0, 0, 50, 25); |
| ctx.rect(100, 0, -50, 25); |
| ctx.rect(0, 50, 50, -25); |
| ctx.rect(100, 50, -50, -25); |
| ctx.fill(); |
| @assert pixel 25,12 == 0,255,0,255; |
| @assert pixel 75,12 == 0,255,0,255; |
| @assert pixel 25,37 == 0,255,0,255; |
| @assert pixel 75,37 == 0,255,0,255; |
| |
| - name: 2d.path.rect.winding |
| testing: |
| - 2d.path.rect.subpath |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.beginPath(); |
| ctx.fillStyle = '#f00'; |
| ctx.rect(0, 0, 50, 50); |
| ctx.rect(100, 50, -50, -50); |
| ctx.rect(0, 25, 100, -25); |
| ctx.rect(100, 25, -100, 25); |
| ctx.fill(); |
| @assert pixel 25,12 == 0,255,0,255; |
| @assert pixel 75,12 == 0,255,0,255; |
| @assert pixel 25,37 == 0,255,0,255; |
| @assert pixel 75,37 == 0,255,0,255; |
| |
| - name: 2d.path.rect.selfintersect |
| #mozilla: { bug: TODO } |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| 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.rect.nonfinite |
| desc: rect() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| code: | |
| ctx.moveTo(0, 0); |
| ctx.lineTo(100, 0); |
| @nonfinite ctx.rect(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>); |
| ctx.lineTo(100, 50); |
| ctx.lineTo(0, 50); |
| ctx.fillStyle = '#0f0'; |
| ctx.fill(); |
| @assert pixel 50,25 == 0,255,0,255; |
| @assert pixel 90,45 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.fill.overlap |
| testing: |
| - 2d.path.fill.basic |
| code: | |
| ctx.fillStyle = '#000'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.fillStyle = 'rgba(0, 255, 0, 0.5)'; |
| ctx.rect(0, 0, 100, 50); |
| ctx.closePath(); |
| ctx.rect(10, 10, 80, 30); |
| ctx.fill(); |
| |
| @assert pixel 50,25 ==~ 0,127,0,255 +/- 1; |
| expected: | |
| size 100 50 |
| cr.set_source_rgb(0, 0.5, 0) |
| cr.rectangle(0, 0, 100, 50) |
| cr.fill() |
| |
| - 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.overlap |
| desc: Stroked subpaths are combined before being drawn |
| testing: |
| - 2d.path.stroke.basic |
| code: | |
| ctx.fillStyle = '#000'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = 'rgba(0, 255, 0, 0.5)'; |
| ctx.lineWidth = 50; |
| ctx.moveTo(0, 20); |
| ctx.lineTo(100, 20); |
| ctx.moveTo(0, 30); |
| ctx.lineTo(100, 30); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 ==~ 0,127,0,255 +/- 1; |
| expected: | |
| size 100 50 |
| cr.set_source_rgb(0, 0.5, 0) |
| cr.rectangle(0, 0, 100, 50) |
| cr.fill() |
| |
| - 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.stroke.empty |
| desc: Empty subpaths are not stroked |
| testing: |
| - 2d.path.stroke.empty |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.moveTo(40, 25); |
| ctx.moveTo(60, 25); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.path.stroke.prune.line |
| desc: Zero-length line segments from lineTo are removed before stroking |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.lineTo(50, 25); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.stroke.prune.closed |
| desc: Zero-length line segments from closed paths are removed before stroking |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.lineTo(50, 25); |
| ctx.closePath(); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.stroke.prune.curve |
| desc: Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.quadraticCurveTo(50, 25, 50, 25); |
| ctx.stroke(); |
| |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.bezierCurveTo(50, 25, 50, 25, 50, 25); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.stroke.prune.arc |
| desc: Zero-length line segments from arcTo and arc are removed before stroking |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.moveTo(50, 25); |
| ctx.arcTo(50, 25, 150, 25, 10); |
| ctx.stroke(); |
| |
| ctx.beginPath(); |
| ctx.moveTo(60, 25); |
| ctx.arc(50, 25, 10, 0, 0, false); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.stroke.prune.rect |
| desc: Zero-length line segments from rect and strokeRect are removed before stroking |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 100; |
| ctx.lineCap = 'round'; |
| ctx.lineJoin = 'round'; |
| |
| ctx.beginPath(); |
| ctx.rect(50, 25, 0, 0); |
| ctx.stroke(); |
| |
| ctx.strokeRect(50, 25, 0, 0); |
| |
| @assert pixel 50,25 == 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.path.stroke.prune.corner |
| desc: Zero-length line segments are removed before stroking with miters |
| testing: |
| - 2d.path.stroke.prune |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 400; |
| ctx.lineJoin = 'miter'; |
| ctx.miterLimit = 1.4; |
| |
| ctx.beginPath(); |
| ctx.moveTo(-1000, 200); |
| ctx.lineTo(-100, 200); |
| ctx.lineTo(-100, 200); |
| ctx.lineTo(-100, 200); |
| ctx.lineTo(-100, 1000); |
| ctx.stroke(); |
| |
| @assert pixel 50,25 == 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 |
| # TODO: change this name |
| desc: Transformations are applied while building paths, not when drawing |
| testing: |
| - 2d.path.transformation |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| ctx.fillStyle = '#f00'; |
| ctx.translate(-100, 0); |
| ctx.rect(0, 0, 100, 50); |
| ctx.fill(); |
| ctx.translate(100, 0); |
| ctx.fill(); |
| |
| ctx.beginPath(); |
| ctx.strokeStyle = '#f00'; |
| ctx.lineWidth = 50; |
| ctx.translate(0, -50); |
| ctx.moveTo(0, 25); |
| ctx.lineTo(100, 25); |
| ctx.stroke(); |
| ctx.translate(0, 50); |
| ctx.stroke(); |
| |
| @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.moveTo(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.moveTo(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 |
| desc: isPointInPath() detects whether the point is inside the path |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.rect(0, 0, 20, 20); |
| @assert ctx.isPointInPath(10, 10) === true; |
| @assert ctx.isPointInPath(30, 10) === false; |
| |
| - name: 2d.path.isPointInPath.basic.2 |
| desc: isPointInPath() detects whether the point is inside the path |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.rect(20, 0, 20, 20); |
| @assert ctx.isPointInPath(10, 10) === false; |
| @assert ctx.isPointInPath(30, 10) === true; |
| |
| - name: 2d.path.isPointInPath.edge |
| desc: isPointInPath() counts points on the path as being inside |
| testing: |
| - 2d.path.isPointInPath.edge |
| code: | |
| ctx.rect(0, 0, 20, 20); |
| @assert ctx.isPointInPath(0, 0) === true; |
| @assert ctx.isPointInPath(10, 0) === true; |
| @assert ctx.isPointInPath(20, 0) === true; |
| @assert ctx.isPointInPath(20, 10) === true; |
| @assert ctx.isPointInPath(20, 20) === true; |
| @assert ctx.isPointInPath(10, 20) === true; |
| @assert ctx.isPointInPath(0, 20) === true; |
| @assert ctx.isPointInPath(0, 10) === true; |
| @assert ctx.isPointInPath(10, -0.01) === false; |
| @assert ctx.isPointInPath(10, 20.01) === false; |
| @assert ctx.isPointInPath(-0.01, 10) === false; |
| @assert ctx.isPointInPath(20.01, 10) === false; |
| |
| - name: 2d.path.isPointInPath.empty |
| desc: isPointInPath() works when there is no path |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| @assert ctx.isPointInPath(0, 0) === false; |
| |
| - name: 2d.path.isPointInPath.subpath |
| desc: isPointInPath() uses the current path, not just the subpath |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.rect(0, 0, 20, 20); |
| ctx.beginPath(); |
| ctx.rect(20, 0, 20, 20); |
| ctx.closePath(); |
| ctx.rect(40, 0, 20, 20); |
| @assert ctx.isPointInPath(10, 10) === false; |
| @assert ctx.isPointInPath(30, 10) === true; |
| @assert ctx.isPointInPath(50, 10) === true; |
| |
| - name: 2d.path.isPointInPath.outside |
| desc: isPointInPath() works on paths outside the canvas |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.rect(0, -100, 20, 20); |
| ctx.rect(20, -10, 20, 20); |
| @assert ctx.isPointInPath(10, -110) === false; |
| @assert ctx.isPointInPath(10, -90) === true; |
| @assert ctx.isPointInPath(10, -70) === false; |
| @assert ctx.isPointInPath(30, -20) === false; |
| @assert ctx.isPointInPath(30, 0) === true; |
| @assert ctx.isPointInPath(30, 20) === false; |
| |
| - name: 2d.path.isPointInPath.unclosed |
| desc: isPointInPath() works on unclosed subpaths |
| 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; |
| @assert ctx.isPointInPath(30, 10) === false; |
| |
| - name: 2d.path.isPointInPath.arc |
| desc: isPointInPath() works on arcs |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.arc(50, 25, 10, 0, Math.PI, false); |
| @assert ctx.isPointInPath(50, 10) === false; |
| @assert ctx.isPointInPath(50, 20) === false; |
| @assert ctx.isPointInPath(50, 30) === true; |
| @assert ctx.isPointInPath(50, 40) === false; |
| @assert ctx.isPointInPath(30, 20) === false; |
| @assert ctx.isPointInPath(70, 20) === false; |
| @assert ctx.isPointInPath(30, 30) === false; |
| @assert ctx.isPointInPath(70, 30) === false; |
| |
| - name: 2d.path.isPointInPath.bigarc |
| desc: isPointInPath() works on unclosed arcs larger than 2pi |
| opera: { bug: 320937 } |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.arc(50, 25, 10, 0, 7, false); |
| @assert ctx.isPointInPath(50, 10) === false; |
| @assert ctx.isPointInPath(50, 20) === true; |
| @assert ctx.isPointInPath(50, 30) === true; |
| @assert ctx.isPointInPath(50, 40) === false; |
| @assert ctx.isPointInPath(30, 20) === false; |
| @assert ctx.isPointInPath(70, 20) === false; |
| @assert ctx.isPointInPath(30, 30) === false; |
| @assert ctx.isPointInPath(70, 30) === false; |
| |
| - name: 2d.path.isPointInPath.bezier |
| desc: isPointInPath() works on Bezier curves |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.moveTo(25, 25); |
| ctx.bezierCurveTo(50, -50, 50, 100, 75, 25); |
| @assert ctx.isPointInPath(25, 20) === false; |
| @assert ctx.isPointInPath(25, 30) === false; |
| @assert ctx.isPointInPath(30, 20) === true; |
| @assert ctx.isPointInPath(30, 30) === false; |
| @assert ctx.isPointInPath(40, 2) === false; |
| @assert ctx.isPointInPath(40, 20) === true; |
| @assert ctx.isPointInPath(40, 30) === false; |
| @assert ctx.isPointInPath(40, 47) === false; |
| @assert ctx.isPointInPath(45, 20) === true; |
| @assert ctx.isPointInPath(45, 30) === false; |
| @assert ctx.isPointInPath(55, 20) === false; |
| @assert ctx.isPointInPath(55, 30) === true; |
| @assert ctx.isPointInPath(60, 2) === false; |
| @assert ctx.isPointInPath(60, 20) === false; |
| @assert ctx.isPointInPath(60, 30) === true; |
| @assert ctx.isPointInPath(60, 47) === false; |
| @assert ctx.isPointInPath(70, 20) === false; |
| @assert ctx.isPointInPath(70, 30) === true; |
| @assert ctx.isPointInPath(75, 20) === false; |
| @assert ctx.isPointInPath(75, 30) === false; |
| |
| - name: 2d.path.isPointInPath.winding |
| desc: isPointInPath() uses the non-zero winding number rule |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| // Create a square ring, using opposite windings to make a hole in the centre |
| 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 |
| desc: isPointInPath() handles transformations correctly |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.translate(50, 0); |
| ctx.rect(0, 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; |
| @assert ctx.isPointInPath(69, 10) === true; |
| @assert ctx.isPointInPath(71, 10) === false; |
| |
| - name: 2d.path.isPointInPath.transform.2 |
| desc: isPointInPath() handles transformations correctly |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.rect(50, 0, 20, 20); |
| ctx.translate(50, 0); |
| @assert ctx.isPointInPath(-40, 10) === false; |
| @assert ctx.isPointInPath(10, 10) === false; |
| @assert ctx.isPointInPath(49, 10) === false; |
| @assert ctx.isPointInPath(51, 10) === true; |
| @assert ctx.isPointInPath(69, 10) === true; |
| @assert ctx.isPointInPath(71, 10) === false; |
| |
| - name: 2d.path.isPointInPath.transform.3 |
| desc: isPointInPath() handles transformations correctly |
| testing: |
| - 2d.path.isPointInPath |
| 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; |
| @assert ctx.isPointInPath(69, 10) === true; |
| @assert ctx.isPointInPath(71, 10) === false; |
| |
| - name: 2d.path.isPointInPath.transform.4 |
| desc: isPointInPath() handles transformations correctly |
| testing: |
| - 2d.path.isPointInPath |
| code: | |
| ctx.translate(50, 0); |
| ctx.rect(50, 0, 20, 20); |
| ctx.translate(0, 50); |
| @assert ctx.isPointInPath(60, 10) === false; |
| @assert ctx.isPointInPath(110, 10) === true; |
| @assert ctx.isPointInPath(110, 60) === false; |
| |
| - name: 2d.path.isPointInPath.nonfinite |
| desc: isPointInPath() returns false for non-finite arguments |
| testing: |
| - 2d.path.isPointInPath.nonfinite |
| code: | |
| ctx.rect(-100, -50, 200, 100); |
| @assert ctx.isPointInPath(Infinity, 0) === false; |
| @assert ctx.isPointInPath(-Infinity, 0) === false; |
| @assert ctx.isPointInPath(NaN, 0) === false; |
| @assert ctx.isPointInPath(0, Infinity) === false; |
| @assert ctx.isPointInPath(0, -Infinity) === false; |
| @assert ctx.isPointInPath(0, NaN) === false; |
| @assert ctx.isPointInPath(NaN, NaN) === 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 |
| testing: |
| - 2d.drawImage.self |
| 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 |
| testing: |
| - 2d.drawImage.self |
| 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 |
| testing: |
| - 2d.drawImage.IDL |
| code: | |
| @assert throws TypeError ctx.drawImage(null, 0, 0); |
| |
| - name: 2d.drawImage.wrongtype |
| desc: Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError |
| notes: *bindings |
| testing: |
| - 2d.drawImage.IDL |
| code: | |
| @assert throws TypeError ctx.drawImage(undefined, 0, 0); |
| @assert throws TypeError ctx.drawImage(0, 0, 0); |
| @assert throws TypeError ctx.drawImage("", 0, 0); |
| @assert throws TypeError ctx.drawImage(document.createElement('p'), 0, 0); |
| |
| - 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 |
| desc: drawImage with zero-sized source rectangle throws INDEX_SIZE_ERR |
| testing: |
| - 2d.drawImage.zerosource |
| 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, 0, 1, 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 1, 0, 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 0, 0, 0, 0, 100, 50); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.zerosource.image |
| desc: drawImage with zero-sized source rectangle from image throws INDEX_SIZE_ERR |
| testing: |
| - 2d.drawImage.zerosource |
| images: |
| - red-zerowidth.svg |
| - red-zeroheight.svg |
| - red-zerosize.svg |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zerowidth.svg'), 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zeroheight.svg'), 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zerosize.svg'), 0, 0, 100, 50); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.negativesource |
| desc: Negative source width/height represents the correct rectangle |
| testing: |
| - 2d.drawImage.direction |
| mozilla: { throws } |
| images: |
| - ggrr-256x256.png |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 78, -100, 50, 0, 0, 50, 50); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 128, -100, -50, 50, 0, 50, 50); |
| @assert pixel 1,1 ==~ 0,255,0,255; |
| @assert pixel 1,48 ==~ 0,255,0,255; |
| @assert pixel 98,1 ==~ 0,255,0,255; |
| @assert pixel 98,48 ==~ 0,255,0,255; |
| @assert pixel 48,1 ==~ 0,255,0,255; |
| @assert pixel 48,48 ==~ 0,255,0,255; |
| @assert pixel 51,1 ==~ 0,255,0,255; |
| @assert pixel 51,48 ==~ 0,255,0,255; |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.negativedest |
| desc: Negative destination width/height represents the correct rectangle |
| testing: |
| - 2d.drawImage.direction |
| mozilla: { throws } |
| images: |
| - ggrr-256x256.png |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 78, 50, 50, 0, 50, 50, -50); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 128, 50, -50, 100, 50, -50, -50); |
| @assert pixel 1,1 ==~ 0,255,0,255; |
| @assert pixel 1,48 ==~ 0,255,0,255; |
| @assert pixel 98,1 ==~ 0,255,0,255; |
| @assert pixel 98,48 ==~ 0,255,0,255; |
| @assert pixel 48,1 ==~ 0,255,0,255; |
| @assert pixel 48,48 ==~ 0,255,0,255; |
| @assert pixel 51,1 ==~ 0,255,0,255; |
| @assert pixel 51,48 ==~ 0,255,0,255; |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.negativedir |
| desc: Negative dimensions do not affect the direction of the image |
| testing: |
| - 2d.drawImage.direction |
| mozilla: { throws } |
| images: |
| - ggrr-256x256.png |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 0, 178, 50, -100, 0, 0, 50, 100); |
| ctx.drawImage(document.getElementById('ggrr-256x256.png'), 0, 78, 50, 100, 50, 100, 50, -100); |
| @assert pixel 1,1 ==~ 0,255,0,255; |
| @assert pixel 1,48 ==~ 0,255,0,255; |
| @assert pixel 98,1 ==~ 0,255,0,255; |
| @assert pixel 98,48 ==~ 0,255,0,255; |
| @assert pixel 48,1 ==~ 0,255,0,255; |
| @assert pixel 48,48 ==~ 0,255,0,255; |
| @assert pixel 51,1 ==~ 0,255,0,255; |
| @assert pixel 51,48 ==~ 0,255,0,255; |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.outsidesource |
| DISABLED: fix this to match the current spec (transparent black outside source) |
| testing: |
| - 2d.drawImage.outsidesource |
| mozilla: { throws } |
| images: |
| - green.png |
| - red.png |
| code: | |
| ctx.drawImage(document.getElementById('green.png'), 10.5, 10.5, 89.5, 39.5, 0, 0, 100, 50); |
| ctx.drawImage(document.getElementById('green.png'), 5.5, 5.5, -5.5, -5.5, 0, 0, 100, 50); |
| ctx.drawImage(document.getElementById('green.png'), 100, 50, -5, -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 throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, -5, 5, 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 5, -5, 0, 0, 100, 50); |
| @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 110, 60, -20, -20, 0, 0, 100, 50); |
| @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.drawImage.incomplete.nosrc |
| testing: |
| - 2d.drawImage.incomplete.image |
| mozilla: { throws } |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = new Image(); |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.incomplete.immediate |
| testing: |
| - 2d.drawImage.incomplete.image |
| images: |
| - red.png |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = new Image(); |
| img.src = '../images/red.png'; |
| // This triggers the "update the image data" algorithm. |
| // The image will not go to the "completely available" state |
| // until a fetch task in the networking task source is processed, |
| // so the image must not be fully decodable yet: |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.drawImage.incomplete.reload |
| testing: |
| - 2d.drawImage.incomplete.image |
| images: |
| - yellow.png |
| - red.png |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = document.getElementById('yellow.png'); |
| img.src = '../images/red.png'; |
| // This triggers the "update the image data" algorithm, |
| // and resets the image to the "unavailable" state. |
| // The image will not go to the "completely available" state |
| // until a fetch task in the networking task source is processed, |
| // so the image must not be fully decodable yet: |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.drawImage.incomplete.emptysrc |
| testing: |
| - 2d.drawImage.incomplete.image |
| images: |
| - red.png |
| mozilla: { throws } |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = document.getElementById('red.png'); |
| img.src = ""; |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.incomplete.removedsrc |
| testing: |
| - 2d.drawImage.incomplete.image |
| images: |
| - red.png |
| mozilla: { throws } |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = document.getElementById('red.png'); |
| img.removeAttribute('src'); |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.broken |
| testing: |
| - 2d.drawImage.incomplete.image |
| images: |
| - broken.png |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var img = document.getElementById('broken.png'); |
| ctx.drawImage(img, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo |
| expected: green |
| |
| - name: 2d.drawImage.zerocanvas |
| testing: |
| - 2d.drawImage.zerocanvas |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| var canvas2 = document.createElement('canvas'); |
| canvas2.width = 0; |
| canvas2.height = 10; |
| @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0); |
| |
| canvas2.width = 10; |
| canvas2.height = 0; |
| @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0); |
| |
| canvas2.width = 0; |
| canvas2.height = 0; |
| @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0); |
| |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.svg |
| desc: drawImage() of an SVG image |
| testing: |
| - 2d.drawImage.svg |
| images: |
| - green.svg |
| code: | |
| ctx.drawImage(document.getElementById('green.svg'), 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.drawImage.animated.gif |
| desc: drawImage() of an animated GIF draws the first frame |
| testing: |
| - 2d.drawImage.animated.image |
| images: |
| - anim-gr.gif |
| code: | |
| deferTest(); |
| setTimeout(t.step_func_done(function () { |
| ctx.drawImage(document.getElementById('anim-gr.gif'), 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| }), 500); |
| expected: green |
| |
| - name: 2d.drawImage.animated.apng |
| desc: drawImage() of an APNG with no poster frame draws the first frame |
| testing: |
| - 2d.drawImage.animated.image |
| images: |
| - anim-gr.png |
| code: | |
| deferTest(); |
| setTimeout(t.step_func_done(function () { |
| ctx.drawImage(document.getElementById('anim-gr.png'), 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| }), 500); |
| expected: green |
| |
| - name: 2d.drawImage.animated.poster |
| desc: drawImage() of an APNG draws the poster frame |
| testing: |
| - 2d.drawImage.animated.image |
| images: |
| - anim-poster-gr.png |
| code: | |
| ctx.drawImage(document.getElementById('anim-poster-gr.png'), 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo |
| expected: green |
| |
| - 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.drawImage.nonfinite |
| desc: drawImage() with Infinity/NaN is ignored |
| testing: |
| - 2d.nonfinite |
| images: |
| - red.png |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var red = document.getElementById('red.png'); |
| @nonfinite ctx.drawImage(<red>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); |
| @nonfinite ctx.drawImage(<red>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| @nonfinite ctx.drawImage(<red>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>); |
| @assert pixel 50,25 == 0,255,0,255; |
| expected: green |
| |
| |
| |
| - name: 2d.imageData.create2.basic |
| desc: createImageData(sw, sh) exists and returns something |
| testing: |
| - 2d.imageData.create2.object |
| code: | |
| @assert ctx.createImageData(1, 1) !== null; |
| |
| - name: 2d.imageData.create1.basic |
| desc: createImageData(imgdata) exists and returns something |
| testing: |
| - 2d.imageData.create1.object |
| code: | |
| @assert ctx.createImageData(ctx.createImageData(1, 1)) !== null; |
| |
| - name: 2d.imageData.create2.type |
| desc: createImageData(sw, sh) returns an ImageData object containing a Uint8ClampedArray object |
| testing: |
| - 2d.imageData.create2.object |
| code: | |
| @assert window.ImageData !== undefined; |
| @assert window.Uint8ClampedArray !== undefined; |
| window.ImageData.prototype.thisImplementsImageData = true; |
| window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true; |
| var imgdata = ctx.createImageData(1, 1); |
| @assert imgdata.thisImplementsImageData; |
| @assert imgdata.data.thisImplementsUint8ClampedArray; |
| |
| - name: 2d.imageData.create1.type |
| desc: createImageData(imgdata) returns an ImageData object containing a Uint8ClampedArray object |
| testing: |
| - 2d.imageData.create1.object |
| code: | |
| @assert window.ImageData !== undefined; |
| @assert window.Uint8ClampedArray !== undefined; |
| window.ImageData.prototype.thisImplementsImageData = true; |
| window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true; |
| var imgdata = ctx.createImageData(ctx.createImageData(1, 1)); |
| @assert imgdata.thisImplementsImageData; |
| @assert imgdata.data.thisImplementsUint8ClampedArray; |
| |
| - name: 2d.imageData.create2.this |
| desc: createImageData(sw, sh) should throw when called with the wrong |this| |
| notes: *bindings |
| testing: |
| - 2d.imageData.create2.object |
| code: | |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, 1, 1); @moz-todo |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, 1, 1); @moz-todo |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, 1, 1); @moz-todo |
| |
| - name: 2d.imageData.create1.this |
| desc: createImageData(imgdata) should throw when called with the wrong |this| |
| notes: *bindings |
| testing: |
| - 2d.imageData.create2.object |
| code: | |
| var imgdata = ctx.createImageData(1, 1); |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, imgdata); @moz-todo |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, imgdata); @moz-todo |
| @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, imgdata); @moz-todo |
| |
| - name: 2d.imageData.create2.initial |
| desc: createImageData(sw, sh) returns transparent black data of the right size |
| testing: |
| - 2d.imageData.create2.size |
| - 2d.imageData.create.initial |
| - 2d.imageData.initial |
| code: | |
| var imgdata = ctx.createImageData(10, 20); |
| @assert imgdata.data.length === imgdata.width*imgdata.height*4; |
| @assert imgdata.width < imgdata.height; |
| @assert imgdata.width > 0; |
| var isTransparentBlack = true; |
| for (var i = 0; i < imgdata.data.length; ++i) |
| if (imgdata.data[i] !== 0) |
| isTransparentBlack = false; |
| @assert isTransparentBlack; |
| |
| - name: 2d.imageData.create1.initial |
| desc: createImageData(imgdata) returns transparent black data of the right size |
| testing: |
| - 2d.imageData.create1.size |
| - 2d.imageData.create.initial |
| - 2d.imageData.initial |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50); |
| var imgdata1 = ctx.getImageData(0, 0, 10, 20); |
| var imgdata2 = ctx.createImageData(imgdata1); |
| @assert imgdata2.data.length === imgdata1.data.length; |
| @assert imgdata2.width === imgdata1.width; |
| @assert imgdata2.height === imgdata1.height; |
| var isTransparentBlack = true; |
| for (var i = 0; i < imgdata2.data.length; ++i) |
| if (imgdata2.data[i] !== 0) |
| isTransparentBlack = false; |
| @assert isTransparentBlack; |
| |
| - name: 2d.imageData.create2.large |
| desc: createImageData(sw, sh) works for sizes much larger than the canvas |
| testing: |
| - 2d.imageData.create2.size |
| code: | |
| var imgdata = ctx.createImageData(1000, 2000); |
| @assert imgdata.data.length === imgdata.width*imgdata.height*4; |
| @assert imgdata.width < imgdata.height; |
| @assert imgdata.width > 0; |
| var isTransparentBlack = true; |
| for (var i = 0; i < imgdata.data.length; i += 7813) // check ~1024 points (assuming normal scaling) |
| if (imgdata.data[i] !== 0) |
| isTransparentBlack = false; |
| @assert isTransparentBlack; |
| |
| - name: 2d.imageData.create2.tiny |
| desc: createImageData(sw, sh) works for sizes smaller than one pixel |
| testing: |
| - 2d.imageData.create2.size |
| - 2d.imageData.one |
| code: | |
| var imgdata = ctx.createImageData(0.0001, 0.0001); |
| @assert imgdata.data.length === imgdata.width*imgdata.height*4; |
| @assert imgdata.width === 1; |
| @assert imgdata.height === 1; |
| var isTransparentBlack = true; |
| for (var i = 0; i < imgdata.data.length; ++i) |
| if (imgdata.data[i] !== 0) |
| isTransparentBlack = false; |
| @assert isTransparentBlack; |
| |
| - name: 2d.imageData.create2.negative |
| desc: createImageData(sw, sh) takes the absolute magnitude of the size arguments |
| testing: |
| - 2d.imageData.create2.size |
| code: | |
| var imgdata1 = ctx.createImageData(10, 20); |
| var imgdata2 = ctx.createImageData(-10, 20); |
| var imgdata3 = ctx.createImageData(10, -20); |
| var imgdata4 = ctx.createImageData(-10, -20); |
| @assert imgdata1.data.length === imgdata2.data.length; |
| @assert imgdata2.data.length === imgdata3.data.length; |
| @assert imgdata3.data.length === imgdata4.data.length; |
| |
| - name: 2d.imageData.create2.zero |
| desc: createImageData(sw, sh) throws INDEX_SIZE_ERR if size is zero |
| testing: |
| - 2d.imageData.getcreate.zero |
| code: | |
| @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0); |
| @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 10); |
| @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 0); |
| |
| - name: 2d.imageData.create2.nonfinite |
| desc: createImageData() throws TypeError if arguments are not finite |
| notes: *bindings |
| testing: |
| - 2d.imageData.getcreate.nonfinite |
| code: | |
| @nonfinite @assert throws TypeError ctx.createImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>); |
| var posinfobj = { valueOf: function() { return Infinity; } }, |
| neginfobj = { valueOf: function() { return -Infinity; } }, |
| nanobj = { valueOf: function() { return -Infinity; } }; |
| @nonfinite @assert throws TypeError ctx.createImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>); |
| |
| - name: 2d.imageData.create1.zero |
| desc: createImageData(null) throws TypeError |
| testing: |
| - 2d.imageData.create.null |
| code: | |
| @assert throws TypeError ctx.createImageData(null); |
| |
| - name: 2d.imageData.create2.round |
| desc: createImageData(w, h) is rounded the same as getImageData(0, 0, w, h) |
| testing: |
| - 2d.imageData.createround |
| code: | |
| var imgdata1 = ctx.createImageData(10.01, 10.99); |
| var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99); |
| @assert imgdata1.width === imgdata2.width; |
| @assert imgdata1.height === imgdata2.height; |
| |
| - name: 2d.imageData.get.basic |
| desc: getImageData() exists and returns something |
| testing: |
| - 2d.imageData.get.basic |
| code: | |
| @assert ctx.getImageData(0, 0, 100, 50) !== null; |
| |
| - name: 2d.imageData.get.type |
| desc: getImageData() returns an ImageData object containing a Uint8ClampedArray object |
| testing: |
| - 2d.imageData.get.object |
| code: | |
| @assert window.ImageData !== undefined; |
| @assert window.Uint8ClampedArray !== undefined; |
| window.ImageData.prototype.thisImplementsImageData = true; |
| window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true; |
| var imgdata = ctx.getImageData(0, 0, 1, 1); |
| @assert imgdata.thisImplementsImageData; |
| @assert imgdata.data.thisImplementsUint8ClampedArray; |
| |
| - name: 2d.imageData.get.zero |
| desc: getImageData() throws INDEX_SIZE_ERR if size is zero |
| testing: |
| - 2d.imageData.getcreate.zero |
| code: | |
| @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0); |
| @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 10); |
| @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 0); |
| |
| - name: 2d.imageData.get.nonfinite |
| desc: getImageData() throws TypeError if arguments are not finite |
| notes: *bindings |
| testing: |
| - 2d.imageData.getcreate.nonfinite |
| code: | |
| @nonfinite @assert throws TypeError ctx.getImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>); |
| var posinfobj = { valueOf: function() { return Infinity; } }, |
| neginfobj = { valueOf: function() { return -Infinity; } }, |
| nanobj = { valueOf: function() { return -Infinity; } }; |
| @nonfinite @assert throws TypeError ctx.getImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>); |
| |
| - name: 2d.imageData.get.source.outside |
| desc: getImageData() returns transparent black outside the canvas |
| testing: |
| - 2d.imageData.get.basic |
| - 2d.imageData.get.outside |
| code: | |
| ctx.fillStyle = '#08f'; |
| ctx.fillRect(0, 0, 100, 50); |
| |
| var imgdata1 = ctx.getImageData(-10, 5, 1, 1); |
| @assert imgdata1.data[0] === 0; |
| @assert imgdata1.data[1] === 0; |
| @assert imgdata1.data[2] === 0; |
| @assert imgdata1.data[3] === 0; |
| |
| var imgdata2 = ctx.getImageData(10, -5, 1, 1); |
| @assert imgdata2.data[0] === 0; |
| @assert imgdata2.data[1] === 0; |
| @assert imgdata2.data[2] === 0; |
| @assert imgdata2.data[3] === 0; |
| |
| var imgdata3 = ctx.getImageData(200, 5, 1, 1); |
| @assert imgdata3.data[0] === 0; |
| @assert imgdata3.data[1] === 0; |
| @assert imgdata3.data[2] === 0; |
| @assert imgdata3.data[3] === 0; |
| |
| var imgdata4 = ctx.getImageData(10, 60, 1, 1); |
| @assert imgdata4.data[0] === 0; |
| @assert imgdata4.data[1] === 0; |
| @assert imgdata4.data[2] === 0; |
| @assert imgdata4.data[3] === 0; |
| |
| var imgdata5 = ctx.getImageData(100, 10, 1, 1); |
| @assert imgdata5.data[0] === 0; |
| @assert imgdata5.data[1] === 0; |
| @assert imgdata5.data[2] === 0; |
| @assert imgdata5.data[3] === 0; |
| |
| var imgdata6 = ctx.getImageData(0, 10, 1, 1); |
| @assert imgdata6.data[0] === 0; |
| @assert imgdata6.data[1] === 136; |
| @assert imgdata6.data[2] === 255; |
| @assert imgdata6.data[3] === 255; |
| |
| var imgdata7 = ctx.getImageData(-10, 10, 20, 20); |
| @assert imgdata7.data[ 0*4+0] === 0; |
| @assert imgdata7.data[ 0*4+1] === 0; |
| @assert imgdata7.data[ 0*4+2] === 0; |
| @assert imgdata7.data[ 0*4+3] === 0; |
| @assert imgdata7.data[ 9*4+0] === 0; |
| @assert imgdata7.data[ 9*4+1] === 0; |
| @assert imgdata7.data[ 9*4+2] === 0; |
| @assert imgdata7.data[ 9*4+3] === 0; |
| @assert imgdata7.data[10*4+0] === 0; |
| @assert imgdata7.data[10*4+1] === 136; |
| @assert imgdata7.data[10*4+2] === 255; |
| @assert imgdata7.data[10*4+3] === 255; |
| @assert imgdata7.data[19*4+0] === 0; |
| @assert imgdata7.data[19*4+1] === 136; |
| @assert imgdata7.data[19*4+2] === 255; |
| @assert imgdata7.data[19*4+3] === 255; |
| @assert imgdata7.data[20*4+0] === 0; |
| @assert imgdata7.data[20*4+1] === 0; |
| @assert imgdata7.data[20*4+2] === 0; |
| @assert imgdata7.data[20*4+3] === 0; |
| |
| - name: 2d.imageData.get.source.negative |
| desc: getImageData() works with negative width and height, and returns top-to-bottom left-to-right |
| testing: |
| - 2d.imageData.get.basic |
| - 2d.pixelarray.order |
| code: | |
| ctx.fillStyle = '#000'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#fff'; |
| ctx.fillRect(20, 10, 60, 10); |
| |
| var imgdata1 = ctx.getImageData(85, 25, -10, -10); |
| @assert imgdata1.data[0] === 255; |
| @assert imgdata1.data[1] === 255; |
| @assert imgdata1.data[2] === 255; |
| @assert imgdata1.data[3] === 255; |
| @assert imgdata1.data[imgdata1.data.length-4+0] === 0; |
| @assert imgdata1.data[imgdata1.data.length-4+1] === 0; |
| @assert imgdata1.data[imgdata1.data.length-4+2] === 0; |
| @assert imgdata1.data[imgdata1.data.length-4+3] === 255; |
| |
| var imgdata2 = ctx.getImageData(0, 0, -1, -1); |
| @assert imgdata2.data[0] === 0; |
| @assert imgdata2.data[1] === 0; |
| @assert imgdata2.data[2] === 0; |
| @assert imgdata2.data[3] === 0; |
| |
| - name: 2d.imageData.get.source.size |
| desc: getImageData() returns bigger ImageData for bigger source rectangle |
| 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.tiny |
| desc: getImageData() works for sizes smaller than one pixel |
| testing: |
| - 2d.imageData.one |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 0.0001, 0.0001); |
| @assert imgdata.data.length === imgdata.width*imgdata.height*4; |
| @assert imgdata.width === 1; |
| @assert imgdata.height === 1; |
| |
| - name: 2d.imageData.get.nonpremul |
| desc: getImageData() returns non-premultiplied colours |
| 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.range |
| desc: getImageData() returns values in the range [0, 255] |
| testing: |
| - 2d.pixelarray.range |
| - 2d.pixelarray.retrieve |
| code: | |
| ctx.fillStyle = '#000'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = '#fff'; |
| ctx.fillRect(20, 10, 60, 10); |
| var imgdata1 = ctx.getImageData(10, 5, 1, 1); |
| @assert imgdata1.data[0] === 0; |
| var imgdata2 = ctx.getImageData(30, 15, 1, 1); |
| @assert imgdata2.data[0] === 255; |
| |
| - name: 2d.imageData.get.clamp |
| desc: getImageData() clamps colours to the range [0, 255] |
| testing: |
| - 2d.pixelarray.range |
| code: | |
| ctx.fillStyle = 'rgb(-100, -200, -300)'; |
| ctx.fillRect(0, 0, 100, 50); |
| ctx.fillStyle = 'rgb(256, 300, 400)'; |
| ctx.fillRect(20, 10, 60, 10); |
| var imgdata1 = ctx.getImageData(10, 5, 1, 1); |
| @assert imgdata1.data[0] === 0; |
| @assert imgdata1.data[1] === 0; |
| @assert imgdata1.data[2] === 0; |
| var imgdata2 = ctx.getImageData(30, 15, 1, 1); |
| @assert imgdata2.data[0] === 255; |
| @assert imgdata2.data[1] === 255; |
| @assert imgdata2.data[2] === 255; |
| |
| - name: 2d.imageData.get.length |
| desc: getImageData() returns a correctly-sized Uint8ClampedArray |
| testing: |
| - 2d.pixelarray.length |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| @assert imgdata.data.length === imgdata.width*imgdata.height*4; |
| |
| - name: 2d.imageData.get.order.cols |
| desc: getImageData() returns leftmost columns first |
| testing: |
| - 2d.pixelarray.order |
| 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.round(imgdata.width/2*4)] === 255; |
| @assert imgdata.data[Math.round((imgdata.height/2)*imgdata.width*4)] === 0; |
| |
| - name: 2d.imageData.get.order.rows |
| desc: getImageData() returns topmost rows first |
| testing: |
| - 2d.pixelarray.order |
| 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 |
| desc: getImageData() returns R then G then B |
| testing: |
| - 2d.pixelarray.order |
| - 2d.pixelarray.indexes |
| 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; |
| @assert imgdata.data[4] === 0x44; |
| @assert imgdata.data[5] === 0x88; |
| @assert imgdata.data[6] === 0xCC; |
| @assert imgdata.data[7] === 255; |
| |
| - name: 2d.imageData.get.order.alpha |
| desc: getImageData() returns A in the fourth component |
| testing: |
| - 2d.pixelarray.order |
| 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.unaffected |
| desc: getImageData() is not affected by context state |
| testing: |
| - 2d.imageData.unaffected |
| code: | |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 50, 50) |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(50, 0, 50, 50) |
| ctx.save(); |
| ctx.translate(50, 0); |
| ctx.globalAlpha = 0.1; |
| ctx.globalCompositeOperation = 'destination-atop'; |
| ctx.shadowColor = '#f00'; |
| ctx.rect(0, 0, 5, 5); |
| ctx.clip(); |
| var imgdata = ctx.getImageData(0, 0, 50, 50); |
| ctx.restore(); |
| ctx.putImageData(imgdata, 50, 0); |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| expected: green |
| |
| |
| - name: 2d.imageData.object.properties |
| desc: ImageData objects have the right properties |
| testing: |
| - 2d.imageData.type |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| @assert typeof(imgdata.width) === 'number'; |
| @assert typeof(imgdata.height) === 'number'; |
| @assert typeof(imgdata.data) === 'object'; |
| |
| - name: 2d.imageData.object.readonly |
| desc: ImageData objects properties are read-only |
| testing: |
| - 2d.imageData.type |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| var w = imgdata.width; |
| var h = imgdata.height; |
| var d = imgdata.data; |
| imgdata.width = 123; |
| imgdata.height = 123; |
| imgdata.data = [100,100,100,100]; |
| @assert imgdata.width === w; |
| @assert imgdata.height === h; |
| @assert imgdata.data === d; |
| @assert imgdata.data[0] === 0; |
| @assert imgdata.data[1] === 0; |
| @assert imgdata.data[2] === 0; |
| @assert imgdata.data[3] === 0; |
| |
| - name: 2d.imageData.object.ctor |
| desc: ImageData does not have a usable constructor |
| testing: |
| - 2d.imageData.type |
| code: | |
| @assert window.ImageData !== undefined; |
| @assert throws TypeError new window.ImageData(1,1); |
| |
| - name: 2d.imageData.object.set |
| desc: ImageData.data can be modified |
| testing: |
| - 2d.pixelarray.modify |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| imgdata.data[0] = 100; |
| @assert imgdata.data[0] === 100; |
| imgdata.data[0] = 200; |
| @assert imgdata.data[0] === 200; |
| |
| - name: 2d.imageData.object.undefined |
| desc: ImageData.data converts undefined to 0 |
| testing: |
| - 2d.pixelarray.modify |
| webidl: |
| - es-octet |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| imgdata.data[0] = 100; |
| imgdata.data[0] = undefined; |
| @assert imgdata.data[0] === 0; |
| |
| - name: 2d.imageData.object.nan |
| desc: ImageData.data converts NaN to 0 |
| testing: |
| - 2d.pixelarray.modify |
| webidl: |
| - es-octet |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| imgdata.data[0] = 100; |
| imgdata.data[0] = NaN; |
| @assert imgdata.data[0] === 0; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = "cheese"; |
| @assert imgdata.data[0] === 0; |
| |
| - name: 2d.imageData.object.string |
| desc: ImageData.data converts strings to numbers with ToNumber |
| testing: |
| - 2d.pixelarray.modify |
| webidl: |
| - es-octet |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| imgdata.data[0] = 100; |
| imgdata.data[0] = "110"; |
| @assert imgdata.data[0] === 110; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = "0x78"; |
| @assert imgdata.data[0] === 120; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = " +130e0 "; |
| @assert imgdata.data[0] === 130; |
| |
| - name: 2d.imageData.object.clamp |
| desc: ImageData.data clamps numbers to [0, 255] |
| testing: |
| - 2d.pixelarray.modify |
| webidl: |
| - es-octet |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| |
| imgdata.data[0] = 100; |
| imgdata.data[0] = 300; |
| @assert imgdata.data[0] === 255; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = -100; |
| @assert imgdata.data[0] === 0; |
| |
| imgdata.data[0] = 100; |
| imgdata.data[0] = 200+Math.pow(2, 32); |
| @assert imgdata.data[0] === 255; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = -200-Math.pow(2, 32); |
| @assert imgdata.data[0] === 0; |
| |
| imgdata.data[0] = 100; |
| imgdata.data[0] = Math.pow(10, 39); |
| @assert imgdata.data[0] === 255; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = -Math.pow(10, 39); |
| @assert imgdata.data[0] === 0; |
| |
| imgdata.data[0] = 100; |
| imgdata.data[0] = -Infinity; |
| @assert imgdata.data[0] === 0; |
| imgdata.data[0] = 100; |
| imgdata.data[0] = Infinity; |
| @assert imgdata.data[0] === 255; |
| |
| - name: 2d.imageData.object.round |
| desc: ImageData.data rounds numbers with round-to-zero |
| testing: |
| - 2d.pixelarray.modify |
| webidl: |
| - es-octet |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| imgdata.data[0] = 0.499; |
| @assert imgdata.data[0] === 0; |
| imgdata.data[0] = 0.5; |
| @assert imgdata.data[0] === 0; |
| imgdata.data[0] = 0.501; |
| @assert imgdata.data[0] === 1; |
| imgdata.data[0] = 1.499; |
| @assert imgdata.data[0] === 1; |
| imgdata.data[0] = 1.5; |
| @assert imgdata.data[0] === 2; |
| imgdata.data[0] = 1.501; |
| @assert imgdata.data[0] === 2; |
| imgdata.data[0] = 2.5; |
| @assert imgdata.data[0] === 2; |
| imgdata.data[0] = 3.5; |
| @assert imgdata.data[0] === 4; |
| imgdata.data[0] = 252.5; |
| @assert imgdata.data[0] === 252; |
| imgdata.data[0] = 253.5; |
| @assert imgdata.data[0] === 254; |
| imgdata.data[0] = 254.5; |
| @assert imgdata.data[0] === 254; |
| imgdata.data[0] = 256.5; |
| @assert imgdata.data[0] === 255; |
| imgdata.data[0] = -0.5; |
| @assert imgdata.data[0] === 0; |
| imgdata.data[0] = -1.5; |
| @assert imgdata.data[0] === 0; |
| |
| |
| |
| - name: 2d.imageData.put.null |
| desc: putImageData() with null imagedata throws TypeError |
| testing: |
| - 2d.imageData.put.wrongtype |
| code: | |
| @assert throws TypeError ctx.putImageData(null, 0, 0); |
| |
| - name: 2d.imageData.put.nonfinite |
| desc: putImageData() throws TypeError if arguments are not finite |
| notes: *bindings |
| testing: |
| - 2d.imageData.put.nonfinite |
| code: | |
| var imgdata = ctx.getImageData(0, 0, 10, 10); |
| @nonfinite @assert throws TypeError ctx.putImageData(<imgdata>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>); |
| @nonfinite @assert throws TypeError ctx.putImageData(<imgdata>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>); |
| |
| - name: 2d.imageData.put.basic |
| desc: putImageData() puts image data from getImageData() onto the canvas |
| testing: |
| - 2d.imageData.put.normal |
| - 2d.imageData.put.3arg |
| 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.created |
| desc: putImageData() puts image data from createImageData() onto the canvas |
| testing: |
| - 2d.imageData.put.normal |
| code: | |
| var imgdata = ctx.createImageData(100, 50); |
| for (var i = 0; i < imgdata.data.length; i += 4) { |
| imgdata.data[i] = 0; |
| imgdata.data[i+1] = 255; |
| imgdata.data[i+2] = 0; |
| imgdata.data[i+3] = 255; |
| } |
| 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.wrongtype |
| desc: putImageData() does not accept non-ImageData objects |
| testing: |
| - 2d.imageData.put.wrongtype |
| code: | |
| var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] }; |
| @assert throws TypeError ctx.putImageData(imgdata, 0, 0); |
| @assert throws TypeError ctx.putImageData("cheese", 0, 0); |
| @assert throws TypeError ctx.putImageData(42, 0, 0); |
| expected: green |
| |
| - name: 2d.imageData.put.cross |
| desc: putImageData() accepts image data got from a different canvas |
| testing: |
| - 2d.imageData.put.normal |
| code: | |
| var canvas2 = document.createElement('canvas'); |
| var ctx2 = canvas2.getContext('2d'); |
| ctx2.fillStyle = '#0f0'; |
| ctx2.fillRect(0, 0, 100, 50) |
| var imgdata = ctx2.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 |
| desc: putImageData() puts non-solid image data correctly |
| testing: |
| - 2d.imageData.put.normal |
| 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 |
| desc: putImageData() puts modified image data correctly |
| testing: |
| - 2d.imageData.put.normal |
| 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.dirty.zero |
| desc: putImageData() with zero-sized dirty rectangle puts nothing |
| testing: |
| - 2d.imageData.put.normal |
| 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, 0, 0, 0, 0, 0, 0); |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.dirty.rect1 |
| desc: putImageData() only modifies areas inside the dirty rectangle, using width and height |
| testing: |
| - 2d.imageData.put.normal |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 20, 20) |
| |
| var imgdata = ctx.getImageData(0, 0, 100, 50); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(40, 20, 20, 20) |
| ctx.putImageData(imgdata, 40, 20, 0, 0, 20, 20); |
| |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| @assert pixel 35,25 ==~ 0,255,0,255; |
| @assert pixel 65,25 ==~ 0,255,0,255; |
| @assert pixel 50,15 ==~ 0,255,0,255; |
| @assert pixel 50,45 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.dirty.rect2 |
| desc: putImageData() only modifies areas inside the dirty rectangle, using x and y |
| testing: |
| - 2d.imageData.put.normal |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(60, 30, 20, 20) |
| |
| var imgdata = ctx.getImageData(0, 0, 100, 50); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(40, 20, 20, 20) |
| ctx.putImageData(imgdata, -20, -10, 60, 30, 20, 20); |
| |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| @assert pixel 35,25 ==~ 0,255,0,255; |
| @assert pixel 65,25 ==~ 0,255,0,255; |
| @assert pixel 50,15 ==~ 0,255,0,255; |
| @assert pixel 50,45 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.dirty.negative |
| desc: putImageData() handles negative-sized dirty rectangles correctly |
| testing: |
| - 2d.imageData.put.normal |
| code: | |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 20, 20) |
| |
| var imgdata = ctx.getImageData(0, 0, 100, 50); |
| |
| ctx.fillStyle = '#0f0'; |
| ctx.fillRect(0, 0, 100, 50) |
| ctx.fillStyle = '#f00'; |
| ctx.fillRect(40, 20, 20, 20) |
| ctx.putImageData(imgdata, 40, 20, 20, 20, -20, -20); |
| |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| @assert pixel 35,25 ==~ 0,255,0,255; |
| @assert pixel 65,25 ==~ 0,255,0,255; |
| @assert pixel 50,15 ==~ 0,255,0,255; |
| @assert pixel 50,45 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.dirty.outside |
| desc: putImageData() handles dirty rectangles outside the canvas correctly |
| testing: |
| - 2d.imageData.put.normal |
| 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, 20, 20, 20, -20, -20); |
| ctx.putImageData(imgdata, 200, 200, 0, 0, 100, 50); |
| ctx.putImageData(imgdata, 40, 20, -30, -20, 30, 20); |
| ctx.putImageData(imgdata, -30, 20, 0, 0, 30, 20); |
| |
| @assert pixel 50,25 ==~ 0,255,0,255; |
| @assert pixel 98,15 ==~ 0,255,0,255; |
| @assert pixel 98,25 ==~ 0,255,0,255; |
| @assert pixel 98,45 ==~ 0,255,0,255; |
| @assert pixel 1,5 ==~ 0,255,0,255; |
| @assert pixel 1,25 ==~ 0,255,0,255; |
| @assert pixel 1,45 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.unchanged |
| desc: putImageData(getImageData(...), ...) has no effect |
| 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 |
| desc: putImageData() is not affected by context state |
| testing: |
| - 2d.imageData.unaffected |
| 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.shadowBlur = 1; |
| 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.clip |
| desc: putImageData() is not affected by clipping regions |
| testing: |
| - 2d.imageData.unaffected |
| 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.beginPath(); |
| ctx.rect(0, 0, 50, 50); |
| ctx.clip(); |
| ctx.putImageData(imgdata, 0, 0); |
| @assert pixel 25,25 ==~ 0,255,0,255; |
| @assert pixel 75,25 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.imageData.put.path |
| desc: putImageData() does not affect the current path |
| testing: |
| - 2d.imageData.put.normal |
| 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 |