blob: 67eef796a74421438834ed3e0c5e74bd11e06bb9 [file] [log] [blame]
# Copyright (c) 2010 Philip Taylor
# Released under the BSD license and W3C Test Suite License: see LICENSE.txt
- name: fallback.basic
desc: Fallback content is inserted into the DOM
testing:
- fallback
code: |
@assert canvas.childNodes.length === 1;
- name: fallback.multiple
desc: Fallback content with multiple elements
testing:
- fallback
fallback: '<p class="fallback">FAIL</p><p class="fallback">FAIL</p>'
code: |
@assert canvas.childNodes.length === 2;
- name: fallback.nested
desc: Fallback content containing another canvas (mostly testing parsers)
testing:
- fallback
fallback: '<canvas><p class="fallback">FAIL (fallback content)</p></canvas><p class="fallback">FAIL (fallback content)</p>'
code: |
@assert canvas.childNodes.length === 2;
- name: type.name
desc: HTMLCanvasElement type and toString
testing:
- canvas.type
code: |
@assert Object.prototype.toString.call(canvas) === '[object HTMLCanvasElement]';
- name: type.exists
desc: HTMLCanvasElement is a property of window
notes: &bindings Defined in "Web IDL" (draft)
testing:
- canvas.type
code: |
@assert window.HTMLCanvasElement;
- name: type.delete
desc: window.HTMLCanvasElement interface object is [[Configurable]]
notes: *bindings
testing:
- canvas.type
code: |
@assert delete window.HTMLCanvasElement === true;
@assert window.HTMLCanvasElement === undefined;
- name: type.prototype
desc: window.HTMLCanvasElement has prototype, which is { ReadOnly, DontDelete }. prototype has getContext, which is not
notes: *bindings
testing:
- canvas.type
code: |
@assert window.HTMLCanvasElement.prototype;
@assert window.HTMLCanvasElement.prototype.getContext;
window.HTMLCanvasElement.prototype = null;
@assert window.HTMLCanvasElement.prototype;
delete window.HTMLCanvasElement.prototype;
@assert window.HTMLCanvasElement.prototype;
window.HTMLCanvasElement.prototype.getContext = 1;
@assert window.HTMLCanvasElement.prototype.getContext === 1;
delete window.HTMLCanvasElement.prototype.getContext;
@assert window.HTMLCanvasElement.prototype.getContext === undefined;
- name: type.replace
desc: HTMLCanvasElement methods can be replaced, and the replacement methods used by canvases
notes: *bindings
testing:
- canvas.type
code: |
window.HTMLCanvasElement.prototype.getContext = function (name) { return 0; };
@assert canvas.getContext('2d') === 0;
- name: type.extend
desc: HTMLCanvasElement methods can be added, and the new methods used by canvases
notes: *bindings
testing:
- canvas.type
code: |
window.HTMLCanvasElement.prototype.getZero = function () { return 0; };
@assert canvas.getZero() === 0;
- name: size.attributes.idl.set.zero
desc: Setting width/height IDL attributes to 0
testing:
- size.width
- size.height
code: |
canvas.width = 0;
canvas.height = 0;
@assert canvas.width === 0;
@assert canvas.height === 0;
# expected: size 0 0 # can't generate zero-sized PNG
- name: size.attributes.idl
desc: Getting/setting width/height IDL attributes
testing:
- size.width
- size.height
webidl:
- es-unsigned-long
code: |
canvas.width = "100";
canvas.height = "100";
@assert canvas.width === 100;
@assert canvas.height === 100;
canvas.width = "+1.5e2";
canvas.height = "0x96";
@assert canvas.width === 150;
@assert canvas.height === 150;
canvas.width = 200 - Math.pow(2, 32);
canvas.height = 200 - Math.pow(2, 32);
@assert canvas.width === 200;
@assert canvas.height === 200;
canvas.width = 301.999;
canvas.height = 301.001;
@assert canvas.width === 301;
@assert canvas.height === 301;
canvas.width = "400x";
canvas.height = "foo";
@assert canvas.width === 0;
@assert canvas.height === 0;
- name: size.attributes.default
desc: Default width/height when attributes are missing
testing:
- size.default
- size.missing
canvas: ""
code: |
@assert canvas.width === 300;
@assert canvas.height === 150;
@assert !canvas.hasAttribute('width');
@assert !canvas.hasAttribute('height');
expected: size 300 150
- name: size.attributes.reflect.setidl
desc: Setting IDL attributes updates IDL and content attributes
testing:
- size.reflect
code: |
canvas.width = 120;
canvas.height = 60;
@assert canvas.getAttribute('width') === '120';
@assert canvas.getAttribute('height') === '60';
@assert canvas.width === 120;
@assert canvas.height === 60;
expected: size 120 60
- name: size.attributes.reflect.setidlzero
desc: Setting IDL attributes to 0 updates IDL and content attributes
testing:
- size.reflect
code: |
canvas.width = 0;
canvas.height = 0;
@assert canvas.getAttribute('width') === '0';
@assert canvas.getAttribute('height') === '0';
@assert canvas.width === 0;
@assert canvas.height === 0;
# expected: size 0 0 # can't generate zero-sized PNG
- name: size.attributes.reflect.setcontent
desc: Setting content attributes updates IDL and content attributes
testing:
- size.reflect
code: |
canvas.setAttribute('width', '120');
canvas.setAttribute('height', '60');
@assert canvas.getAttribute('width') === '120';
@assert canvas.getAttribute('height') === '60';
@assert canvas.width === 120;
@assert canvas.height === 60;
expected: size 120 60
- name: size.attributes.removed
desc: Removing content attributes reverts to default size
testing:
- size.missing
canvas: width="120" height="60"
code: |
@assert canvas.width === 120;
canvas.removeAttribute('width');
@assert canvas.width === 300;
expected: size 300 60
- meta: |
cases = [
("zero", "0", 0),
("empty", "", None),
("onlyspace", " ", None),
("space", " 100", 100),
("whitespace", "\n\t\f100", 100),
("plus", "+100", 100),
("minus", "-100", None),
("octal", "0100", 100),
("hex", "0x100", 0),
("exp", "100e1", 100),
("decimal", "100.999", 100),
("percent", "100%", 100),
("em", "100em", 100),
("junk", "#!?", None),
("trailingjunk", "100#!?", 100),
]
def gen(name, string, exp, code):
testing = ["size.nonnegativeinteger"]
if exp is None:
testing.append("size.error")
code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n"
expected = "size 300 150"
else:
code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp)
expected = "size %s %s" % (exp, exp)
# With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width,
# so check the CSS display width
code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, )
code += "@assert canvas.getAttribute('width') === %r;\n" % string
code += "@assert canvas.getAttribute('height') === %r;\n" % string
if exp == 0:
expected = None # can't generate zero-sized PNGs for the expected image
return code, testing, expected
for name, string, exp in cases:
code = ""
code, testing, expected = gen(name, string, exp, code)
tests.append( {
"name": "size.attributes.parse.%s" % name,
"desc": "Parsing of non-negative integers",
"testing": testing,
"canvas": 'width="%s" height="%s"' % (string, string),
"code": code,
"expected": expected
} )
for name, string, exp in cases:
code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string)
code, testing, expected = gen(name, string, exp, code)
tests.append( {
"name": "size.attributes.setAttribute.%s" % name,
"desc": "Parsing of non-negative integers in setAttribute",
"testing": testing,
"canvas": 'width="50" height="50"',
"code": code,
"expected": expected
} )
- name: size.attributes.style
desc: Canvas size is independent of CSS resizing
testing:
- size.css
canvas: 'width="50" height="30" style="width: 100px; height: 50px"'
code: |
@assert canvas.width === 50;
@assert canvas.height === 30;
expected: size 100 50
- name: size.large
DISABLED: |
"User agents may impose implementation-specific limits on otherwise unconstrained
inputs, e.g. to prevent denial of service attacks, to guard against running out of memory,
or to work around platform-specific limitations."
testing:
- size.width
- size.height
notes: Not sure how reasonable this is, but the spec doesn't say there's an upper limit on the size.
code: |
var n = 2147483647; // 2^31 - 1, which should be supported by any sensible definition of "long"
canvas.width = n;
canvas.height = n;
@assert canvas.width === n;
@assert canvas.height === n;
# expected: size 2147483647 2147483647 # not a good idea to generate the expected image in this case...
- name: initial.colour
desc: Initial state is transparent black
testing:
- initial.colour
notes: |
Output should be transparent black (not transparent anything-else), but manual
verification can only confirm that it's transparent - it's not possible to make
the actual blackness visible.
code: |
@assert pixel 20,20 == 0,0,0,0;
expected: size 100 50 # transparent
- name: initial.reset.different
desc: Changing size resets canvas to transparent black
testing:
- initial.reset
code: |
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 50, 50);
@assert pixel 20,20 == 255,0,0,255;
canvas.width = 50;
@assert pixel 20,20 == 0,0,0,0;
expected: size 50 50 # transparent
- name: initial.reset.same
desc: Setting size (not changing the value) resets canvas to transparent black
testing:
- initial.reset
code: |
canvas.width = 100;
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 50, 50);
@assert pixel 20,20 == 255,0,0,255;
canvas.width = 100;
@assert pixel 20,20 == 0,0,0,0;
expected: size 100 50 # transparent
- name: initial.reset.path
desc: Resetting the canvas state resets the current path
testing:
- initial.reset
code: |
canvas.width = 100;
ctx.rect(0, 0, 100, 50);
canvas.width = 100;
ctx.fillStyle = '#f00';
ctx.fill();
@assert pixel 20,20 == 0,0,0,0;
expected: size 100 50 # transparent
- name: initial.reset.clip
desc: Resetting the canvas state resets the current clip region
testing:
- initial.reset
code: |
canvas.width = 100;
ctx.rect(0, 0, 1, 1);
ctx.clip();
canvas.width = 100;
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 50);
@assert pixel 20,20 == 0,255,0,255;
expected: green
- name: initial.reset.transform
desc: Resetting the canvas state resets the current transformation matrix
testing:
- initial.reset
code: |
canvas.width = 100;
ctx.scale(0.1, 0.1);
canvas.width = 100;
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 50);
@assert pixel 20,20 == 0,255,0,255;
expected: green
- name: initial.reset.gradient
desc: Resetting the canvas state does not invalidate any existing gradients
testing:
- initial.reset
code: |
canvas.width = 50;
var g = ctx.createLinearGradient(0, 0, 100, 0);
g.addColorStop(0, '#0f0');
g.addColorStop(1, '#0f0');
canvas.width = 100;
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = g;
ctx.fillRect(0, 0, 100, 50);
@assert pixel 50,25 == 0,255,0,255;
expected: green
- name: initial.reset.pattern
desc: Resetting the canvas state does not invalidate any existing patterns
testing:
- initial.reset
code: |
canvas.width = 30;
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 30, 50);
var p = ctx.createPattern(canvas, 'repeat-x');
canvas.width = 100;
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = p;
ctx.fillRect(0, 0, 100, 50);
@assert pixel 50,25 == 0,255,0,255;
expected: green
# See tests2d.yaml for initial.reset.2dstate
- name: context.emptystring
desc: getContext with empty string returns null
testing:
- context.unrecognised
code: |
@assert canvas.getContext("") === null;
- name: context.unrecognised.badname
desc: getContext with unrecognised context name returns null
testing:
- context.unrecognised
code: |
@assert canvas.getContext('This is not an implemented context in any real browser') === null;
- name: context.unrecognised.badsuffix
desc: Context name "2d" plus a suffix is unrecognised
testing:
- context.unrecognised
code: |
@assert canvas.getContext("2d#") === null;
- name: context.unrecognised.nullsuffix
desc: Context name "2d" plus a "\0" suffix is unrecognised
testing:
- context.unrecognised
code: |
@assert canvas.getContext("2d\0") === null;
- name: context.unrecognised.unicode
desc: Context name which kind of looks like "2d" is unrecognised
testing:
- context.unrecognised
code: |
@assert canvas.getContext("2\uFF44") === null; // Fullwidth Latin Small Letter D
- name: context.casesensitive
desc: Context name "2D" is unrecognised; matching is case sensitive
testing:
- context.unrecognised
code: |
@assert canvas.getContext('2D') === null;
- name: context.arguments.missing
notes: *bindings
testing:
- canvas.getContext
code: |
@assert throws TypeError canvas.getContext(); @moz-todo
- name: toBlob.png
desc: toBlob with image/png returns a PNG Blob
testing:
- toBlob.png
code: |
canvas.toBlob(function(data){
@assert data.type === "image/png";
}, 'image/png');
- name: toBlob.jpeg
desc: toBlob with image/jpeg returns a JPEG Blob
testing:
- toBlob.jpeg
code: |
canvas.toBlob(function(data){
@assert data.type === "image/jpeg";
}, 'image/jpeg');
- name: toDataURL.default
desc: toDataURL with no arguments returns a PNG
testing:
- toDataURL.noarguments
code: |
var data = canvas.toDataURL();
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.png
desc: toDataURL with image/png returns a PNG
testing:
- toDataURL.png
- toDataURL.witharguments
code: |
var data = canvas.toDataURL('image/png');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.jpg
desc: toDataURL with image/jpg is invalid type hence returns a PNG
testing:
- toDataURL.jpg
- toDataURL.witharguments
code: |
var data = canvas.toDataURL('image/jpg');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.bogustype
desc: toDataURL with a syntactically invalid type returns a PNG
testing:
- toDataURL.unrecognised
code: |
var data = canvas.toDataURL('bogus');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.unrecognised
desc: toDataURL with an unhandled type returns a PNG
testing:
- toDataURL.unrecognised
code: |
var data = canvas.toDataURL('image/example');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.lowercase.ascii
desc: toDataURL type is case-insensitive
testing:
- toDataURL.lowercase
code: |
var data = canvas.toDataURL('ImAgE/PnG');
@assert data =~ /^data:image\/png[;,]/;
// If JPEG is supported at all, it must be supported case-insensitively
data = canvas.toDataURL('image/jpeg');
if (data.match(/^data:image\/jpeg[;,]/)) {
data = canvas.toDataURL('ImAgE/JpEg');
@assert data =~ /^data:image\/jpeg[;,]/;
}
- name: toDataURL.lowercase.unicode
desc: toDataURL type is ASCII-case-insensitive
testing:
- toDataURL.lowercase
code: |
// Use LATIN CAPITAL LETTER I WITH DOT ABOVE (Unicode lowercase is "i")
var data = canvas.toDataURL('\u0130mage/png');
@assert data =~ /^data:image\/png[;,]/;
var data = canvas.toDataURL('\u0130mage/jpeg');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.arguments.1
desc: toDataURL ignores extra arguments
testing:
- toDataURL.arguments
code: |
var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.arguments.2
desc: toDataURL ignores extra arguments
testing:
- toDataURL.arguments
code: |
var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception', 'and another');
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.arguments.3
desc: toDataURL ignores extra arguments
testing:
- toDataURL.arguments
code: |
// More arguments that should not raise exceptions
var data = canvas.toDataURL('image/png', null, null, null);
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.nocontext
desc: toDataURL works before any context has been got
testing:
- toDataURL.noarguments
code: |
var canvas2 = document.createElement('canvas');
var data = canvas2.toDataURL();
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.zerosize
desc: toDataURL on zero-size canvas returns 'data:,'
testing:
- toDataURL.zerosize
canvas: width="0" height="0"
code: |
var data = canvas.toDataURL();
@assert data === 'data:,';
- name: toDataURL.zerowidth
desc: toDataURL on zero-size canvas returns 'data:,'
testing:
- toDataURL.zerosize
canvas: width="0"
code: |
var data = canvas.toDataURL();
@assert data === 'data:,';
- name: toDataURL.zeroheight
desc: toDataURL on zero-size canvas returns 'data:,'
testing:
- toDataURL.zerosize
canvas: height="0"
code: |
var data = canvas.toDataURL();
@assert data === 'data:,';
- name: toDataURL.large1
DISABLED: just testing implementation limits, and tends to crash
canvas: width="30000" height="1"
code: |
var data = canvas.toDataURL();
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.large2
DISABLED: just testing implementation limits, and tends to crash
canvas: width="32767" height="1"
code: |
var data = canvas.toDataURL();
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.large3
DISABLED: just testing implementation limits, and tends to crash
canvas: width="32768" height="1"
code: |
var data = canvas.toDataURL();
@assert data =~ /^data:image\/png[;,]/;
- name: toDataURL.png.primarycolours
desc: toDataURL with PNG handles simple colours correctly
testing:
- toDataURL.png
code: |
ctx.fillStyle = '#ff0';
ctx.fillRect(0, 0, 25, 40);
ctx.fillStyle = '#0ff';
ctx.fillRect(25, 0, 50, 40);
ctx.fillStyle = '#00f';
ctx.fillRect(75, 0, 25, 40);
ctx.fillStyle = '#fff';
ctx.fillRect(0, 40, 100, 10);
var data = canvas.toDataURL();
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
var img = new Image();
deferTest();
img.onload = t.step_func_done(function ()
{
ctx.drawImage(img, 0, 0);
@assert pixel 12,20 == 255,255,0,255;
@assert pixel 50,20 == 0,255,255,255;
@assert pixel 87,20 == 0,0,255,255;
@assert pixel 50,45 == 255,255,255,255;
});
img.src = data;
expected: |
size 100 50
cr.set_source_rgb(1, 1, 0)
cr.rectangle(0, 0, 25, 40)
cr.fill()
cr.set_source_rgb(0, 1, 1)
cr.rectangle(25, 0, 50, 40)
cr.fill()
cr.set_source_rgb(0, 0, 1)
cr.rectangle(75, 0, 25, 40)
cr.fill()
cr.set_source_rgb(1, 1, 1)
cr.rectangle(0, 40, 100, 10)
cr.fill()
- name: toDataURL.png.complexcolours
desc: toDataURL with PNG handles non-primary and non-solid colours correctly
testing:
- toDataURL.png
code: |
// (These values are chosen to survive relatively alright through being premultiplied)
ctx.fillStyle = 'rgba(1, 3, 254, 1)';
ctx.fillRect(0, 0, 25, 25);
ctx.fillStyle = 'rgba(8, 252, 248, 0.75)';
ctx.fillRect(25, 0, 25, 25);
ctx.fillStyle = 'rgba(6, 10, 250, 0.502)';
ctx.fillRect(50, 0, 25, 25);
ctx.fillStyle = 'rgba(12, 16, 244, 0.25)';
ctx.fillRect(75, 0, 25, 25);
var img = new Image();
deferTest();
img.onload = t.step_func_done(function ()
{
ctx.drawImage(img, 0, 25);
// (The alpha values do not really survive float->int conversion, so just
// do approximate comparisons)
@assert pixel 12,40 == 1,3,254,255;
@assert pixel 37,40 ==~ 8,252,248,191 +/- 2;
@assert pixel 62,40 ==~ 6,10,250,127 +/- 4;
@assert pixel 87,40 ==~ 12,16,244,63 +/- 8;
});
img.src = canvas.toDataURL();
expected: |
size 100 50
cr.set_source_rgba(1/255., 3/255., 254/255., 1)
cr.rectangle(0, 0, 25, 50)
cr.fill()
cr.set_source_rgba(8/255., 252/255., 248/255., 191/255.)
cr.rectangle(25, 0, 25, 50)
cr.fill()
cr.set_source_rgba(6/255., 10/255., 250/255., 127/255.)
cr.rectangle(50, 0, 25, 50)
cr.fill()
cr.set_source_rgba(12/255., 16/255., 244/255., 63/255.)
cr.rectangle(75, 0, 25, 50)
cr.fill()
- name: toDataURL.jpeg.primarycolours
desc: toDataURL with JPEG handles simple colours correctly
testing:
- toDataURL.jpeg
code: |
ctx.fillStyle = '#ff0';
ctx.fillRect(0, 0, 25, 40);
ctx.fillStyle = '#0ff';
ctx.fillRect(25, 0, 50, 40);
ctx.fillStyle = '#00f';
ctx.fillRect(75, 0, 25, 40);
ctx.fillStyle = '#fff';
ctx.fillRect(0, 40, 100, 10);
var data = canvas.toDataURL('image/jpeg'); // it is okay if this returns a PNG instead
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
var img = new Image();
deferTest();
img.onload = t.step_func_done(function ()
{
ctx.drawImage(img, 0, 0);
@assert pixel 12,20 ==~ 255,255,0,255 +/- 8;
@assert pixel 50,20 ==~ 0,255,255,255 +/- 8;
@assert pixel 87,20 ==~ 0,0,255,255 +/- 8;
@assert pixel 50,45 ==~ 255,255,255,255 +/- 8;
});
img.src = data;
expected: |
size 100 50
cr.set_source_rgb(1, 1, 0)
cr.rectangle(0, 0, 25, 40)
cr.fill()
cr.set_source_rgb(0, 1, 1)
cr.rectangle(25, 0, 50, 40)
cr.fill()
cr.set_source_rgb(0, 0, 1)
cr.rectangle(75, 0, 25, 40)
cr.fill()
cr.set_source_rgb(1, 1, 1)
cr.rectangle(0, 40, 100, 10)
cr.fill()
- name: toDataURL.jpeg.alpha
desc: toDataURL with JPEG composites onto black
testing:
- toDataURL.jpeg
- toDataURL.noalpha
code: |
ctx.fillStyle = 'rgba(128, 255, 128, 0.5)';
ctx.fillRect(0, 0, 100, 50);
ctx.globalCompositeOperation = 'destination-over'; // should be ignored by toDataURL
var data = canvas.toDataURL('image/jpeg');
ctx.globalCompositeOperation = 'source-over';
if (!data.match(/^data:image\/jpeg[;,]/)) {
@assert true;
} else {
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
var img = new Image();
deferTest();
img.onload = t.step_func_done(function ()
{
ctx.drawImage(img, 0, 0);
@assert pixel 50,25 ==~ 63,127,63,255 +/- 8;
});
img.src = data;
}
expected: |
size 100 50
cr.set_source_rgb(0.25, 0.5, 0.25)
cr.rectangle(0, 0, 100, 50)
cr.fill()
- name: toDataURL.jpeg.quality.basic
desc: toDataURL with JPEG uses the quality parameter
testing:
- toDataURL.jpeg.quality
mozilla: { throws }
code: |
ctx.fillStyle = '#00f';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = '#0ff';
ctx.fillRect(0, 3, 100, 1);
// Check for JPEG support first
var data = canvas.toDataURL('image/jpeg');
if (!data.match(/^data:image\/jpeg[;,]/)) {
@assert true;
} else {
var data_hi = canvas.toDataURL('image/jpeg', 0.99);
var data_lo = canvas.toDataURL('image/jpeg', 0.01);
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
deferTest();
var img_hi = new Image();
img_hi.onload = function ()
{
var img_lo = new Image();
img_lo.onload = t.step_func_done(function ()
{
ctx.drawImage(img_hi, 0, 0, 50, 50, 0, 0, 50, 50);
ctx.drawImage(img_lo, 0, 0, 50, 50, 50, 0, 50, 50);
@assert data_hi.length > data_lo.length;
@assert pixel 25,25 ==~ 0,0,255,255 +/- 8;
@assert pixel 75,25 ==~ 0,0,255,255 +/- 32;
});
img_lo.src = data_lo;
};
img_hi.src = data_hi;
}
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, 3, 100, 1)
cr.fill()
- name: toDataURL.jpeg.quality.notnumber
desc: toDataURL with JPEG handles non-numeric quality parameters
testing:
- toDataURL.jpeg.nan
code: |
ctx.fillStyle = '#00f';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = '#0ff';
ctx.fillRect(0, 3, 100, 1);
// Check for JPEG support first
var data = canvas.toDataURL('image/jpeg');
if (!data.match(/^data:image\/jpeg[;,]/)) {
@assert true;
} else {
@assert canvas.toDataURL('image/jpeg', 'bogus') === data;
@assert canvas.toDataURL('image/jpeg', {}) === data;
@assert canvas.toDataURL('image/jpeg', null) === data;
@assert canvas.toDataURL('image/jpeg', undefined) === data;
@assert canvas.toDataURL('image/jpeg', true) === data;
@assert canvas.toDataURL('image/jpeg', '0.01') === data;
}
- name: toDataURL.jpeg.quality.outsiderange
desc: toDataURL with JPEG handles out-of-range quality parameters
testing:
- toDataURL.jpeg.range
code: |
ctx.fillStyle = '#00f';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = '#0ff';
ctx.fillRect(0, 3, 100, 1);
// Check for JPEG support first
var data = canvas.toDataURL('image/jpeg');
if (!data.match(/^data:image\/jpeg[;,]/)) {
@assert true;
} else {
@assert canvas.toDataURL('image/jpeg', 10) === data;
@assert canvas.toDataURL('image/jpeg', -10) === data;
@assert canvas.toDataURL('image/jpeg', 1.01) === data;
@assert canvas.toDataURL('image/jpeg', -0.01) === data;
@assert canvas.toDataURL('image/jpeg', 1).length >= canvas.toDataURL('image/jpeg', 0.9).length;
@assert canvas.toDataURL('image/jpeg', 0).length <= canvas.toDataURL('image/jpeg', 0.1).length;
}
# TODO: work out what security exception should be thrown
# TODO: test same-origin vs same-host
- name: security.drawImage.image.sub
desc: drawImage of different-origin image makes the canvas origin-unclean
mozilla: { disabled } # relies on external resources
testing:
- security.drawImage.image
- security.toDataURL
- security.getImageData
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.drawImage.canvas.sub
desc: drawImage of unclean canvas makes the canvas origin-unclean
mozilla: { disabled } # relies on external resources
testing:
- security.drawImage.canvas
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var canvas2 = document.createElement('canvas');
canvas2.width = 100;
canvas2.height = 50;
var ctx2 = canvas2.getContext('2d');
ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
ctx.drawImage(canvas2, 0, 0);
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.pattern.create.sub
desc: Creating an unclean pattern does not make the canvas origin-unclean
mozilla: { disabled } # relies on external resources
testing:
- security.start
images:
- http://{{domains[www]}}:{{ports[http][0]}}/images/yellow.png
code: |
var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
canvas.toDataURL();
ctx.getImageData(0, 0, 1, 1);
@assert true; // okay if there was no exception
- name: security.pattern.cross.sub
desc: Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas
mozilla: { disabled } # relies on external resources
testing:
- security.start
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var canvas2 = document.createElement('canvas');
canvas2.width = 100;
canvas2.height = 50;
var ctx2 = canvas2.getContext('2d');
var p = ctx2.createPattern(document.getElementById('yellow.png'), 'repeat');
ctx.fillStyle = p;
ctx.fillRect(0, 0, 100, 50);
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
canvas2.toDataURL();
ctx2.getImageData(0, 0, 1, 1);
- name: security.pattern.canvas.timing.sub
desc: Pattern safety depends on whether the source was origin-clean, not on whether it still is clean
notes: Disagrees with spec on "is" vs "was"
mozilla: { disabled } # relies on external resources
testing:
- security.start
- security.fillStyle.canvas
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
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 p = ctx.createPattern(canvas2, 'repeat');
ctx2.drawImage(document.getElementById('yellow.png'), 0, 0); // make canvas2 origin-unclean
ctx.fillStyle = p;
ctx.fillRect(0, 0, 100, 50);
canvas.toDataURL();
ctx.getImageData(0, 0, 1, 1);
@assert true; // okay if there was no exception
- name: security.pattern.image.fillStyle.sub
desc: Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean
mozilla: { disabled } # relies on external resources
testing:
- security.fillStyle.image
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
ctx.fillStyle = p;
ctx.fillStyle = 'red';
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.pattern.canvas.fillStyle.sub
desc: Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean
mozilla: { bug: 354127, disabled } # relies on external resources
testing:
- security.fillStyle.canvas
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var canvas2 = document.createElement('canvas');
canvas2.width = 100;
canvas2.height = 50;
var ctx2 = canvas2.getContext('2d');
ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
var p = ctx.createPattern(canvas2, 'repeat');
ctx.fillStyle = p;
ctx.fillStyle = 'red';
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.pattern.image.strokeStyle.sub
desc: Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean
mozilla: { disabled } # relies on external resources
testing:
- security.strokeStyle.image
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
ctx.strokeStyle = p;
ctx.strokeStyle = 'red';
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.pattern.canvas.strokeStyle.sub
desc: Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean
mozilla: { bug: 354127, disabled } # relies on external resources
testing:
- security.strokeStyle.canvas
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
var canvas2 = document.createElement('canvas');
canvas2.width = 100;
canvas2.height = 50;
var ctx2 = canvas2.getContext('2d');
ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
var p = ctx.createPattern(canvas2, 'repeat');
ctx.strokeStyle = p;
ctx.strokeStyle = 'red';
@assert throws SECURITY_ERR canvas.toDataURL();
@assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
- name: security.dataURI
desc: 'data: URIs do not count as different-origin, and do not taint the canvas'
mozilla: { disabled, bug: 417836 } # can't do "todo" so just disable it
code: |
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 50);
var data = canvas.toDataURL();
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
var img = new Image();
deferTest();
img.onload = t.step_func_done(function ()
{
ctx.drawImage(img, 0, 0);
canvas.toDataURL(); // should be permitted
@assert pixel 50,25 == 0,255,0,255;
});
img.src = data;
expected: green
- name: security.reset.sub
desc: Resetting the canvas state does not reset the origin-clean flag
mozilla: { disabled } # relies on external resources
testing:
- initial.reset
images:
- http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
code: |
canvas.width = 50;
ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
@assert throws SECURITY_ERR canvas.toDataURL();
canvas.width = 100;
@assert throws SECURITY_ERR canvas.toDataURL();