summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/2dcontext/tools/spec.yaml
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/2dcontext/tools/spec.yaml')
-rw-r--r--testing/web-platform/tests/2dcontext/tools/spec.yaml717
1 files changed, 717 insertions, 0 deletions
diff --git a/testing/web-platform/tests/2dcontext/tools/spec.yaml b/testing/web-platform/tests/2dcontext/tools/spec.yaml
new file mode 100644
index 000000000..12b7d6be9
--- /dev/null
+++ b/testing/web-platform/tests/2dcontext/tools/spec.yaml
@@ -0,0 +1,717 @@
+# Extracts from http://www.whatwg.org/specs/web-apps/current-work/
+#
+# (c) Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA.
+# You are granted a license to use, reproduce and create derivative works of this document.
+
+assertions:
+ - id: canvas.type
+ text: "interface HTMLCanvasElement<^> : HTMLElement {"
+ - id: size.width
+ text: "interface HTMLCanvasElement<...>attribute unsigned long width;<^>"
+ - id: size.height
+ text: "interface HTMLCanvasElement<...>attribute unsigned long height;<^>"
+ - id: canvas.getContext
+ text: "interface HTMLCanvasElement<...>object\\? getContext(in DOMString contextId, in any... args);<^>"
+ - id: fallback
+ text: "The contents of the canvas element, if any, are the element's fallback content<^>."
+ - id: size.nonnegativeinteger
+ text: "The rules for parsing non-negative integers *must* be used to obtain their numeric values<^>."
+ - id: size.missing
+ text: "If an attribute is missing<^>, <...> then the default value *must* be used instead."
+ - id: size.error
+ text: "if parsing its value returns an error<^>, then the default value *must* be used instead."
+ - id: size.default
+ text: "The width attribute defaults to 300, and the height attribute defaults to 150<^>."
+ - id: size.css
+ text: "the element can be sized arbitrarily by a style sheet. During rendering, the image is scaled to fit this layout size<^>."
+ - id: initial.reset
+ text: "When the canvas element is created, and subsequently whenever the width and height attributes are set (whether to a new value or to the previous value), the bitmap and any associated contexts *must* be cleared back to their initial state <...><^>."
+ - id: initial.colour
+ text: "When the canvas is initialized, its bitmap *must* be cleared to transparent black<^>."
+ - id: size.reflect
+ text: "The width and height IDL attributes *must* reflect the respective content attributes of the same name<^>,"
+
+ - id: context.unrecognised
+ text: "If contextId is not the name of a context supported by the user agent, return null and abort these steps<^>."
+ - id: context.unique
+ text: "If the getContext() method has already been invoked on this element for the same contextId, return the same object as was returned that time, and abort these steps<^>."
+ - id: context.2d
+ text: "When the getContext() method of a canvas element is to return a new object for the contextId 2d, the user agent *must* return a new CanvasRenderingContext2D object<^>."
+ - id: context.2d.extraargs
+ text: "When the getContext() method of a canvas element is to return a new object for the contextId 2d, the user agent *must* return a new CanvasRenderingContext2D object. Any additional arguments are ignored<^>."
+
+ - id: toDataURL.noarguments
+ text: "When a user agent is to create a serialization of the image as a file, <...> if there are no arguments, in the PNG format<^>."
+ - id: toDataURL.zerosize
+ text: "If the canvas has no pixels (i.e. either its horizontal dimension or its vertical dimension is zero) then return the string \"data:,\"<^> and abort these steps."
+ - id: toDataURL.witharguments
+ text: "If arguments is not empty, the first value must be interpreted as a MIME type giving the format to use<^>."
+ - id: toDataURL.noalpha
+ text: "For image types that do not support an alpha channel, the serialized image *must* be the canvas image composited onto a solid black background using the source-over operator<^>."
+ - id: toDataURL.png
+ text: "User agents *must* support PNG (\"image/png\")<^>."
+ - id: toDataURL.unrecognised
+ text: "If the user agent does not support the requested type, it *must* create the file using the PNG format<^>."
+ - id: toDataURL.lowercase
+ text: "User agents *must* convert the provided type to ASCII lowercase before establishing if they support that type<^>."
+ - id: toDataURL.jpeg
+ previously: [ 0, "image/png", false ]
+ text: "image/jpeg<^>"
+ - id: toDataURL.jpeg.quality
+ text: "The second argument, if it is a number in the range 0.0 to 1.0 inclusive, *must* be treated as the desired quality level<^>."
+ - id: toDataURL.jpeg.nan
+ text: "If it is not a number<^> <...>, the user agent *must* use its default value, as if the argument had been omitted."
+ - id: toDataURL.jpeg.range
+ text: "If it is <...> outside that range<^>, the user agent *must* use its default value, as if the argument had been omitted."
+ - id: toDataURL.arguments
+ text: "Other arguments *must* be ignored and must not cause the user agent to raise an exception<^>."
+
+ - id: 2d.coordinatespace
+ text: "flat Cartesian surface whose origin (0,0) is at the top left corner, with the coordinate space having x values increasing when going right, and y values increasing when going down<^>."
+ - id: context.2d.type
+ text: "interface CanvasRenderingContext2D<^> {"
+ - id: 2d.canvasGradient.type
+ text: "interface CanvasGradient<^> {"
+ - id: 2d.imageData.type
+ text: "interface ImageData<^> {"
+ - id: 2d.canvas.attribute
+ text: "readonly<^> attribute HTMLCanvasElement canvas;"
+ - id: 2d.canvas
+ text: "The canvas attribute *must* return the canvas element that the context paints on<^>."
+ - id: 2d.nonfinite
+ text: "Except where otherwise specified, for the 2D context interface, any method call with a numeric argument whose value is infinite or a NaN value *must* be ignored<^>."
+
+ - id: 2d.currentColor.onset
+ text: "Whenever the CSS value currentColor is used as a color in this API, the \"computed value of the 'color' property\" for the purposes of determining the computed value of the currentColor keyword is the computed value of the 'color' property on the element in question at the time that the color is specified<^>"
+ - id: 2d.currentColor.outofdoc
+ text: "If the computed value of the 'color' property is undefined for a particular case (e.g. because the element is not in a Document), then the \"computed value of the 'color' property\" for the purposes of determining the computed value of the currentColor keyword is fully opaque black<^>."
+ - id: 2d.currentColor.gradient
+ text: "In the case of addColorStop() on CanvasGradient, the \"computed value of the 'color' property\" for the purposes of determining the computed value of the currentColor keyword is always fully opaque black<^> (there is no associated element)."
+
+ - id: 2d.state.transformation
+ text: "The current transformation matrix<^>."
+ - id: 2d.state.clip
+ text: "The current clipping region<^>."
+ - meta: |
+ for s in [
+ 'strokeStyle', 'fillStyle', 'globalAlpha',
+ 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
+ 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor',
+ 'globalCompositeOperation',
+ 'font', 'textAlign', 'textBaseline'
+ ]:
+ assertions.append( {
+ 'id': '2d.state.%s' % s,
+ 'text': 'The current values of the following attributes:<...>%s<^>' % s
+ } )
+ - id: 2d.state.path
+ text: "The current path<^> <...> are not part of the drawing state."
+ - id: 2d.state.bitmap
+ text: "The <...> current bitmap<^> are not part of the drawing state."
+
+ - id: 2d.state.save
+ text: "The save() method *must* push a copy of the current drawing state onto the drawing state stack<^>."
+ - id: 2d.state.restore
+ text: "The restore() method *must* pop the top entry in the drawing state stack, and reset the drawing state it describes<^>."
+ - id: 2d.state.restore.underflow
+ text: "If there is no saved state, the method *must* do nothing<^>."
+
+ - id: 2d.transformation.initial
+ text: "When the context is created, the transformation matrix *must* initially be the identity transform<^>."
+ - id: 2d.transformation.order
+ text: "The transformations *must* be performed in reverse order<^>."
+ - id: 2d.transformation.scale
+ text: "The scale(x, y) method *must* add the scaling transformation described by the arguments to the transformation matrix<^>."
+ - id: 2d.transformation.scale.multiple
+ text: "The factors are multiples<^>."
+ - id: 2d.transformation.rotate
+ text: "The rotate(angle) method *must* add the rotation transformation described by the argument to the transformation matrix<^>."
+ - id: 2d.transformation.rotate.direction
+ text: "The angle argument represents a clockwise rotation angle<^>"
+ - id: 2d.transformation.rotate.radians
+ text: "The angle argument <...> expressed in radians<^>."
+ - id: 2d.transformation.translate
+ text: "The translate(x, y) method *must* add the translation transformation described by the arguments to the transformation matrix<^>."
+ - id: 2d.transformation.transform
+ text: "The transform(a, b, c, d, e, f) method *must* replace the current transformation matrix with the result of multiplying the current transformation matrix with the matrix described by<^>:"
+ - id: 2d.transformation.transform.multiply
+ text: "The transform(a, b, c, d, e, f) method *must* replace the current transformation matrix with the result of multiplying<^> the current transformation matrix with the matrix described by:"
+ - id: 2d.transformation.setTransform
+ text: "The setTransform(a, b, c, d, e, f) method *must* <...> invoke the transform(a, b, c, d, e, f) method with the same arguments<^>"
+ - id: 2d.transformation.setTransform.identity
+ text: "The setTransform(a, b, c, d, e, f) method *must* reset the current transform to the identity matrix<^>, "
+
+
+ - id: 2d.composite.operation
+ text: "All drawing operations are affected by the global compositing attributes, globalAlpha and globalCompositeOperation<^>."
+
+ - id: 2d.composite.globalAlpha.shape
+ text: "The globalAlpha attribute gives an alpha value that is applied to shapes<^> and images before they are composited onto the canvas."
+ - id: 2d.composite.globalAlpha.image
+ text: "The globalAlpha attribute gives an alpha value that is applied to shapes and images<^> before they are composited onto the canvas."
+ - id: 2d.composite.globalAlpha.range
+ text: "The value must be in the range from 0.0 (fully transparent) to 1.0 (no additional transparency). If an attempt is made to set the attribute to a value outside this range, including Infinity and Not-a-Number (NaN) values, the attribute *must* retain its previous value<^>."
+ - id: 2d.composite.globalAlpha.default
+ text: "When the context is created, the globalAlpha attribute *must* initially have the value 1.0<^>."
+
+ - id: 2d.composite.operation.shape
+ text: "The globalCompositeOperation attribute sets how shapes<^> and images are drawn onto the existing bitmap,"
+ - id: 2d.composite.operation.image
+ text: "The globalCompositeOperation attribute sets how shapes and images<^> are drawn onto the existing bitmap,"
+
+ - id: 2d.composite.source-atop
+ text: "source-atop<^><eol>"
+ - id: 2d.composite.source-in
+ text: "source-in<^><eol>"
+ - id: 2d.composite.source-out
+ text: "source-out<^><eol>"
+ - id: 2d.composite.source-over
+ text: "source-over (default)<^><eol>"
+ - id: 2d.composite.destination-atop
+ text: "destination-atop<^><eol>"
+ - id: 2d.composite.destination-in
+ text: "destination-in<^><eol>"
+ - id: 2d.composite.destination-out
+ text: "destination-out<^><eol>"
+ - id: 2d.composite.destination-over
+ text: "destination-over<^><eol>"
+ - id: 2d.composite.lighter
+ text: "lighter<^><eol>"
+ - id: 2d.composite.copy
+ text: "copy<^><eol>"
+ - id: 2d.composite.xor
+ text: "xor<^><eol>"
+
+ - id: 2d.composite.operation.casesensitive
+ text: "These values are all case-sensitive<^> <...> they *must* be used exactly as shown."
+ - id: 2d.composite.operation.exact
+ text: "User agents *must* not recognize values that are not a case-sensitive match for one of the values given above<^>."
+ - id: 2d.composite.operation.porterduff
+ text: "The operators in the above list *must* be treated as described by the Porter-Duff operator given at the start of their description (e.g. A over B)<^>."
+ - id: 2d.composite.operation.unrecognised
+ text: "On setting, if the user agent does not recognize the specified value, it *must* be ignored, leaving the value of globalCompositeOperation unaffected<^>."
+ - id: 2d.composite.operation.default
+ text: "When the context is created, the globalCompositeOperation attribute *must* initially have the value source-over<^>."
+
+
+ - id: 2d.colours.parse
+ text: "On setting, strings *must* be parsed as CSS <color> values and the color assigned<^>,"
+ - id: 2d.gradient.assign
+ text: "On setting, <...> CanvasGradient<^> and CanvasPattern objects *must* be assigned themselves."
+ - id: 2d.pattern.assign
+ text: "On setting, <...> CanvasGradient and CanvasPattern<^> objects *must* be assigned themselves."
+ - id: 2d.colours.invalidstring
+ text: "If the value is a string but cannot be parsed as a CSS <color> value<^>, <...> then it *must* be ignored, and the attribute must retain its previous value."
+ - id: 2d.colours.invalidtype
+ text: "If the value is <...> neither a string, a CanvasGradient, nor a CanvasPattern<^>, then it *must* be ignored, and the attribute must retain its previous value."
+ - id: 2d.colours.getcolour
+ text: "On getting, if the value is a color, then the serialization of the color *must* be returned<^>."
+ - id: 2d.gradient.object
+ text: "if it is not a color but a CanvasGradient<^> or CanvasPattern, then the respective object *must* be returned."
+ - id: 2d.pattern.object
+ text: "if it is not a color but a CanvasGradient or CanvasPattern<^>, then the respective object *must* be returned."
+ - id: 2d.serializecolour.solid
+ text: "if it has alpha equal to 1.0, then the string is a lowercase six-digit hex value<^>"
+ - id: 2d.serializecolour.transparent
+ text: "Otherwise, the color value has alpha less than 1.0, and the string is the color value in the CSS rgba() functional-notation format<^>:"
+ - id: 2d.colours.default
+ text: "When the context is created, the strokeStyle and fillStyle attributes *must* initially have the string value #000000<^>."
+
+ - id: 2d.gradient.interpolate.linear
+ text: "Between each such stop, the colors and the alpha component *must* be linearly interpolated<^> over the RGBA space without premultiplying the alpha value to find the color to use at that offset."
+ - id: 2d.gradient.interpolate.alpha
+ text: "Between each such stop, the colors and the alpha component *must* be linearly interpolated over the RGBA space without premultiplying the alpha value<^> to find the color to use at that offset."
+ - id: 2d.gradient.outside.first
+ text: "Before the first stop, the color *must* be the color of the first stop<^>."
+ - id: 2d.gradient.outside.last
+ text: "After the last stop, the color *must* be the color of the last stop<^>."
+ - id: 2d.gradient.empty
+ text: "When there are no stops, the gradient is transparent black<^>."
+
+
+ - id: 2d.gradient.invalidoffset
+ text: "If the offset is less than 0, greater than 1, infinite, or NaN, then an INDEX_SIZE_ERR exception *must* be raised<^>."
+ - id: 2d.gradient.invalidcolour
+ text: "If the color cannot be parsed as a CSS <color> value, then a SYNTAX_ERR exception *must* be raised<^>."
+ - id: 2d.gradient.update
+ text: "Otherwise, the gradient *must* have a new stop placed, at offset offset relative to the whole gradient, and with the color obtained by parsing color as a CSS <color> value<^>."
+ - id: 2d.gradient.interpolate.overlap
+ text: "If multiple stops are added at the same offset on a gradient, they *must* be placed in the order added, with the first one closest to the start of the gradient, <...><^>."
+
+ - id: 2d.gradient.linear.nonfinite
+ text: "If any of the arguments to createLinearGradient() are infinite or NaN, the method *must* raise a NOT_SUPPORTED_ERR exception<^>."
+ - id: 2d.gradient.linear.return
+ text: "Otherwise, the method *must* return a linear CanvasGradient initialized with the specified line<^>."
+ - id: 2d.gradient.linear.rendering
+ text: "Linear gradients *must* be rendered such that all points on a line perpendicular to the line that crosses the start and end points have the color at the point where those two lines cross (with the colors coming from the interpolation and extrapolation described above)<^>."
+ - id: 2d.gradient.linear.transform
+ text: "The points in the linear gradient *must* be transformed as described by the current transformation matrix when rendering<^>."
+ - id: 2d.gradient.linear.zerosize
+ text: "If x0 = x1 and y0 = y1, then the linear gradient *must* paint nothing<^>."
+
+ - id: 2d.gradient.radial.nonfinite
+ text: "If any of the arguments are infinite or NaN, a NOT_SUPPORTED_ERR exception *must* be raised<^>."
+ - id: 2d.gradient.radial.negative
+ text: "If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception *must* be raised<^>."
+ - id: 2d.gradient.radial.return
+ text: "Otherwise, the method *must* return a radial CanvasGradient initialized with the two specified circles<^>."
+ - id: 2d.gradient.radial.rendering
+ text: "Radial gradients *must* be rendered by following these steps<^>:"
+ - id: 2d.gradient.radial.equal
+ text: "If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient *must* paint nothing<^>."
+ - id: 2d.gradient.extent
+ text: "Gradients *must* be painted only where the relevant stroking or filling effects requires that they be drawn<^>."
+ - id: 2d.gradient.radial.transform
+ text: "The points in the radial gradient *must* be transformed as described by the current transformation matrix when rendering<^>."
+
+
+ - id: 2d.pattern.modify
+ text: "Modifying this image after calling the createPattern() method *must* not affect the pattern<^>."
+ - id: 2d.pattern.missing
+ text: "If the empty string is specified, repeat *must* be assumed<^>."
+ - id: 2d.pattern.unrecognised
+ text: "If an unrecognized value is given, then the user agent *must* raise a SYNTAX_ERR exception<^>."
+ - id: 2d.pattern.exact
+ text: "User agents *must* recognize the four values described above exactly (e.g. they must not do case folding)<^>."
+ - id: 2d.pattern.return
+ text: "the method *must* return a CanvasPattern object suitably initialized<^>."
+ - id: 2d.pattern.IDL
+ text: "CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition);<...>CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition);<...>CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition);<^>"
+ - id: 2d.pattern.incomplete.image
+ text: "If the image argument is an HTMLImageElement object that is not fully decodable<^><...> then the implementation *must* return null."
+ - id: 2d.pattern.incomplete.video
+ previously: [ 6, "createPattern" ]
+ text: "If the image argument is <...> an HTMLVideoElement object whose readyState attribute is either HAVE_NOTHING or HAVE_METADATA<^>, then the implementation *must* return null."
+ - id: 2d.pattern.zerocanvas
+ previously: [ 10, "createPattern" ]
+ text: "If the image argument is an HTMLCanvasElement object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* raise an INVALID_STATE_ERR exception<^>."
+ - id: 2d.pattern.painting
+ text: "Patterns *must* be painted so that the top left of the first image is anchored at the origin of the coordinate space, and images are then repeated horizontally to the left and right (if the repeat-x string was specified) or vertically up and down (if the repeat-y string was specified) or in all four directions all over the canvas (if the repeat string was specified)<^>."
+ - id: 2d.pattern.unscaled
+ text: "The images are not scaled by this process; one CSS pixel of the image *must* be painted on one coordinate space unit<^>."
+ - id: 2d.pattern.extent
+ text: "patterns *must* actually be painted only where the stroking or filling effect requires that they be drawn<^>, and are affected by the current transformation matrix."
+ - id: 2d.pattern.animated.image
+ text: "When the createPattern() method is passed an animated image as its image argument, the user agent must use the poster frame of the animation, or, if there is no poster frame, the first frame of the animation<^>."
+ - id: 2d.pattern.animated.video
+ previously: [ 4, "createPattern" ]
+ text: "When the image argument is an HTMLVideoElement, then the frame at the current playback position *must* be used as the source image<^>,"
+ - id: 2d.pattern.video.size
+ previously: [ 4, "createPattern" ]
+ text: "When the image argument is an HTMLVideoElement, <...> the source image's dimensions *must* be the intrinsic width and intrinsic height of the media resource (i.e. after any aspect-ratio correction has been applied)<^>."
+
+
+ - id: 2d.lineWidth
+ text: "The lineWidth attribute gives the width of lines, in coordinate space units<^>."
+ - id: 2d.lineWidth.get
+ text: "The lineWidth attribute <...>. On getting, it *must* return the current value<^>."
+ - id: 2d.lineWidth.invalid
+ text: "The lineWidth attribute <...>. On setting, zero, negative, infinite, and NaN values *must* be ignored, leaving the value unchanged<^>;"
+ - id: 2d.lineWidth.set
+ text: "The lineWidth attribute <...>. On setting, <...> other values *must* change the current value to the new value<^>."
+ - id: 2d.lineWidth.default
+ text: "the lineWidth attribute *must* initially have the value 1.0<^>."
+ - id: 2d.lineCap.end
+ text: "The lineCap attribute defines the type of endings that UAs will place on the end of lines<^>."
+ - id: 2d.lineCap.butt
+ text: "The butt value means that the end of each line has a flat edge perpendicular to the direction of the line (and that no additional line cap is added)<^>."
+ - id: 2d.lineCap.round
+ text: "The round value means that a semi-circle with the diameter equal to the width of the line *must* then be added on to the end of the line<^>."
+ - id: 2d.lineCap.square
+ text: "The square value means that a rectangle with the length of the line width and the width of half the line width, placed flat against the edge perpendicular to the direction of the line, *must* be added at the end of each line<^>."
+ - id: 2d.lineCap.get
+ previously: [ 2, "The lineCap attribute" ]
+ text: "On getting, it *must* return the current value<^>."
+ - id: 2d.lineCap.set
+ text: "On setting, if the new value is one of the literal strings butt, round, and square, then the current value *must* be changed to the new value<^>;"
+ - id: 2d.lineCap.invalid
+ text: "On setting, if the new value is one of the literal strings butt, round, and square, then <...>; other values *must* ignored, leaving the value unchanged<^>."
+ - id: 2d.lineCap.default
+ text: "When the context is created, the lineCap attribute *must* initially have the value butt<^>."
+ - id: 2d.lineJoin.get
+ previously: [ 2, "lineJoin" ]
+ text: "On getting, it *must* return the current value<^>."
+ - id: 2d.lineJoin.set
+ text: "On setting, if the new value is one of the literal strings bevel, round, and miter, then the current value *must* be changed to the new value<^>;"
+ - id: 2d.lineJoin.invalid
+ text: "On setting, if the new value is one of the literal strings bevel, round, and miter, then <...>; other values *must* be ignored, leaving the value unchanged<^>."
+ - id: 2d.lineJoin.default
+ text: "When the context is created, the lineJoin attribute *must* initially have the value miter<^>."
+ - id: 2d.lineJoin.joins
+ text: "A join exists at any point in a subpath shared by two consecutive lines<^>."
+ - id: 2d.lineJoin.joinclosed
+ text: "When a subpath is closed, then a join also exists at its first point (equivalent to its last point) connecting the first and last lines in the subpath<^>."
+ - id: 2d.lineJoin.common
+ text: "A filled triangle connecting these two opposite corners with a straight line, with the third point of the triangle being the join point, *must* be rendered at all joins<^>."
+ - id: 2d.lineJoin.round
+ text: "The round value means that a filled arc connecting the two aforementioned corners of the join, abutting (and not overlapping) the aforementioned triangle, with the diameter equal to the line width and the origin at the point of the join, *must* be rendered at joins<^>."
+ - id: 2d.lineJoin.bevel
+ text: "The bevel value means that this is all that is rendered at joins<^>."
+ - id: 2d.lineJoin.miter
+ text: "The miter value means that a second filled triangle *must* (if it can given the miter length) be rendered at the join, with one line being the line between the two aforementioned corners, abutting the first triangle, and the other two being continuations of the outside edges of the two joining lines, as long as required to intersect without going over the miter length<^>."
+ - id: 2d.lineJoin.miterLimit
+ text: "If the miter length would cause the miter limit ratio to be exceeded, this second triangle *must* not be rendered<^>."
+ - id: 2d.miterLimit.get
+ text: "The miter limit <...>. On getting, it *must* return the current value<^>."
+ - id: 2d.miterLimit.invalid
+ text: "The miter limit <...>. On setting, zero, negative, infinite, and NaN values *must* be ignored, leaving the value unchanged<^>;"
+ - id: 2d.miterLimit.set
+ text: "The miter limit <...>. On setting, <...>; other values *must* change the current value to the new value<^>."
+ - id: 2d.miterLimit.default
+ text: "When the context is created, the miterLimit attribute *must* initially have the value 10.0<^>."
+
+
+ - id: 2d.shadow.color.initial
+ text: "When the context is created, the shadowColor attribute initially *must* be fully-transparent black<^>."
+ - id: 2d.shadow.color.get
+ text: "On getting, the serialization of the color *must* be returned<^>."
+ - id: 2d.shadow.color.set
+ text: "On setting, the new value *must* be parsed as a CSS <color> value and the color assigned<^>."
+ - id: 2d.shadow.color.invalid
+ text: "If the value cannot be parsed as a CSS <color> value then it *must* be ignored, and the attribute must retain its previous value<^>."
+ - id: 2d.shadow.offset.initial
+ text: "When the context is created, the shadow offset attributes *must* initially have the value 0<^>."
+ - id: 2d.shadow.offset.get
+ text: "On getting, they *must* return their current value<^>."
+ - id: 2d.shadow.offset.set
+ text: "On setting, the attribute being set *must* be set to the new value<^>,"
+ - id: 2d.shadow.offset.invalid
+ text: "On setting, <...> if the value is infinite or NaN, in which case the new value *must* be ignored<^>."
+ - id: 2d.shadow.blur.initial
+ text: "When the context is created, the shadowBlur attribute *must* initially have the value 0<^>."
+ - id: 2d.shadow.blur.get
+ text: "On getting, the attribute *must* return its current value<^>."
+ - id: 2d.shadow.blur.set
+ text: "On setting the attribute *must* be set to the new value<^>,"
+ - id: 2d.shadow.blur.invalid
+ text: "On setting <...> if the value is negative, infinite or NaN, in which case the new value *must* be ignored<^>."
+ - id: 2d.shadow.enable
+ text: "Shadows are only drawn if the opacity component of the alpha component of the color of shadowColor is non-zero and either the shadowBlur is non-zero, or the shadowOffsetX is non-zero, or the shadowOffsetY is non-zero<^>."
+ - id: 2d.shadow.render
+ text: "When shadows are drawn, they *must* be rendered as follows<^>:"
+
+ - id: 2d.rect.transform
+ text: "The current transformation matrix *must* be applied to the following four coordinates<^>,"
+ - id: 2d.rect.closed
+ text: "the following four coordinates, which form the path that *must* then be closed to get the specified rectangle<^>:"
+ - id: 2d.clearRect
+ text: "The clearRect(x, y, w, h) method *must* clear the pixels in the specified rectangle that also intersect the current clipping region to a fully transparent black, erasing any previous image<^>."
+ - id: 2d.fillRect
+ text: "The fillRect(x, y, w, h) method *must* paint the specified rectangular area using the fillStyle<^>."
+ - id: 2d.strokeRect
+ text: "The strokeRect(x, y, w, h) method *must* stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin, and (if appropriate) miterLimit attributes<^>."
+
+
+ - id: 2d.path.initial
+ text: "Initially, the context's path *must* have zero subpaths<^>."
+ - id: 2d.path.transformation
+ text: "The points and lines added to the path by these methods *must* be transformed according to the current transformation matrix as they are added<^>."
+ - id: 2d.path.beginPath
+ text: "The beginPath() method *must* empty the list of subpaths so that the context once again has zero subpaths<^>."
+ - id: 2d.path.moveTo
+ text: "The moveTo(x, y) method *must* create a new subpath with the specified point as its first (and only) point<^>."
+ - id: 2d.path.ensure
+ text: "When the user agent is to ensure there is a subpath for a coordinate (x, y), the user agent must check to see if the context has any subpaths, and if it does not, then the user agent *must* create a new subpath with the point (x, y) as its first (and only) point, as if the moveTo() method had been called<^>."
+ - id: 2d.path.closePath.empty
+ text: "The closePath() method *must* do nothing if the context has no subpaths<^>."
+ - id: 2d.path.closePath.nonempty
+ text: "The closePath() method <...> *must* mark the last subpath as closed, create a new subpath whose first point is the same as the previous subpath's first point, and finally add this new subpath to the path<^>."
+ - id: 2d.path.lineTo.empty
+ text: "The lineTo(x, y) method *must* ensure there is a subpath for (x, y) if the context has no subpaths<^>."
+ - id: 2d.path.lineTo.nonempty
+ text: "The lineTo(x, y) method <...> *must* connect the last point in the subpath to the given point (x, y) using a straight line, and must then add the given point (x, y) to the subpath<^>."
+ - id: 2d.path.quadratic.empty
+ text: "The quadraticCurveTo(cpx, cpy, x, y) method *must* ensure there is a subpath for (cpx, cpy)<^>,"
+ - id: 2d.path.quadratic.nonempty
+ text: "The quadraticCurveTo(cpx, cpy, x, y) method <...> *must* connect the last point in the subpath to the given point (x, y) using a quadratic B<...>zier curve with control point (cpx, cpy), and must then add the given point (x, y) to the subpath<^>."
+ - id: 2d.path.bezier.empty
+ text: "The bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) method *must* ensure there is a subpath for (cp1x, cp1y)<^>,"
+ - id: 2d.path.bezier.nonempty
+ text: "The bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) method <...> *must* connect the last point in the subpath to the given point (x, y) using a cubic B<...>zier curve with control points (cp1x, cp1y) and (cp2x, cp2y). Then, it must add the point (x, y) to the subpath<^>."
+ - id: 2d.path.arcTo.empty
+ text: "The arcTo(x1, y1, x2, y2, radius) method *must* first ensure there is a subpath for (x1, y1)<^>."
+ - id: 2d.path.arcTo.negative
+ previously: [ 2, "arcTo(" ]
+ text: "Negative values for radius *must* cause the implementation to raise an INDEX_SIZE_ERR exception<^>."
+ - id: 2d.path.arcTo.coincide.01
+ text: "If the point (x0, y0) is equal to the point (x1, y1)<^>, or if the point (x1, y1) is equal to the point (x2, y2), or if the radius radius is zero, then the method *must* add the point (x1, y1) to the subpath, and connect that point to the previous point (x0, y0) by a straight line."
+ - id: 2d.path.arcTo.coincide.12
+ text: "If the point (x0, y0) is equal to the point (x1, y1), or if the point (x1, y1) is equal to the point (x2, y2)<^>, or if the radius radius is zero, then the method *must* add the point (x1, y1) to the subpath, and connect that point to the previous point (x0, y0) by a straight line."
+ - id: 2d.path.arcTo.zeroradius
+ text: "If the point (x0, y0) is equal to the point (x1, y1), or if the point (x1, y1) is equal to the point (x2, y2), or if the radius radius is zero<^>, then the method *must* add the point (x1, y1) to the subpath, and connect that point to the previous point (x0, y0) by a straight line."
+ - id: 2d.path.arcTo.collinear
+ text: "if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, then the method *must* add the point (x1, y1) to the subpath, and connect that point to the previous point (x0, y0) by a straight line<^>."
+ - id: 2d.path.arcTo.shape
+ text: "The method *must* connect the point (x0, y0) to the start tangent point by a straight line, adding the start tangent point to the subpath, and then must connect the start tangent point to the end tangent point by The Arc, adding the end tangent point to the subpath<^>."
+
+ - id: 2d.path.arc.nonempty
+ text: "If the context has any subpaths, then the method *must* add a straight line from the last point in the subpath to the start point of the arc<^>."
+ - id: 2d.path.arc.draw
+ text: "it *must* draw the arc between the start point of the arc and the end point of the arc, and add the start and end points of the arc to the subpath<^>."
+ - id: 2d.path.arc.zero
+ text: "If the two points are the same, or if the radius is zero<^>, then the arc is defined as being of zero length in both directions."
+ - id: 2d.path.arc.negative
+ previously: [ 2, "anticlockwise" ]
+ text: "Negative values for radius *must* cause the implementation to raise an INDEX_SIZE_ERR exception<^>."
+
+ - id: 2d.path.rect.subpath
+ text: "The rect(x, y, w, h) method *must* create a new subpath containing just the four points (x, y), (x+w, y), (x+w, y+h), (x, y+h), with those four points connected by straight lines<^>"
+ - id: 2d.path.rect.closed
+ text: "The rect(x, y, w, h) method <...> *must* then mark the subpath as closed<^>."
+ - id: 2d.path.rect.newsubpath
+ text: "The rect(x, y, w, h) method <...> *must* then create a new subpath with the point (x, y) as the only point in the subpath<^>."
+
+ - id: 2d.path.fill.basic
+ text: "The fill() method *must* fill all the subpaths of the current path, using fillStyle, and using the non-zero winding number rule<^>."
+ - id: 2d.path.fill.closed
+ text: "Open subpaths *must* be implicitly closed when being filled (without affecting the actual subpaths)<^>."
+ - id: 2d.path.stroke.basic
+ text: "The stroke() method *must* calculate the strokes of all the subpaths of the current path, using the lineWidth, lineCap, lineJoin, and (if appropriate) miterLimit attributes, and then fill the combined stroke area using the strokeStyle attribute<^>."
+ - id: 2d.path.unaffected
+ text: "Paths, when filled or stroked, *must* be painted without affecting the current path<^>"
+ - id: 2d.path.subjected
+ text: "Paths, when filled or stroked, <...> *must* be subject to shadow effects, global alpha, the clipping region, and global composition operators<^>."
+
+ - id: 2d.path.stroke.prune
+ text: "Zero-length line segments *must* be pruned before stroking a path<^>."
+ - id: 2d.path.stroke.empty
+ text: "Empty subpaths *must* be ignored<^>."
+
+ - id: 2d.path.clip.basic
+ text: "The clip() method *must* create a new clipping region by calculating the intersection of the current clipping region and the area described by the current path, using the non-zero winding number rule<^>."
+ - id: 2d.path.clip.closed
+ text: "Open subpaths *must* be implicitly closed when computing the clipping region, without affecting the actual subpaths<^>."
+ - id: 2d.path.clip.initial
+ text: "When the context is initialized, the clipping region *must* be set to the rectangle with the top left corner at (0,0) and the width and height of the coordinate space<^>."
+ - id: 2d.path.isPointInPath
+ text: "The isPointInPath(x, y) method *must* return true if the point given by the x and y coordinates passed to the method, when treated as coordinates in the canvas coordinate space unaffected by the current transformation, is inside the current path as determined by the non-zero winding number rule; and must return false otherwise<^>."
+ - id: 2d.path.isPointInPath.edge
+ text: "The isPointInPath(x, y) method *must* return true if <...>. Points on the path itself are considered to be inside the path<^>."
+ - id: 2d.path.isPointInPath.nonfinite
+ text: "If either of the arguments is infinite or NaN, then the method *must* return false<^>."
+
+ # TODO: Focus management
+
+ - id: 2d.text.font.parse
+ text: "The font IDL attribute, on setting, *must* be parsed the same way as the 'font' property of CSS (but without supporting property-independent style sheet syntax like 'inherit')<^>,"
+ - id: 2d.text.font.lineheight
+ text: "The font IDL attribute, on setting, *must* be parsed <...> with the 'line-height' component forced to 'normal'<^>,"
+ - id: 2d.text.font.fontsize
+ text: "The font IDL attribute, on setting, *must* be parsed <...> with the 'font-size' component converted to CSS pixels<^>,"
+ - id: 2d.text.font.systemfonts
+ text: "The font IDL attribute, on setting, *must* be parsed <...> with system fonts being computed to explicit values<^>."
+ - id: 2d.text.font.invalid
+ text: "If the new value is syntactically incorrect (including using property-independent style sheet syntax like 'inherit' or 'initial'), then it *must* be ignored, without assigning a new font value<^>."
+
+ - id: 2d.text.font.fontface
+ text: "Font names must be interpreted in the context of the canvas element's stylesheets; any fonts embedded using @font-face *must* therefore be available once they are loaded<^>."
+ - id: 2d.text.font.notfullyloaded
+ text: "If a font is referenced before it is fully loaded, then it *must* be treated as if it was an unknown font, falling back to another as described by the relevant CSS specifications<^>."
+ - id: 2d.text.font.get
+ text: "On getting, the font attribute *must* return the serialized form of the current font of the context (with no 'line-height' component)<^>."
+ - id: 2d.text.font.default
+ text: "When the context is created, the font of the context *must* be set to 10px sans-serif<^>."
+ - id: 2d.text.font.size
+ text: "When the 'font-size' component is set to lengths using percentages, 'em' or 'ex' units, or the 'larger' or 'smaller' keywords, these *must* be interpreted relative to the computed value of the 'font-size' property of the corresponding canvas element at the time that the attribute is set<^>."
+ - id: 2d.text.font.weight
+ text: "When the 'font-weight' component is set to the relative values 'bolder' and 'lighter', these *must* be interpreted relative to the computed value of the 'font-weight' property of the corresponding canvas element at the time that the attribute is set<^>."
+ - id: 2d.text.font.undefined
+ text: "If the computed values are undefined for a particular case (e.g. because the canvas element is not in a Document), then the relative keywords *must* be interpreted relative to the normal-weight 10px sans-serif default<^>."
+ - id: 2d.text.align.get
+ text: "The textAlign IDL attribute, on getting, *must* return the current value<^>."
+ - id: 2d.text.align.set
+ text: "On setting, if the value is one of start, end, left, right, or center, then the value *must* be changed to the new value<^>."
+ - id: 2d.text.align.invalid
+ text: "The textAlign IDL attribute, <...> Otherwise, the new value *must* be ignored<^>."
+ - id: 2d.text.align.default
+ text: "When the context is created, the textAlign attribute *must* initially have the value start<^>."
+ - id: 2d.text.baseline.get
+ text: "The textBaseline IDL attribute, on getting, *must* return the current value<^>."
+ - id: 2d.text.baseline.set
+ text: "On setting, if the value is one of top, hanging, middle, alphabetic, ideographic, or bottom, then the value *must* be changed to the new value<^>."
+ - id: 2d.text.baseline.invalid
+ text: "The textBaseline IDL attribute, <...> Otherwise, the new value *must* be ignored<^>."
+ - id: 2d.text.baseline.default
+ text: "When the context is created, the textBaseline attribute *must* initially have the value alphabetic<^>."
+
+ - id: 2d.text.draw
+ text: "The fillText() and strokeText() methods <...> when the methods are called, the user agent *must* run the following steps<^>:"
+ - id: 2d.text.draw.spaces
+ text: "Replace all the space characters in text with U+0020 SPACE characters<^>."
+ - id: 2d.text.draw.direction
+ text: "the 'direction' property of the inline box set to the directionality of the canvas element<^>,"
+ - id: 2d.text.draw.maxwidth
+ text: "If the maxWidth argument was specified and the hypothetical width of the inline box in the hypothetical line box is greater than maxWidth CSS pixels, then change font to have a more condensed font (if one is available or if a reasonably readable one can be synthesized by applying a horizontal scale factor to the font) or a smaller font, and return to the previous step<^>."
+ - id: 2d.text.align.left
+ text: "Let the anchor point's horizontal position be the left edge of the inline box<^>."
+ - id: 2d.text.align.right
+ text: "Let the anchor point's horizontal position be the right edge of the inline box<^>."
+ - id: 2d.text.align.center
+ text: "Let the anchor point's horizontal position be half way between the left and right edges of the inline box<^>."
+
+ - id: 2d.text.baseline.top
+ text: "Let the anchor point's vertical position be the top of the em box of the first available font of the inline box<^>."
+ - id: 2d.text.baseline.hanging
+ text: "Let the anchor point's vertical position be the hanging baseline of the first available font of the inline box<^>."
+ - id: 2d.text.baseline.middle
+ text: "Let the anchor point's vertical position be half way between the bottom and the top of the em box of the first available font of the inline box<^>."
+ - id: 2d.text.baseline.alphabetic
+ text: "Let the anchor point's vertical position be the alphabetic baseline of the first available font of the inline box<^>."
+ - id: 2d.text.baseline.ideographic
+ text: "Let the anchor point's vertical position be the ideographic baseline of the first available font of the inline box<^>."
+ - id: 2d.text.baseline.bottom
+ text: "Let the anchor point's vertical position be the bottom of the em box of the first available font of the inline box<^>."
+
+ - id: 2d.text.draw.fill
+ text: "For fillText() fillStyle must be applied to the glyphs and strokeStyle *must* be ignored<^>."
+ - id: 2d.text.draw.stroke
+ text: "For strokeText() the reverse holds and strokeStyle must be applied to the glyph outlines and fillStyle *must* be ignored<^>."
+ - id: 2d.text.measure.spaces
+ text: "When the method is invoked, the user agent *must* replace all the space characters in text with U+0020 SPACE characters<^>,"
+ - id: 2d.text.measure
+ text: "When the method is invoked, the user agent <...> *must* form a hypothetical infinitely wide CSS line box containing a single inline box containing the text text, with all the properties at their initial values except the 'white-space' property of the inline element set to 'pre' and the 'font' property of the inline element set to the current font of the context as given by the font attribute, and must then return a new TextMetrics object with its width attribute set to the width of that inline box, in CSS pixels<^>."
+
+ - id: 2d.drawImage.defaultdest
+ text: "If not specified, the dw and dh arguments *must* default to the values of sw and sh, interpreted such that one CSS pixel in the image is treated as one unit in the canvas coordinate space<^>."
+ - id: 2d.drawImage.defaultsource
+ text: "If the sx, sy, sw, and sh arguments are omitted, they *must* default to 0, 0, the image's intrinsic width in image pixels, and the image's intrinsic height in image pixels, respectively<^>."
+ - id: 2d.drawImage.IDL
+ text: "void drawImage(in HTMLVideoElement image, in double sx, in double sy, in double sw, in double sh, in double dx, in double dy, in double dw, in double dh);<^>"
+ - id: 2d.drawImage.incomplete.image
+ text: "If the image argument is an HTMLImageElement object that is not fully decodable<^><...> then the implementation *must* return without drawing anything."
+ - id: 2d.drawImage.incomplete.video
+ previously: [ 6, "dw and dh" ]
+ text: "If the image argument is <...> an HTMLVideoElement object whose readyState attribute is either HAVE_NOTHING or HAVE_METADATA<^>, then the implementation *must* return without drawing anything."
+ - id: 2d.drawImage.zerocanvas
+ previously: [ 10, "dw and dh" ]
+ text: "If the image argument is an HTMLCanvasElement object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* raise an INVALID_STATE_ERR exception<^>."
+ - id: 2d.drawImage.zerosource
+ text: "If one of the sw or sh arguments is zero<^>, the implementation *must* raise an INDEX_SIZE_ERR exception."
+ - id: 2d.drawImage.paint
+ text: "When drawImage() is invoked, the region of the image specified by the source rectangle *must* be painted on the region of the canvas specified by the destination rectangle<^>, after applying the current transformation matrix to the points of the destination rectangle."
+ - id: 2d.drawImage.original
+ text: "The original image data of the source image *must* be used, not the image as it is rendered (e.g. width and height attributes on the source element have no effect)<^>."
+ - id: 2d.drawImage.direction
+ text: "The image data *must* be processed in the original direction, even if the dimensions given are negative<^>."
+ - id: 2d.drawImage.self
+ text: "When a canvas is drawn onto itself, the drawing model requires the source to be copied before the image is drawn back onto the canvas, so it is possible to copy parts of a canvas onto overlapping parts of itself<^>."
+ - id: 2d.drawImage.animated.image
+ text: "When the drawImage() method is passed an animated image as its image argument, the user agent *must* use the poster frame of the animation, or, if there is no poster frame, the first frame of the animation<^>."
+ - id: 2d.drawImage.animated.video
+ previously: [ 4, "drawImage" ]
+ text: "When the image argument is an HTMLVideoElement, then the frame at the current playback position *must* be used as the source image<^>,"
+ - id: 2d.drawImage.video.size
+ previously: [ 4, "drawImage" ]
+ text: "When the image argument is an HTMLVideoElement, <...> the source image's dimensions *must* be the intrinsic width and intrinsic height of the media resource (i.e. after any aspect-ratio correction has been applied)<^>."
+ - id: 2d.drawImage.unaffect
+ text: "Images are painted without affecting the current path<^>"
+ - id: 2d.drawImage.subject
+ text: "Images are painted without affecting the current path, and are subject to shadow effects, global alpha, the clipping region, and global composition operators<^>."
+
+
+ - id: 2d.imageData.create2.object
+ text: "When the method is invoked with two arguments sw and sh, it *must* return an ImageData object<^>"
+ - id: 2d.imageData.create2.size
+ text: "When the method is invoked with two arguments sw and sh, it *must* return an ImageData object representing a rectangle with a width in CSS pixels equal to the absolute magnitude of sw and a height in CSS pixels equal to the absolute magnitude of sh<^>."
+ - id: 2d.imageData.create1.object
+ text: "When invoked with a single imagedata argument, it *must* return an ImageData object<^>"
+ - id: 2d.imageData.create1.size
+ text: "When invoked with a single imagedata argument, it *must* return an ImageData object representing a rectangle with the same dimensions as the ImageData object passed as the argument<^>."
+ - id: 2d.imageData.create.initial
+ text: "The ImageData object returned must be filled with transparent black<^>."
+
+ - id: 2d.imageData.get.object
+ text: "The getImageData(sx, sy, sw, sh) method *must* return an ImageData object<^>"
+ - id: 2d.imageData.get.basic
+ text: "The getImageData(sx, sy, sw, sh) method *must* return an ImageData object representing the underlying pixel data for the area of the canvas denoted by the rectangle whose corners are the four points (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh), in canvas coordinate space units<^>."
+ - id: 2d.imageData.get.outside
+ text: "Pixels outside the canvas *must* be returned as transparent black<^>."
+ - id: 2d.imageData.get.premul
+ text: "Pixels *must* be returned as non-premultiplied alpha values<^>."
+
+ - id: 2d.imageData.getcreate.nonfinite
+ text: "If any of the arguments to createImageData() or getImageData() are infinite or NaN<^>, the method *must* instead raise a NOT_SUPPORTED_ERR exception."
+ - id: 2d.imageData.create.null
+ text: "ImageData createImageData(in ImageData imagedata);<^>"
+ - id: 2d.imageData.getcreate.zero
+ text: "If either the sw or sh arguments are zero, the method *must* instead raise an INDEX_SIZE_ERR exception<^>."
+
+ - id: 2d.imageData.initial
+ text: "ImageData objects *must* be initialized so that their width attribute is set to w, the number of physical device pixels per row in the image data, their height attribute is set to h, the number of rows in the image data, and their data attribute is initialized to a CanvasPixelArray object holding the image data<^>."
+ - id: 2d.imageData.one
+ text: "At least one pixel's worth of image data *must* be returned<^>."
+ - id: 2d.pixelarray.order
+ text: "The data *must* be represented in left-to-right order, row by row top to bottom, starting with the top left, with each pixel's red, green, blue, and alpha components being given in that order for each pixel<^>."
+ - id: 2d.pixelarray.range
+ text: "Each component of each device pixel represented in this array *must* be in the range 0..255, representing the 8 bit value for that component<^>."
+ - id: 2d.pixelarray.indexes
+ text: "The components *must* be assigned consecutive indices starting with 0 for the top left pixel's red component<^>."
+ - id: 2d.pixelarray.length
+ text: "The length attribute of a CanvasPixelArray object *must* return this number<^>."
+ - id: 2d.pixelarray.retrieve
+ text: "To determine the value of an indexed property index, the user agent *must* return the value of the indexth component in the array<^>."
+ - id: 2d.pixelarray.modify
+ text: "To set the value of an existing indexed property index to value value, the value of the indexth component in the array *must* be set to value<^>."
+
+ - id: 2d.imageData.put.nonfinite
+ text: "If any of the arguments to the method are infinite or NaN, the method *must* raise a NOT_SUPPORTED_ERR exception<^>."
+ - id: 2d.imageData.put.wrongtype
+ text: "void putImageData(in ImageData imagedata, in double dx, in double dy);<...>void putImageData(in ImageData imagedata, in double dx, in double dy, in double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);<^>"
+ - id: 2d.imageData.put.3arg
+ text: "When the last four arguments are omitted, they *must* be assumed to have the values 0, 0, the width member of the imagedata structure, and the height member of the imagedata structure, respectively<^>."
+ - id: 2d.imageData.put.normal
+ text: "When invoked with arguments that do not, per the last few paragraphs, cause an exception to be raised, the putImageData() method *must* act as follows<^>:"
+
+ - id: 2d.imageData.unchanged
+ text: "the following *must* result in no visible changes to the rendering<^>:"
+ - id: 2d.imageData.createround
+ text: "...*must* return ImageData objects with the same dimensions, for any value of w and h<^>."
+ - id: 2d.imageData.unaffected
+ text: "The current path, transformation matrix, shadow attributes, global alpha, the clipping region, and global composition operator *must* not affect the getImageData() and putImageData() methods<^>."
+
+ - id: 2d.drawingmodel
+ text: "When a shape or image is painted, user agents *must* follow these steps, in the order given (or act as if they do)<^>:"
+
+ - id: 2d.colorspace.correction
+ text: "The canvas APIs *must* perform color correction at only two points: when rendering images with their own gamma correction and color space information onto the canvas, to convert the image to the color space used by the canvas (e.g. using the 2D Context's drawImage() method with an HTMLImageElement object)<^>,"
+ - id: 2d.colorspace.toDataURL.info
+ text: "The toDataURL() method *must* not include color space information in the resource returned<^>."
+ - id: 2d.colorspace.toDataURL.equal
+ text: "Where the output format allows it, the color of pixels in resources created by toDataURL() *must* match those returned by the getImageData() method<^>."
+ - id: 2d.colorspace.match
+ text: "In user agents that support CSS, the color space used by a canvas element *must* match the color space used for processing any colors for that element in CSS<^>."
+ - id: 2d.colorspace.img.equal
+ text: "The gamma correction and color space information of images *must* be handled in such a way that an image rendered directly using an img element would use the same colors as one painted on a canvas element that is then itself rendered<^>."
+ - id: 2d.colorspace.img.noinfo
+ text: "Furthermore, the rendering of images that have no color correction information (such as those returned by the toDataURL() method) *must* be rendered with no color correction<^>."
+
+ - id: security.start
+ text: "All canvas elements *must* start with their origin-clean set to true<^>."
+ - id: security.drawImage.image
+ keyword: must
+ text: "The element's 2D context's drawImage() method is called with an HTMLImageElement or an HTMLVideoElement whose origin is not the same as that of the Document object that owns the canvas element<^>."
+ - id: security.drawImage.canvas
+ keyword: must
+ text: "The element's 2D context's drawImage() method is called with an HTMLCanvasElement whose origin-clean flag is false<^>."
+ - id: security.fillStyle.image
+ keyword: must
+ text: "The element's 2D context's fillStyle attribute is set to a CanvasPattern object that was created from an HTMLImageElement<^> or an HTMLVideoElement whose origin was not the same as that of the Document object that owns the canvas element when the pattern was created."
+ - id: security.fillStyle.video
+ keyword: must
+ text: "The element's 2D context's fillStyle attribute is set to a CanvasPattern object that was created from an HTMLImageElement or an HTMLVideoElement<^> whose origin was not the same as that of the Document object that owns the canvas element when the pattern was created."
+ - id: security.fillStyle.canvas
+ keyword: must
+ text: "The element's 2D context's fillStyle attribute is set to a CanvasPattern object that was created from an HTMLCanvasElement whose origin-clean flag was false when the pattern was created<^>."
+ - id: security.strokeStyle.image
+ keyword: must
+ text: "The element's 2D context's strokeStyle attribute is set to a CanvasPattern object that was created from an HTMLImageElement<^> or an HTMLVideoElement whose origin was not the same as that of the Document object that owns the canvas element when the pattern was created."
+ - id: security.strokeStyle.video
+ keyword: must
+ text: "The element's 2D context's strokeStyle attribute is set to a CanvasPattern object that was created from an HTMLImageElement or an HTMLVideoElement<^> whose origin was not the same as that of the Document object that owns the canvas element when the pattern was created."
+ - id: security.strokeStyle.canvas
+ keyword: must
+ text: "The element's 2D context's strokeStyle attribute is set to a CanvasPattern object that was created from an HTMLCanvasElement whose origin-clean flag was false when the pattern was created<^>."
+ - id: security.toDataURL
+ text: "Whenever the toDataURL() method of a canvas element whose origin-clean flag is set to false is called, the method *must* raise a SECURITY_ERR exception<^>."
+ - id: security.getImageData
+ text: "Whenever the getImageData() method of the 2D context of a canvas element whose origin-clean flag is set to false is called with otherwise correct arguments, the method *must* raise a SECURITY_ERR exception<^>."