mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 04:05:32 +00:00
1325009ca4
MozReview-Commit-ID: GmGgeZxHy0j --HG-- rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_1_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_1_2.sub.html.sub.headers rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_2_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_2_2.sub.html.sub.headers rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_3_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_3_2.sub.html.sub.headers rename : testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/test.html => testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/resources/frameElement-nested-frame.html rename : testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/testcase3.html => testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/resources/frameElement-window-post.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationAvailability_onchange-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationAvailability_onchange-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_onmessage-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_onmessage-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_send-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_send-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_error.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_error.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.html => testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/getAvailability_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/getAvailability_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_notfound_error.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_notfound_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotallowed-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotallowed-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotfound-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotfound-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_error.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_sandboxing_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_sandboxing_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_unsettledpromise-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_unsettledpromise-manual.https.html rename : testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.html => testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html rename : testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.html => testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html rename : testing/web-platform/tests/webdriver/util/http_request.py => testing/web-platform/tests/webdriver/support/http_request.py
9220 lines
282 KiB
YAML
9220 lines
282 KiB
YAML
- meta: |
|
|
state = [ # some non-default values to test with
|
|
('strokeStyle', '"#ff0000"'),
|
|
('fillStyle', '"#ff0000"'),
|
|
('globalAlpha', 0.5),
|
|
('lineWidth', 0.5),
|
|
('lineCap', '"round"'),
|
|
('lineJoin', '"round"'),
|
|
('miterLimit', 0.5),
|
|
('shadowOffsetX', 5),
|
|
('shadowOffsetY', 5),
|
|
('shadowBlur', 5),
|
|
('shadowColor', '"#ff0000"'),
|
|
('globalCompositeOperation', '"copy"'),
|
|
]
|
|
for key,value in state:
|
|
tests.append( {
|
|
'name': '2d.state.saverestore.%s' % key,
|
|
'desc': 'save()/restore() works for %s' % key,
|
|
'testing': [ '2d.state.%s' % key ],
|
|
'code':
|
|
"""// Test that restore() undoes any modifications
|
|
var old = ctx.%(key)s;
|
|
ctx.save();
|
|
ctx.%(key)s = %(value)s;
|
|
ctx.restore();
|
|
@assert ctx.%(key)s === old;
|
|
|
|
// Also test that save() doesn't modify the values
|
|
ctx.%(key)s = %(value)s;
|
|
old = ctx.%(key)s;
|
|
// we're not interested in failures caused by get(set(x)) != x (e.g.
|
|
// from rounding), so compare against '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':
|
|
"""offscreenCanvas.width = 100;
|
|
var default_val;
|
|
""" + "".join(
|
|
"""
|
|
default_val = ctx.%(key)s;
|
|
ctx.%(key)s = %(value)s;
|
|
offscreenCanvas.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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.transformation.scale.zero
|
|
desc: scale() with a scale factor of zero works
|
|
testing:
|
|
- 2d.transformation.scale
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.save();
|
|
ctx.translate(50, 0);
|
|
ctx.scale(0, 1);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.restore();
|
|
ctx.save();
|
|
ctx.translate(0, 25);
|
|
ctx.scale(1, 0);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.restore();
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.composite.globalAlpha.image
|
|
testing:
|
|
- 2d.composite.globalAlpha.image
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 2,253,0,255;
|
|
});
|
|
|
|
- name: 2d.composite.globalAlpha.canvas
|
|
testing:
|
|
- 2d.composite.globalAlpha.image
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.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(offscreenCanvas2, 0, 0);
|
|
@assert pixel 50,25 ==~ 2,253,0,255;
|
|
|
|
- name: 2d.composite.globalAlpha.imagepattern
|
|
testing:
|
|
- 2d.composite.globalAlpha.image
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.fillStyle = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.composite.globalAlpha.canvaspattern
|
|
testing:
|
|
- 2d.composite.globalAlpha.image
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#f00';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- name: 2d.composite.globalAlpha.canvascopy
|
|
testing:
|
|
- 2d.composite.globalAlpha.image
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.globalCompositeOperation = 'copy'
|
|
ctx.globalAlpha = 0.51;
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,130;
|
|
|
|
|
|
- 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)),
|
|
} )
|
|
|
|
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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/yellow75.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ %s +/- 5;
|
|
});
|
|
""" % (dest, op, to_test(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 offscreenCanvas2 = new OffscreenCanvas(offscreenCanvas.width, offscreenCanvas.height);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/yellow75.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx2.drawImage(response, 0, 0);
|
|
ctx.fillStyle = 'rgba%s';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.globalCompositeOperation = '%s';
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
@assert pixel 50,25 ==~ %s +/- 5;
|
|
});
|
|
""" % (dest, op, to_test(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)),
|
|
} )
|
|
|
|
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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/yellow.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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)),
|
|
} )
|
|
|
|
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 offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
@assert pixel 50,25 ==~ %s +/- 5;
|
|
""" % (dest, op, to_test(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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/yellow.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.fillStyle = ctx.createPattern(response, 'no-repeat');
|
|
ctx.fillRect(0, 50, 100, 50);
|
|
@assert pixel 50,25 ==~ %s +/- 5;
|
|
});
|
|
""" % (dest, op, to_test(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),
|
|
} )
|
|
|
|
- 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.clear
|
|
code: |
|
|
ctx.globalCompositeOperation = 'xor';
|
|
ctx.globalCompositeOperation = 'clear';
|
|
@assert ctx.globalCompositeOperation === 'clear';
|
|
|
|
- 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, ""),
|
|
# css-color-4 rgb() color function
|
|
# https://drafts.csswg.org/css-color/#numeric-rgb
|
|
('css-color-4-rgb-1', 'rgb(0, 255.0, 0)', 0,255,0,255, ""),
|
|
('css-color-4-rgb-2', 'rgb(0, 255, 0, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-rgb-3', 'rgb(0, 255, 0, 20%)', 0,255,0,51, ""),
|
|
('css-color-4-rgb-4', 'rgb(0 255 0)', 0,255,0,255, ""),
|
|
('css-color-4-rgb-5', 'rgb(0 255 0 / 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-rgb-6', 'rgb(0 255 0 / 20%)', 0,255,0,51, ""),
|
|
('css-color-4-rgba-1', 'rgba(0, 255.0, 0)', 0,255,0,255, ""),
|
|
('css-color-4-rgba-2', 'rgba(0, 255, 0, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-rgba-3', 'rgba(0, 255, 0, 20%)', 0,255,0,51, ""),
|
|
('css-color-4-rgba-4', 'rgba(0 255 0)', 0,255,0,255, ""),
|
|
('css-color-4-rgba-5', 'rgba(0 255 0 / 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-rgba-6', 'rgba(0 255 0 / 20%)', 0,255,0,51, ""),
|
|
# css-color-4 hsl() color function
|
|
# https://drafts.csswg.org/css-color/#the-hsl-notation
|
|
('css-color-4-hsl-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsl-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsl-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsl-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""),
|
|
('css-color-4-hsl-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsl-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsl-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsl-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsl-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsla-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsla-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsla-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsla-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""),
|
|
('css-color-4-hsla-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
|
|
('css-color-4-hsla-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsla-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsla-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""),
|
|
('css-color-4-hsla-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,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),
|
|
}
|
|
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(100%, 0, 0)'),
|
|
('rgb-3', 'rgb(255, - 1, 0)'),
|
|
('rgba-1', 'rgba(100%, 0, 0, 1)'),
|
|
('rgba-2', 'rgba(255, 0, 0, 1. 0)'),
|
|
('rgba-3', 'rgba(255, 0, 0, 1.)'),
|
|
('rgba-4', 'rgba(255, 0, 0, '),
|
|
('rgba-5', 'rgba(255, 0, 0, 1,)'),
|
|
('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.%, 50%)'),
|
|
('hsl-6', 'hsl(0, 100%, 50%,)'),
|
|
('hsla-1', 'hsla(0%, 100%, 50%, 1)'),
|
|
('hsla-2', 'hsla(0, 0, 50%, 1)'),
|
|
('hsla-3', 'hsla(0, 0, 50%, 1,)'),
|
|
('name-1', 'darkbrown'),
|
|
('name-2', 'firebrick1'),
|
|
('name-3', 'red blue'),
|
|
('name-4', '"red"'),
|
|
('name-5', '"red'),
|
|
# css-color-4 color function
|
|
# comma and comma-less expressions should not mix together.
|
|
('css-color-4-rgb-1', 'rgb(255, 0, 0 / 1)'),
|
|
('css-color-4-rgb-2', 'rgb(255 0 0, 1)'),
|
|
('css-color-4-rgb-3', 'rgb(255, 0 0)'),
|
|
('css-color-4-rgba-1', 'rgba(255, 0, 0 / 1)'),
|
|
('css-color-4-rgba-2', 'rgba(255 0 0, 1)'),
|
|
('css-color-4-rgba-3', 'rgba(255, 0 0)'),
|
|
('css-color-4-hsl-1', 'hsl(0, 100%, 50% / 1)'),
|
|
('css-color-4-hsl-2', 'hsl(0 100% 50%, 1)'),
|
|
('css-color-4-hsl-3', 'hsl(0, 100% 50%)'),
|
|
('css-color-4-hsla-1', 'hsla(0, 100%, 50% / 1)'),
|
|
('css-color-4-hsla-2', 'hsla(0 100% 50%, 1)'),
|
|
('css-color-4-hsla-3', 'hsla(0, 100% 50%)'),
|
|
# trailing slash
|
|
('css-color-4-rgb-4', 'rgb(0 0 0 /)'),
|
|
('css-color-4-rgb-5', 'rgb(0, 0, 0 /)'),
|
|
('css-color-4-hsl-4', 'hsl(0 100% 50% /)'),
|
|
('css-color-4-hsl-5', 'hsl(0, 100%, 50% /)'),
|
|
]:
|
|
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,
|
|
}
|
|
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.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;
|
|
|
|
- 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;
|
|
|
|
- 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.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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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 ==~ 190,190,65,65 +/- 3;
|
|
@assert pixel 50,25 ==~ 126,126,128,128 +/- 3;
|
|
@assert pixel 75,25 ==~ 62,62,192,192 +/- 3;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- name: 2d.gradient.interpolate.multiple
|
|
testing:
|
|
- 2d.gradient.interpolate.linear
|
|
code: |
|
|
offscreenCanvas.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;
|
|
|
|
- name: 2d.gradient.interpolate.overlap
|
|
testing:
|
|
- 2d.gradient.interpolate.overlap
|
|
code: |
|
|
offscreenCanvas.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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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 offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var g = offscreenCanvas2.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;
|
|
|
|
- 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
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.pattern.basic.image
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.basic.canvas
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
var pattern = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- name: 2d.pattern.basic.zerocanvas
|
|
testing:
|
|
- 2d.pattern.zerocanvas
|
|
code: |
|
|
offscreenCanvas.width = 0;
|
|
offscreenCanvas.height = 10;
|
|
@assert offscreenCanvas.width === 0;
|
|
@assert offscreenCanvas.height === 10;
|
|
@assert throws INVALID_STATE_ERR ctx.createPattern(offscreenCanvas, 'repeat');
|
|
offscreenCanvas.width = 10;
|
|
offscreenCanvas.height = 0;
|
|
@assert offscreenCanvas.width === 10;
|
|
@assert offscreenCanvas.height === 0;
|
|
@assert throws INVALID_STATE_ERR ctx.createPattern(offscreenCanvas, 'repeat');
|
|
offscreenCanvas.width = 0;
|
|
offscreenCanvas.height = 0;
|
|
@assert offscreenCanvas.width === 0;
|
|
@assert offscreenCanvas.height === 0;
|
|
@assert throws INVALID_STATE_ERR ctx.createPattern(offscreenCanvas, 'repeat');
|
|
|
|
- name: 2d.pattern.basic.nocontext
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var pattern = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- name: 2d.pattern.image.undefined
|
|
testing:
|
|
- 2d.pattern.IDL
|
|
code: |
|
|
@assert throws TypeError ctx.createPattern(undefined, 'repeat');
|
|
|
|
- name: 2d.pattern.image.null
|
|
testing:
|
|
- 2d.pattern.IDL
|
|
code: |
|
|
@assert throws TypeError ctx.createPattern(null, 'repeat');
|
|
|
|
- name: 2d.pattern.image.string
|
|
testing:
|
|
- 2d.pattern.IDL
|
|
code: |
|
|
@assert throws TypeError ctx.createPattern('../images/red.png', 'repeat');
|
|
|
|
- name: 2d.pattern.repeat.empty
|
|
testing:
|
|
- 2d.pattern.missing
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green-1x1.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, "");
|
|
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;
|
|
});
|
|
|
|
- name: 2d.pattern.repeat.null
|
|
testing:
|
|
- 2d.pattern.unrecognised
|
|
code: |
|
|
@assert ctx.createPattern(offscreenCanvas, null) != null;
|
|
|
|
- name: 2d.pattern.repeat.undefined
|
|
testing:
|
|
- 2d.pattern.unrecognised
|
|
code: |
|
|
@assert throws SYNTAX_ERR ctx.createPattern(offscreenCanvas, undefined);
|
|
|
|
- name: 2d.pattern.repeat.unrecognised
|
|
testing:
|
|
- 2d.pattern.unrecognised
|
|
code: |
|
|
@assert throws SYNTAX_ERR ctx.createPattern(offscreenCanvas, "invalid");
|
|
|
|
- name: 2d.pattern.repeat.unrecognisednull
|
|
testing:
|
|
- 2d.pattern.unrecognised
|
|
code: |
|
|
@assert throws SYNTAX_ERR ctx.createPattern(offscreenCanvas, "null");
|
|
|
|
- name: 2d.pattern.repeat.case
|
|
testing:
|
|
- 2d.pattern.exact
|
|
code: |
|
|
@assert throws SYNTAX_ERR ctx.createPattern(offscreenCanvas, "Repeat");
|
|
|
|
- name: 2d.pattern.repeat.nullsuffix
|
|
testing:
|
|
- 2d.pattern.exact
|
|
code: |
|
|
@assert throws SYNTAX_ERR ctx.createPattern(offscreenCanvas, "repeat\0");
|
|
|
|
- name: 2d.pattern.modify.canvas1
|
|
testing:
|
|
- 2d.pattern.modify
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
var pattern = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- name: 2d.pattern.modify.canvas2
|
|
testing:
|
|
- 2d.pattern.modify
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
var pattern = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- name: 2d.pattern.crosscanvas
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var pattern = offscreenCanvas2.getContext('2d').createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.norepeat.basic
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.norepeat.outside
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.norepeat.coord1
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 50, 50);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(50, 0, 50, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.norepeat.coord2
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.norepeat.coord3
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeat.basic
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeat.outside
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, 'no-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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeat.coord1
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/rgrg-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, 'no-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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeat.coord2
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/grgr-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeat.coord3
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/rgrg-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, 'no-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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeatx.basic
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 16);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeatx.outside
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeatx.coord1
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeaty.basic
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 16, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.repeaty.outside
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- 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 promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red-16x16.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.pattern.paint.orientation.image
|
|
desc: Image patterns do not get flipped when painted
|
|
testing:
|
|
- 2d.pattern.painting
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/rrgg-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- 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 offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#f00';
|
|
ctx2.fillRect(0, 0, 100, 25);
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 25, 100, 25);
|
|
var pattern = ctx.createPattern(offscreenCanvas2, '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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, -50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
});
|
|
|
|
- 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;
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/transparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, -50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
});
|
|
|
|
- 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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 50, -50);
|
|
ctx.shadowColor = '#f00';
|
|
ctx.drawImage(response, -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;
|
|
});
|
|
|
|
- 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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/transparent50.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, -50);
|
|
@assert pixel 50,25 ==~ 127,0,127,255;
|
|
});
|
|
|
|
- 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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- 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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- name: 2d.shadow.canvas.basic
|
|
desc: Shadows are drawn for canvases
|
|
testing:
|
|
- 2d.shadow.render
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.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(offscreenCanvas2, 0, -50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
|
|
- name: 2d.shadow.canvas.transparent.1
|
|
desc: Shadows are not drawn for transparent canvases
|
|
testing:
|
|
- 2d.shadow.render
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.shadowColor = '#f00';
|
|
ctx.shadowOffsetY = 50;
|
|
ctx.drawImage(offscreenCanvas2, 0, -50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
|
|
- name: 2d.shadow.canvas.transparent.2
|
|
desc: Shadows are not drawn for transparent parts of canvases
|
|
testing:
|
|
- 2d.shadow.render
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.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(offscreenCanvas2, 50, -50);
|
|
ctx.shadowColor = '#f00';
|
|
ctx.drawImage(offscreenCanvas2, -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;
|
|
|
|
- name: 2d.shadow.canvas.alpha
|
|
desc: Shadows are drawn correctly for partially-transparent canvases
|
|
testing:
|
|
- 2d.shadow.render
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.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(offscreenCanvas2, 0, -50);
|
|
@assert pixel 50,25 ==~ 127,0,127,255;
|
|
|
|
- name: 2d.shadow.pattern.basic
|
|
desc: Shadows are drawn for fill patterns
|
|
testing:
|
|
- 2d.shadow.render
|
|
images:
|
|
- red.png
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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);
|
|
});
|
|
|
|
- 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 promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/transparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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);
|
|
});
|
|
|
|
- name: 2d.shadow.pattern.transparent.2
|
|
desc: Shadows are not drawn for transparent parts of fill patterns
|
|
testing:
|
|
- 2d.shadow.render
|
|
images:
|
|
- redtransparent.png
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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;
|
|
});
|
|
|
|
- name: 2d.shadow.pattern.alpha
|
|
desc: Shadows are drawn correctly for partially-transparent fill patterns
|
|
testing:
|
|
- 2d.shadow.render
|
|
images:
|
|
- transparent50.png
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/transparent50.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
var pattern = ctx.createPattern(response, '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);
|
|
});
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.shadow.gradient.transparent.2
|
|
desc: Shadows are not drawn for transparent parts of gradient fills
|
|
testing:
|
|
- 2d.shadow.render
|
|
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;
|
|
|
|
- name: 2d.shadow.gradient.alpha
|
|
desc: Shadows are drawn correctly for partially-transparent gradient fills
|
|
testing:
|
|
- 2d.shadow.render
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
# 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- name: 2d.drawImage.3arg
|
|
testing:
|
|
- 2d.drawImage.defaultsource
|
|
- 2d.drawImage.defaultdest
|
|
images:
|
|
- red.png
|
|
- green.png
|
|
code: |
|
|
var promise1 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
var promise2 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
Promise.all([promise1, promise2]).then(function(response1, response2) {
|
|
ctx.drawImage(response2, 0, 0);
|
|
ctx.drawImage(response1, -100, 0);
|
|
ctx.drawImage(response1, 100, 0);
|
|
ctx.drawImage(response1, 0, -50);
|
|
ctx.drawImage(response1, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.5arg
|
|
testing:
|
|
- 2d.drawImage.defaultsource
|
|
images:
|
|
- red.png
|
|
- green.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise1 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
var promise2 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
Promise.all([promise1, promise2]).then(function(response1, response2) {
|
|
ctx.drawImage(response2, 50, 0, 50, 50);
|
|
ctx.drawImage(response1, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.9arg.basic
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
images:
|
|
- green.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.9arg.sourcepos
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
images:
|
|
- rgrg-256x256.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/rgrg-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.9arg.sourcesize
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
images:
|
|
- rgrg-256x256.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/rgrg-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.9arg.destpos
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
images:
|
|
- red.png
|
|
- green.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise1 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
var promise2 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
Promise.all([promise1, promise2]).then(function(response1, response2) {
|
|
ctx.drawImage(response2, 0, 0, 100, 50, 0, 0, 100, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, -100, 0, 100, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, 100, 0, 100, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, 0, -50, 100, 50);
|
|
ctx.drawImage(response1, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.9arg.destsize
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
images:
|
|
- red.png
|
|
- green.png
|
|
code: |
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var promise1 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
var promise2 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
Promise.all([promise1, promise2]).then(function(response1, response2) {
|
|
ctx.drawImage(response2, 1, 1, 1, 1, 0, 0, 100, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, -50, 0, 50, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, 100, 0, 50, 50);
|
|
ctx.drawImage(response1, 0, 0, 100, 50, 0, -25, 100, 25);
|
|
ctx.drawImage(response1, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.canvas
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.getContext('2d');
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx2.fillRect(0, 0, 100, 50);
|
|
ctx.fillStyle = '#f00';
|
|
ctx.drawImage(offscreenCanvas2, 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;
|
|
|
|
- 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(offscreenCanvas, 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;
|
|
|
|
- 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(offscreenCanvas, 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;
|
|
|
|
- name: 2d.drawImage.null
|
|
testing:
|
|
- 2d.drawImage.IDL
|
|
code: |
|
|
@assert throws TypeError ctx.drawImage(null, 0, 0);
|
|
|
|
- name: 2d.drawImage.zerocanvas
|
|
testing:
|
|
- 2d.drawImage.zerocanvas
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
offscreenCanvas2.width = 10;
|
|
offscreenCanvas2.height = 0;
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
offscreenCanvas2.width = 0;
|
|
offscreenCanvas2.height = 0;
|
|
ctx.drawImage(offscreenCanvas2, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
|
|
- name: 2d.drawImage.wrongtype
|
|
desc: Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError
|
|
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);
|
|
|
|
- name: 2d.drawImage.floatsource
|
|
testing:
|
|
- 2d.drawImage.paint
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 10.1, 10.1, 0.1, 0.1, 0, 0, 100, 50);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 10, 10, 0, 1, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 10, 10, 1, 0, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 10, 10, 0, 0, 0, 0, 100, 50);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red-zerowidth.svg');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response, 0, 0, 100, 50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/ggrr-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 100, 78, -100, 50, 0, 0, 50, 50);
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/ggrr-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 100, 78, 50, 50, 0, 50, 50, -50);
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/ggrr-256x256.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 178, 50, -100, 0, 0, 50, 100);
|
|
ctx.drawImage(response, 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;
|
|
});
|
|
|
|
- name: 2d.drawImage.outsidesource
|
|
DISABLED: fix this to match the current spec (transparent black outside source)
|
|
testing:
|
|
- 2d.drawImage.outsidesource
|
|
code: |
|
|
var promise1 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
var promise2 = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
Promise.all([promise1, promise2]).then(function(response1, response2) {
|
|
ctx.drawImage(response2, 10.5, 10.5, 89.5, 39.5, 0, 0, 100, 50);
|
|
ctx.drawImage(response2, 5.5, 5.5, -5.5, -5.5, 0, 0, 100, 50);
|
|
ctx.drawImage(response2, 100, 50, -5, -5, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, -0.001, 0, 100, 50, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 0, -0.001, 100, 50, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 0, 0, 100.001, 50, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 0, 0, 100, 50.001, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 50, 0, 50.001, 50, 0, 0, 100, 50); @moz-todo
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 0, 0, -5, 5, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 0, 0, 5, -5, 0, 0, 100, 50);
|
|
@assert throws INDEX_SIZE_ERR ctx.drawImage(response1, 110, 60, -20, -20, 0, 0, 100, 50);
|
|
@assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
|
|
});
|
|
|
|
- name: 2d.drawImage.broken
|
|
testing:
|
|
- 2d.drawImage.incomplete.image
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/broken.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
|
|
});
|
|
|
|
- name: 2d.drawImage.svg
|
|
desc: drawImage() of an SVG image
|
|
testing:
|
|
- 2d.drawImage.svg
|
|
code: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/green.svg');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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: |
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/anim-poster-gr.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
|
|
});
|
|
|
|
- name: 2d.drawImage.path
|
|
testing:
|
|
- 2d.drawImage.unaffect
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.rect(0, 0, 100, 50);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
ctx.fill();
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- name: 2d.drawImage.alpha
|
|
testing:
|
|
- 2d.drawImage.subject
|
|
images:
|
|
- red.png
|
|
code: |
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
ctx.globalAlpha = 0;
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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();
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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';
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/red.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, 0, 0);
|
|
@assert pixel 50,25 ==~ 0,255,0,255;
|
|
});
|
|
|
|
- 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);
|
|
var promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
ctx.drawImage(response, -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;
|
|
});
|
|
|
|
- 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 promise = new Promise(function(resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", '/images/redtransparent.png');
|
|
xhr.responseType = 'blob';
|
|
xhr.send();
|
|
xhr.onload = function() {
|
|
resolve(xhr.response);
|
|
};
|
|
});
|
|
promise.then(function(response) {
|
|
@nonfinite ctx.drawImage(<response>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
|
|
@nonfinite ctx.drawImage(<response>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
|
|
@nonfinite ctx.drawImage(<response>, <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;
|
|
});
|
|
|
|
- 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.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.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
|
|
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.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
|
|
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;
|
|
|
|
|
|
- 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.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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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);
|
|
|
|
- name: 2d.imageData.put.cross
|
|
desc: putImageData() accepts image data got from a different canvas
|
|
testing:
|
|
- 2d.imageData.put.normal
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var ctx2 = offscreenCanvas2.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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.path.initial
|
|
testing:
|
|
- 2d.path.initial
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.path.lineTo.nonfinite.details
|
|
desc: lineTo() with Infinity/NaN for first arg still converts the second arg
|
|
testing:
|
|
- 2d.nonfinite
|
|
code: |
|
|
for (var arg1 of [Infinity, -Infinity, NaN]) {
|
|
var converted = false;
|
|
ctx.lineTo(arg1, { valueOf: function() { converted = true; return 0; } });
|
|
@assert converted;
|
|
}
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.path.rect.zero.6
|
|
testing:
|
|
- 2d.path.rect.subpath
|
|
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
|
|
|
|
- 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
|
|
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
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- name: 2d.path.transformation.multiple
|
|
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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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;
|
|
|
|
- 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.coordinatespace
|
|
desc: Coordinate space goes from top-left to bottom-right
|
|
notes: This should not be upside down.
|
|
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;
|
|
|
|
- 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(offscreenCanvas);
|
|
@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);
|
|
@assert throws TypeError ctx.drawImage();
|
|
@assert throws TypeError ctx.drawImage(offscreenCanvas);
|
|
@assert throws TypeError ctx.drawImage(offscreenCanvas, 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.voidreturn
|
|
desc: void methods return undefined
|
|
code: |
|
|
@assert ctx.save() === undefined;
|
|
@assert ctx.restore() === undefined;
|
|
@assert ctx.scale(1, 1) === undefined;
|
|
@assert ctx.rotate(0) === undefined;
|
|
@assert ctx.translate(0, 0) === undefined;
|
|
if (ctx.transform) { // (avoid spurious failures, since the aim here is not to test that all features are supported)
|
|
@assert ctx.transform(1, 0, 0, 1, 0, 0) === undefined;
|
|
}
|
|
if (ctx.setTransform) {
|
|
@assert ctx.setTransform(1, 0, 0, 1, 0, 0) === undefined;
|
|
}
|
|
@assert ctx.clearRect(0, 0, 0, 0) === undefined;
|
|
@assert ctx.fillRect(0, 0, 0, 0) === undefined;
|
|
@assert ctx.strokeRect(0, 0, 0, 0) === undefined;
|
|
@assert ctx.beginPath() === undefined;
|
|
@assert ctx.closePath() === undefined;
|
|
@assert ctx.moveTo(0, 0) === undefined;
|
|
@assert ctx.lineTo(0, 0) === undefined;
|
|
@assert ctx.quadraticCurveTo(0, 0, 0, 0) === undefined;
|
|
@assert ctx.bezierCurveTo(0, 0, 0, 0, 0, 0) === undefined;
|
|
@assert ctx.arcTo(0, 0, 0, 0, 1) === undefined;
|
|
@assert ctx.rect(0, 0, 0, 0) === undefined;
|
|
@assert ctx.arc(0, 0, 1, 0, 0, true) === undefined;
|
|
@assert ctx.fill() === undefined;
|
|
@assert ctx.stroke() === undefined;
|
|
@assert ctx.clip() === undefined;
|
|
if (ctx.putImageData) {
|
|
@assert ctx.putImageData(ctx.getImageData(0, 0, 1, 1), 0, 0) === undefined;
|
|
}
|
|
@assert ctx.drawImage(offscreenCanvas, 0, 0, 1, 1, 0, 0, 0, 0) === undefined;
|
|
@assert ctx.createLinearGradient(0, 0, 0, 0).addColorStop(0, 'white') === undefined;
|
|
|
|
- name: 2d.canvas.reference
|
|
desc: canvas refers back to its canvas
|
|
testing:
|
|
- 2d.canvas
|
|
code: |
|
|
@assert ctx.canvas === offscreenCanvas;
|
|
|
|
- name: 2d.canvas.readonly
|
|
desc: canvas is readonly
|
|
testing:
|
|
- 2d.canvas.attribute
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
var d = ctx.canvas;
|
|
@assert offscreenCanvas2 !== d;
|
|
ctx.canvas = offscreenCanvas2;
|
|
@assert ctx.canvas === d;
|
|
|
|
- name: 2d.getcontext.exists
|
|
desc: The 2D context is implemented
|
|
testing:
|
|
- context.2d
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert offscreenCanvas2.getContext('2d') !== null;
|
|
|
|
- name: 2d.getcontext.extraargs
|
|
desc: The 2D context ignores extra getContext arguments
|
|
testing:
|
|
- context.2d.extraargs
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert offscreenCanvas2.getContext('2d', false, {}, [], 1, "2") !== null;
|
|
|
|
- name: 2d.getcontext.unique
|
|
desc: getContext('2d') returns the same object
|
|
testing:
|
|
- context.unique
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert offscreenCanvas2.getContext('2d') === offscreenCanvas2.getContext('2d');
|
|
|
|
- name: 2d.getcontext.shared
|
|
desc: getContext('2d') returns objects which share canvas state
|
|
testing:
|
|
- context.unique
|
|
code: |
|
|
var ctx2 = offscreenCanvas.getContext('2d');
|
|
ctx.fillStyle = '#f00';
|
|
ctx2.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
@assert pixel 50,25 == 0,255,0,255;
|
|
|
|
- name: context.emptystring
|
|
desc: getContext with empty string returns null
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext("");
|
|
|
|
- name: context.unrecognised.badname
|
|
desc: getContext with unrecognised context name returns null
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext('This is not an implemented context in any real browser');
|
|
|
|
- name: context.unrecognised.badsuffix
|
|
desc: Context name "2d" plus a suffix is unrecognised
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext("2d#");
|
|
|
|
- name: context.unrecognised.nullsuffix
|
|
desc: Context name "2d" plus a "\0" suffix is unrecognised
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext("2d\0");
|
|
|
|
- name: context.unrecognised.unicode
|
|
desc: Context name which kind of looks like "2d" is unrecognised
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext("2\uFF44");
|
|
|
|
- name: context.casesensitive
|
|
desc: Context name "2D" is unrecognised; matching is case sensitive
|
|
testing:
|
|
- context.unrecognised
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext('2D');
|
|
|
|
- name: context.arguments.missing
|
|
testing:
|
|
- canvas.getContext
|
|
code: |
|
|
var offscreenCanvas2 = new OffscreenCanvas(100, 50);
|
|
@assert throws TypeError offscreenCanvas2.getContext(); @moz-todo
|
|
|
|
|
|
- name: initial.colour
|
|
desc: Initial state is transparent black
|
|
testing:
|
|
- initial.colour
|
|
code: |
|
|
@assert pixel 20,20 == 0,0,0,0;
|
|
|
|
- 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;
|
|
offscreenCanvas.width = 50;
|
|
@assert pixel 20,20 == 0,0,0,0;
|
|
|
|
- name: initial.reset.same
|
|
desc: Setting size (not changing the value) resets canvas to transparent black
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 100;
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fillRect(0, 0, 50, 50);
|
|
@assert pixel 20,20 == 255,0,0,255;
|
|
offscreenCanvas.width = 100;
|
|
@assert pixel 20,20 == 0,0,0,0;
|
|
|
|
- name: initial.reset.path
|
|
desc: Resetting the canvas state resets the current path
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 100;
|
|
ctx.rect(0, 0, 100, 50);
|
|
offscreenCanvas.width = 100;
|
|
ctx.fillStyle = '#f00';
|
|
ctx.fill();
|
|
@assert pixel 20,20 == 0,0,0,0;
|
|
|
|
- name: initial.reset.clip
|
|
desc: Resetting the canvas state resets the current clip region
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 100;
|
|
ctx.rect(0, 0, 1, 1);
|
|
ctx.clip();
|
|
offscreenCanvas.width = 100;
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
@assert pixel 20,20 == 0,255,0,255;
|
|
|
|
- name: initial.reset.transform
|
|
desc: Resetting the canvas state resets the current transformation matrix
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 100;
|
|
ctx.scale(0.1, 0.1);
|
|
offscreenCanvas.width = 100;
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 100, 50);
|
|
@assert pixel 20,20 == 0,255,0,255;
|
|
|
|
- name: initial.reset.gradient
|
|
desc: Resetting the canvas state does not invalidate any existing gradients
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 50;
|
|
var g = ctx.createLinearGradient(0, 0, 100, 0);
|
|
g.addColorStop(0, '#0f0');
|
|
g.addColorStop(1, '#0f0');
|
|
offscreenCanvas.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;
|
|
|
|
- name: initial.reset.pattern
|
|
desc: Resetting the canvas state does not invalidate any existing patterns
|
|
testing:
|
|
- initial.reset
|
|
code: |
|
|
offscreenCanvas.width = 30;
|
|
ctx.fillStyle = '#0f0';
|
|
ctx.fillRect(0, 0, 30, 50);
|
|
var p = ctx.createPattern(offscreenCanvas, 'repeat-x');
|
|
offscreenCanvas.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;
|
|
|
|
- name: size.attributes.idl.set.zero
|
|
desc: Setting width/height IDL attributes to 0
|
|
testing:
|
|
- size.width
|
|
- size.height
|
|
code: |
|
|
offscreenCanvas.width = 0;
|
|
offscreenCanvas.height = 0;
|
|
@assert offscreenCanvas.width === 0;
|
|
@assert offscreenCanvas.height === 0;
|
|
|
|
- name: size.attributes.idl
|
|
desc: Getting/setting width/height IDL attributes
|
|
testing:
|
|
- size.width
|
|
- size.height
|
|
webidl:
|
|
- es-unsigned-long
|
|
code: |
|
|
offscreenCanvas.width = "100";
|
|
offscreenCanvas.height = "100";
|
|
@assert offscreenCanvas.width === 100;
|
|
@assert offscreenCanvas.height === 100;
|
|
offscreenCanvas.width = "+1.5e2";
|
|
offscreenCanvas.height = "0x96";
|
|
@assert offscreenCanvas.width === 150;
|
|
@assert offscreenCanvas.height === 150;
|
|
offscreenCanvas.width = 301.999;
|
|
offscreenCanvas.height = 301.001;
|
|
@assert offscreenCanvas.width === 301;
|
|
@assert offscreenCanvas.height === 301;
|
|
offscreenCanvas.width = "400x";
|
|
offscreenCanvas.height = "foo";
|
|
@assert offscreenCanvas.width === 0;
|
|
@assert offscreenCanvas.height === 0;
|
|
|
|
- name: size.attributes.default
|
|
desc: Default width/height when attributes are missing
|
|
testing:
|
|
- size.default
|
|
- size.missing
|
|
code: |
|
|
@assert offscreenCanvas.width === 100;
|
|
@assert offscreenCanvas.height === 50;
|
|
|
|
- name: size.attributes.reflect.setidl
|
|
desc: Setting IDL attributes updates IDL and content attributes
|
|
testing:
|
|
- size.reflect
|
|
code: |
|
|
offscreenCanvas.width = 120;
|
|
offscreenCanvas.height = 60;
|
|
@assert offscreenCanvas.width === 120;
|
|
@assert offscreenCanvas.height === 60;
|
|
|
|
- name: size.attributes.reflect.setidlzero
|
|
desc: Setting IDL attributes to 0 updates IDL and content attributes
|
|
testing:
|
|
- size.reflect
|
|
code: |
|
|
offscreenCanvas.width = 0;
|
|
offscreenCanvas.height = 0;
|
|
@assert offscreenCanvas.width === 0;
|
|
@assert offscreenCanvas.height === 0;
|
|
|
|
- meta: |
|
|
cases = [
|
|
("zero", "0", 0),
|
|
("empty", "", None),
|
|
("onlyspace", " ", None),
|
|
("space", " 100", 100),
|
|
("whitespace", "\t\f100", 100),
|
|
("plus", "+100", 100),
|
|
("minus", "-100", None),
|
|
("octal", "0100", 100),
|
|
("hex", "0x100", 0x100),
|
|
("exp", "100e1", 100e1),
|
|
("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 += "offscreenCanvas.width = '%s';\noffscreenCanvas.height = '%s';\n" % (string, string)
|
|
code += "@assert offscreenCanvas.width === 100;\n@assert offscreenCanvas.height === 50;\n"
|
|
expected = None
|
|
else:
|
|
code += "offscreenCanvas.width = '%s';\noffscreenCanvas.height = '%s';\n" % (string, string)
|
|
code += "@assert offscreenCanvas.width === %s;\n@assert offscreenCanvas.height === %s;\n" % (exp, exp)
|
|
expected = None
|
|
|
|
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,
|
|
"code": code,
|
|
} )
|
|
|
|
- name: size.large
|
|
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"
|
|
offscreenCanvas.width = n;
|
|
offscreenCanvas.height = n;
|
|
@assert offscreenCanvas.width === n;
|
|
@assert offscreenCanvas.height === n;
|