# Extracts from http://www.whatwg.org/specs/web-apps/current-work/

assertions:
  - id: fallback
    text: "The contents of the canvas element, if any, are the element's fallback content<^>."
  - id: canvas.type
    text: "interface HTMLCanvasElement<^> : HTMLElement {"
  - id: size.width
    text: "attribute unsigned long width;<^>"
  - id: size.height
    text: "attribute unsigned long height;<^>"
  - 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.colour
    text: "When the canvas is initialized it *must* be set to fully transparent black<^>."
  - id: initial.reset
    text: "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: size.reflect
    text: "The width and height DOM attributes *must* reflect the content attributes of the same name<^>."

  - id: context.2d
    text: "If getContext() is called with that exact string for its contextId argument, then the UA *must* return a reference to an object implementing CanvasRenderingContext2D<^>."
  - id: context.empty
    text: "When the UA is passed an empty string<^> <...> then it *must* return null."
  - id: context.unrecognised
    text: "When the UA is passed <...> a string specifying a context that it does not support<^>, then it *must* return null."
  - id: context.casesensitive
    text: "String comparisons *must* be <...> case-sensitive<^>."
  - id: context.extraarguments
    text: "Arguments other than the contextId *must* be ignored, and must not cause the user agent to raise an exception (as would normally occur if a method was called with the wrong number of arguments)<^>."

  - id: toDataURL.noarguments
    text: "The toDataURL() method *must*, when called with no arguments, return a data: URI containing a representation of the image as a PNG file<^>."
  - id: toDataURL.zerosize
    text: "If the canvas has no pixels (i.e. either its horizontal dimension or its vertical dimension is zero) then the method *must* return the string \"data:,\"<^>."
  - id: toDataURL.png
    text: "support for image/png is *required*<^>."
  - id: toDataURL.unrecognised
    text: "If the user agent does not support the requested type, it *must* return the image using the PNG format<^>."
  - id: toDataURL.lowercase
    text: "User agents *must* convert the provided type to lower case before establishing if they support that type and before creating the data: URI<^>."
  - id: toDataURL.arguments
    text: "Other arguments *must* be ignored and must not cause the user agent to raise an exception (as would normally occur if a method was called with the wrong number of arguments)<^>."

  - id: context.2d.unique
    text: "calling the getContext() method with the 2d argument a second time *must* return the same object<^>."

  - 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.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: "Unless otherwise stated, 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<^>."

  - meta: |
        for s in ['strokeStyle', 'fillStyle', 'globalAlpha', 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor', 'globalCompositeOperation']:
            assertions.append( {
                'id': '2d.state.%s' % s,
                'text': 'The current values of the following attributes:<...>%s<^>' % s
            } )
  - id: 2d.state.transformation
    text: "The current transformation matrix<^>."
  - id: 2d.state.clip
    text: "The current clipping region<^>."
  - 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.order
    text: "For instance, <...> the actual result will be a square<^>."
  - 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(m11, m12, m21, m22, dx, dy) method *must* multiply the current transformation matrix with the matrix described by<^>:"
  - id: 2d.transformation.transform.multiply
    text: "The transform(m11, m12, m21, m22, dx, dy) method *must* multiply<^> the current transformation matrix with the matrix described by:"
  - id: 2d.transformation.setTransform
    text: "The setTransform(m11, m12, m21, m22, dx, dy) method *must* <...> invoke the transform(m11, m12, m21, m22, dx, dy) method with the same arguments<^>"
  - id: 2d.transformation.setTransform.identity
    text: "The setTransform(m11, m12, m21, m22, dx, dy) 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, 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.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 do not exactly match the values given above<^>."
  - 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<^>, <...> [CSS3COLOR]"
  - id: 2d.colours.invalidstring
    text: "If the value is a string but is not a valid color<^>, <...> 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.solid
    text: "if it has alpha equal to 1.0, then the string is a lowercase six-digit hex value<^>"
  - id: 2d.colours.getcolour.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: <...> finally a U+0029 RIGHT PARENTHESIS<^>."
  - 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.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.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.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, 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.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.return.linear
    text: "Otherwise, the method *must* return a linear CanvasGradient<^> initialized with the specified line."
  - 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.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.return.radial
    text: "Otherwise, the method *must* return a radial CanvasGradient<^> initialized with the two specified circles<^>."
  - 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.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.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 or null 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.wrongtype
    previously: [ 1, "createPattern" ]
    text: "The image argument must be an instance of an HTMLImageElement or HTMLCanvasElement. If the image is of the wrong type or null, the implementation *must* raise a TYPE_MISMATCH_ERR exception<^>."
  - id: 2d.pattern.incomplete
    previously: [ 5, "createPattern" ]
    text: "If the image argument is an HTMLImageElement object whose complete attribute is false, then the implementation *must* raise an INVALID_STATE_ERR exception<^>."
  - id: 2d.pattern.zerocanvas
    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
    text: "When the createPattern() method is passed, as its image argument, an animated image, the poster frame of the animation, or the first frame of the animation if there is no poster frame, *must* be used<^>."
  - id: 2d.pattern.unsupported
    text: "If the user agent doesn't support patterns, then createPattern() *must* return null<^>."


  - id: 2d.lineWidth
    text: "The lineWidth attribute gives the width of lines, in coordinate space units<^>."
  - 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.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.invalid
    text: "On setting, any other value than the literal strings butt, round, and square *must* be 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.invalid
    text: "On setting, any other value than the literal strings bevel, round, and miter *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.invalid
    text: "The <...> miterLimit attribute. On setting, zero, negative, infinite, and NaN values *must* be ignored, leaving the value unchanged<^>."
  - id: 2d.miterLimit.default
    text: "When the context is created, the miterLimit attribute *must* initially have the value 10.0<^>."

  - 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.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* do nothing 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* do nothing if the context has no subpaths<^>."
  - 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* do nothing if the context has no subpaths<^>."
  - 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* do nothing if the context has no subpaths<^>."
  - 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.same
    text: "if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, then: if the direction from (x0, y0) to (x1, y1) is the same as the direction from (x1, y1) to (x2, y2), 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.opposite
    text: "otherwise, the direction from (x0, y0) to (x1, y1) is the opposite of the direction from (x1, y1) to (x2, y2), and the method *must* add a point <...> on the same side of (x1, y1) on that line as (x2, y2)<^>."
  - 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.arcTo.negative
    text: "Negative values for radius *must* cause the implementation to raise an INDEX_SIZE_ERR exception<^>."
    previously: [ 1, "The arcTo(x1, y1, x2, y2, radius) method" ]
  - 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
    text: "Negative values for radius *must* cause the implementation to raise an INDEX_SIZE_ERR exception<^>."
    previously: [ 7, "The arc(x, y, radius, startAngle, endAngle, anticlockwise) method" ]
  - 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; 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<^>."

  - 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.type
    previously: [ 1, 'drawImage' ]
    text: "The image argument must be an instance of an HTMLImageElement or HTMLCanvasElement. If the image is of the wrong type or null, the implementation *must* raise a TYPE_MISMATCH_ERR exception<^>."
  - id: 2d.drawImage.outsidesource
    text: "If the source rectangle is not entirely within the source image<^><...> the implementation *must* raise an INDEX_SIZE_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.incomplete
    previously: [ 5, "drawImage" ]
    text: "If the image argument is an HTMLImageElement object whose complete attribute is false, then the implementation *must* raise an INVALID_STATE_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.animated
    text: "When the drawImage() method is passed, as its image argument, an animated image, the poster frame of the animation, or the first frame of the animation if there is no poster frame, *must* be used<^>."
  - 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.create.object
    text: "The createImageData(sw, sh) method *must* return an ImageData object<^>"
  - id: 2d.imageData.create.size
    text: "The createImageData(sw, sh) method *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.create.initial
    text: "The createImageData(sw, sh) method *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, 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.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.type
    text: "interface ImageData<^> {"
  - 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.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.imageData.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.imageData.one
    text: "At least one pixel's worth of image data *must* be returned<^>."

  - id: 2d.imageData.set.basic
    text: "The XXX6(index, value) method *must* set the value of the indexth component in the array to value<^>."
  - id: 2d.imageData.set.undefined
    text: "JS undefined values *must* be converted to zero<^>."
  - id: 2d.imageData.set.tonumber
    text: "Other values *must* first be converted to numbers using JavaScript's ToNumber algorithm<^>,"
  - id: 2d.imageData.set.nan
    text: "if the result is a NaN value, then the value be *must* converted to zero<^>."
  - id: 2d.imageData.set.clamp0
    text: "If the result is less than 0, it *must* be clamped to zero<^>."
  - id: 2d.imageData.set.clamp255
    text: "If the result is more than 255, it *must* be clamped to 255<^>."
  - id: 2d.imageData.set.round
    text: "If the number is not an integer, it *must* be rounded to the nearest integer using the IEEE 754r convertToIntegerTiesToEven rounding mode<^>."

  - id: 2d.imageData.put.nonfinite
    text: "If any of the arguments to the method are infinite or NaN, the method *must* raise an NOT_SUPPORTED_ERR exception<^>."
  - id: 2d.imageData.put.null
    text: "If the first argument to the method is null<^> or not an ImageData object then the putImageData() method *must* raise a TYPE_MISMATCH_ERR exception."
  - id: 2d.imageData.put.wrongtype
    text: "If the first argument to the method is null or not an ImageData object<^> then the putImageData() method *must* raise a TYPE_MISMATCH_ERR exception."
  - 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: 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 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 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 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 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 exception<^>."

#  - id: nonnegative.return
#    text: "This algorithm will either return zero, a positive integer, or an error<^>."
#  - id: nonnegative.leading
#    text: "Leading spaces are ignored<^>."
#  - id: nonnegative.trailing
#    text: "Trailing spaces and indeed any trailing garbage characters are ignored<^>."
