mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
1078 lines
34 KiB
YAML
1078 lines
34 KiB
YAML
# 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", "\r\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)
|
|
# We need to replace \r with 
 because \r\n gets converted to \n in the HTML parser.
|
|
htmlString = string.replace('\r', '
')
|
|
tests.append( {
|
|
"name": "size.attributes.parse.%s" % name,
|
|
"desc": "Parsing of non-negative integers",
|
|
"testing": testing,
|
|
"canvas": 'width="%s" height="%s"' % (htmlString, htmlString),
|
|
"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: 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 no_context_data = canvas.toDataURL();
|
|
var ctx = canvas.getContext('2d');
|
|
ctx.rect(0, 0, 100, 50);
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0)";
|
|
ctx.fill();
|
|
var data = canvas.toDataURL();
|
|
assert_equals(no_context_data, data);
|
|
|
|
- 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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
desc: drawImage of unclean canvas makes the canvas origin-unclean
|
|
mozilla: { disabled } # relies on external resources
|
|
testing:
|
|
- security.drawImage.canvas
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
desc: Creating an unclean pattern does not make the canvas origin-unclean
|
|
mozilla: { disabled } # relies on external resources
|
|
testing:
|
|
- security.start
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
desc: Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas
|
|
mozilla: { disabled } # relies on external resources
|
|
testing:
|
|
- security.start
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
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
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
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
|
|
desc: Resetting the canvas state resets the origin-clean flag
|
|
mozilla: { disabled } # relies on external resources
|
|
testing:
|
|
- initial.reset
|
|
scripts:
|
|
- /common/get-host-info.sub.js
|
|
script-variants:
|
|
cross: data:text/javascript,addCrossOriginYellowImage()
|
|
redirect: data:text/javascript,addCrossOriginRedirectYellowImage()
|
|
code: |
|
|
canvas.width = 50;
|
|
ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
|
|
@assert throws SECURITY_ERR canvas.toDataURL();
|
|
canvas.width = 100;
|
|
canvas.toDataURL();
|
|
ctx.getImageData(0, 0, 1, 1);
|
|
@assert true; // okay if there was no exception
|