%s' % test['notes'] if 'notes' in test else ''
+
+ images = ''
+ for i in test.get('images', []):
+ id = i.split('/')[-1]
+ if '/' not in i:
+ used_images[i] = 1
+ i = '../images/%s' % i
+ images += ' \n' % (i,id)
+ mochi_images = images.replace('../images/', 'image_')
+ if W3CMODE: images = images.replace("../images/", "/images/")
+
+ fonts = ''
+ fonthack = ''
+ for i in test.get('fonts', []):
+ fonts += '@font-face {\n font-family: %s;\n src: url("/fonts/%s.ttf");\n}\n' % (i, i)
+ # Browsers require the font to actually be used in the page
+ if test.get('fonthack', 1):
+ fonthack += 'A \n' % i
+ if fonts:
+ fonts = '\n' % fonts
+
+ fallback = test.get('fallback', '
\n')
+ for ua in uas:
+ f.write(' %s\n' % ua)
+ f.write('\n')
+
+def getNodeText(node):
+ t, offsets = '', []
+
+ # Skip over any previous annotations we added
+ if node.nodeType == node.ELEMENT_NODE and 'testrefs' in node.getAttribute('class').split(' '):
+ return t, offsets
+
+ if node.nodeType == node.TEXT_NODE:
+ val = node.nodeValue
+ val = val.replace(unichr(0xa0), ' ') # replace s
+ t += val
+ offsets += [ (node, len(node.nodeValue)) ]
+ for n in node.childNodes:
+ child_t, child_offsets = getNodeText(n)
+ t += child_t
+ offsets += child_offsets
+ return t, offsets
+
+def htmlSerializer(element):
+ element.normalize()
+ rv = []
+ specialtext = ['style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript']
+ empty = ['area', 'base', 'basefont', 'bgsound', 'br', 'col', 'embed', 'frame',
+ 'hr', 'img', 'input', 'link', 'meta', 'param', 'spacer', 'wbr']
+
+ def serializeElement(element):
+ if element.nodeType == Node.DOCUMENT_TYPE_NODE:
+ rv.append("" % element.name)
+ elif element.nodeType == Node.DOCUMENT_NODE:
+ for child in element.childNodes:
+ serializeElement(child)
+ elif element.nodeType == Node.COMMENT_NODE:
+ rv.append("" % element.nodeValue)
+ elif element.nodeType == Node.TEXT_NODE:
+ unescaped = False
+ n = element.parentNode
+ while n is not None:
+ if n.nodeName in specialtext:
+ unescaped = True
+ break
+ n = n.parentNode
+ if unescaped:
+ rv.append(element.nodeValue)
+ else:
+ rv.append(escapeHTML(element.nodeValue))
+ else:
+ rv.append("<%s" % element.nodeName)
+ if element.hasAttributes():
+ for name, value in element.attributes.items():
+ rv.append(' %s="%s"' % (name, escapeHTML(value)))
+ rv.append(">")
+ if element.nodeName not in empty:
+ for child in element.childNodes:
+ serializeElement(child)
+ rv.append("%s>" % element.nodeName)
+ serializeElement(element)
+ return '\n' + ''.join(rv)
+
+def write_annotated_spec():
+ # Load the stripped-down XHTMLised copy of the spec
+ doc = xml.dom.minidom.parse(open('current-work-canvas.xhtml', 'r'))
+
+ # Insert our new stylesheet
+ n = doc.getElementsByTagName('head')[0].appendChild(doc.createElement('link'))
+ n.setAttribute('rel', 'stylesheet')
+ n.setAttribute('href', '../common/canvas-spec.css' if W3CMODE else '../spectest.css')
+ n.setAttribute('type', 'text/css')
+
+ spec_assertion_patterns = []
+ for a in spec_assertions:
+ # Warn about problems
+ if a['id'] not in spec_refs:
+ print "Unused spec statement %s" % a['id']
+
+ pattern_text = a['text']
+
+ if 'keyword' in a:
+ # Explicit keyword override
+ keyword = a['keyword']
+ else:
+ # Extract the marked keywords, and remove the markers
+ keyword = 'none'
+ for kw in ['must', 'should', 'required']:
+ if ('*%s*' % kw) in pattern_text:
+ keyword = kw
+ pattern_text = pattern_text.replace('*%s*' % kw, kw)
+ break
+ # Make sure there wasn't >1 keyword
+ for kw in ['must', 'should', 'required']:
+ assert('*%s*' % kw not in pattern_text)
+
+ # Convert the special pattern format into regexp syntax
+ pattern_text = (pattern_text.
+ # Escape relevant characters
+ replace('*', r'\*').
+ replace('+', r'\+').
+ replace('.', r'\.').
+ replace('(', r'\(').
+ replace(')', r'\)').
+ replace('[', r'\[').
+ replace(']', r'\]').
+ # Convert special sequences back into unescaped regexp code
+ replace(' ', r'\s+').
+ replace(r'<\.\.\.>', r'.+').
+ replace('<^>', r'()').
+ replace('', r'\s*?\n')
+ )
+ pattern = re.compile(pattern_text, re.S)
+ spec_assertion_patterns.append( (a['id'], pattern, keyword, a.get('previously', None)) )
+ matched_assertions = {}
+
+ def process_element(e):
+ if e.nodeType == e.ELEMENT_NODE and (e.getAttribute('class') == 'impl' or e.hasAttribute('data-component')):
+ for c in e.childNodes:
+ process_element(c)
+ return
+
+ t, offsets = getNodeText(e)
+ for id, pattern, keyword, previously in spec_assertion_patterns:
+ m = pattern.search(t)
+ if m:
+ # When the pattern-match isn't enough to uniquely identify a sentence,
+ # allow explicit back-references to earlier paragraphs
+ if previously:
+ if len(previously) >= 3:
+ n, text, exp = previously
+ else:
+ n, text = previously
+ exp = True
+ node = e
+ while n and node.previousSibling:
+ node = node.previousSibling
+ n -= 1
+ if (text not in getNodeText(node)[0]) == exp:
+ continue # discard this match
+
+ if id in matched_assertions:
+ print "Spec statement %s matches multiple places" % id
+ matched_assertions[id] = True
+
+ if m.lastindex != 1:
+ print "Spec statement %s has incorrect number of match groups" % id
+
+ end = m.end(1)
+ end_node = None
+ for end_node, o in offsets:
+ if end < o:
+ break
+ end -= o
+ assert(end_node)
+
+ n1 = doc.createElement('span')
+ n1.setAttribute('class', 'testrefs kw-%s' % keyword)
+ n1.setAttribute('id', 'testrefs.%s' % id)
+ n1.appendChild(doc.createTextNode(' '))
+
+ n = n1.appendChild(doc.createElement('a'))
+ n.setAttribute('href', '#testrefs.%s' % id)
+ n.setAttribute('title', id)
+ n.appendChild(doc.createTextNode('#'))
+
+ n1.appendChild(doc.createTextNode(' '))
+ for test_id in spec_refs.get(id, []):
+ n = n1.appendChild(doc.createElement('a'))
+ n.setAttribute('href', '../canvas/%s.html' % test_id)
+ n.appendChild(doc.createTextNode(test_id))
+ n1.appendChild(doc.createTextNode(' '))
+ n0 = doc.createTextNode(end_node.nodeValue[:end])
+ n2 = doc.createTextNode(end_node.nodeValue[end:])
+
+ p = end_node.parentNode
+ p.replaceChild(n2, end_node)
+ p.insertBefore(n1, n2)
+ p.insertBefore(n0, n1)
+
+ t, offsets = getNodeText(e)
+
+ for e in doc.getElementsByTagName('body')[0].childNodes:
+ process_element(e)
+
+ for s in spec_assertions:
+ if s['id'] not in matched_assertions:
+ print "Annotation incomplete: Unmatched spec statement %s" % s['id']
+
+ # Convert from XHTML back to HTML
+ doc.documentElement.removeAttribute('xmlns')
+ doc.documentElement.setAttribute('lang', doc.documentElement.getAttribute('xml:lang'))
+
+ head = doc.documentElement.getElementsByTagName('head')[0]
+ head.insertBefore(doc.createElement('meta'), head.firstChild).setAttribute('charset', 'UTF-8')
+
+ f = codecs.open('%s/canvas.html' % SPECOUTPUTDIR, 'w', 'utf-8')
+ f.write(htmlSerializer(doc))
+
+if not W3CMODE:
+ write_index()
+ write_category_indexes()
+ write_reportgen()
+ write_results()
+ write_annotated_spec()
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/name2dir.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/name2dir.yaml
new file mode 100644
index 00000000000..6c170ce5537
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/name2dir.yaml
@@ -0,0 +1,45 @@
+2d.transformation: "transformations"
+2d.composite: "compositing"
+2d.coordinatespace: "conformance-requirements"
+2d.missingargs: "conformance-requirements"
+2d.type.delete: "conformance-requirements"
+2d.voidreturn: "conformance-requirements"
+2d.drawImage: "drawing-images-to-the-canvas"
+2d.clearRect: "drawing-rectangles-to-the-canvas"
+2d.fillRect: "drawing-rectangles-to-the-canvas"
+2d.strokeRect: "drawing-rectangles-to-the-canvas"
+2d.text.draw: "drawing-text-to-the-canvas"
+2d.text.draw.baseline.alphabetic: "drawing-text-to-the-canvas"
+2d.text.draw.space.basic: "drawing-text-to-the-canvas"
+2d.text.draw.space.collapse: "drawing-text-to-the-canvas"
+2d.text.measure: "drawing-text-to-the-canvas"
+2d.fillStyle: "fill-and-stroke-styles"
+2d.gradient: "fill-and-stroke-styles"
+2d.pattern: "fill-and-stroke-styles"
+2d.strokeStyle: "fill-and-stroke-styles"
+2d.line: "line-styles"
+2d.path: "path-objects"
+2d.imageData: "pixel-manipulation"
+2d.shadow: "shadows"
+2d.text.align: "text-styles"
+2d.text.baseline: "text-styles"
+2d.text.font: "text-styles"
+2d.text.draw.baseline: "text-styles"
+2d.text.draw.space: "text-styles"
+2d.text.measure.width.space: "text-styles"
+2d.text.draw.space.collapse.end: "text-styles"
+2d.text.draw.space.collapse.other: "text-styles"
+2d.text.draw.space.collapse.space: "text-styles"
+2d.text.draw.space.collapse.start: "text-styles"
+2d.state: "the-canvas-state"
+2d.canvas: "../html/semantics/embedded-content/the-canvas-element/"
+2d.getcontext: "../html/semantics/embedded-content/the-canvas-element/"
+2d.scaled: "../html/semantics/embedded-content/the-canvas-element/"
+2d.type: "../html/semantics/embedded-content/the-canvas-element/"
+context: "../html/semantics/embedded-content/the-canvas-element/"
+fallback: "../html/semantics/embedded-content/the-canvas-element/"
+initial: "../html/semantics/embedded-content/the-canvas-element/"
+security: "../html/semantics/embedded-content/the-canvas-element/"
+size: "../html/semantics/embedded-content/the-canvas-element/"
+toDataURL: "../html/semantics/embedded-content/the-canvas-element/"
+type: "../html/semantics/embedded-content/the-canvas-element/"
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/spec.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/spec.yaml
new file mode 100644
index 00000000000..12b7d6be990
--- /dev/null
+++ b/tests/wpt/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<^>"
+ - id: 2d.composite.source-in
+ text: "source-in<^>"
+ - id: 2d.composite.source-out
+ text: "source-out<^>"
+ - id: 2d.composite.source-over
+ text: "source-over (default)<^>"
+ - id: 2d.composite.destination-atop
+ text: "destination-atop<^>"
+ - id: 2d.composite.destination-in
+ text: "destination-in<^>"
+ - id: 2d.composite.destination-out
+ text: "destination-out<^>"
+ - id: 2d.composite.destination-over
+ text: "destination-over<^>"
+ - id: 2d.composite.lighter
+ text: "lighter<^>"
+ - id: 2d.composite.copy
+ text: "copy<^>"
+ - id: 2d.composite.xor
+ text: "xor<^>"
+
+ - 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 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 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 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 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 value and the color assigned<^>."
+ - id: 2d.shadow.color.invalid
+ text: "If the value cannot be parsed as a CSS 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<^>."
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/specextract.py b/tests/wpt/web-platform-tests/2dcontext/tools/specextract.py
new file mode 100644
index 00000000000..679bf10e285
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/specextract.py
@@ -0,0 +1,57 @@
+import html5lib
+import html5lib.treebuilders.dom
+
+# Expected use:
+# curl --compressed http://www.whatwg.org/specs/web-apps/current-work/ >current-work
+# python specextract.py
+#
+# Generates current-work-canvas.xhtml, for use by gentest.py to create the annotated spec document
+
+def extract():
+ parser = html5lib.html5parser.HTMLParser(tree=html5lib.treebuilders.dom.TreeBuilder)
+ doc = parser.parse(open('current-work'), encoding='utf-8')
+
+ head = doc.getElementsByTagName('head')[0]
+ for n in head.childNodes:
+ if n.tagName == 'script':
+ head.removeChild(n)
+
+ header = doc.getElementsByTagName('header')[0]
+ #thecanvas = doc.getElementById('the-canvas') # doesn't work (?!)
+ thecanvas = [ n for n in doc.getElementsByTagName('h4') if n.getAttribute('id') == 'the-canvas-element' ][0]
+
+ keep = [header, thecanvas]
+ node = thecanvas.nextSibling
+ while node.nodeName != 'h4':
+ keep.append(node)
+ node = node.nextSibling
+ p = thecanvas.parentNode
+ for n in p.childNodes[:]:
+ if n not in keep:
+ p.removeChild(n)
+
+ for n in header.childNodes[3:-4]:
+ header.removeChild(n)
+
+ def make_absolute(uri):
+ if uri.startswith('data:'):
+ return uri
+ elif uri[0] == '/':
+ return 'http://www.whatwg.org' + uri
+ else:
+ return 'http://www.whatwg.org/specs/web-apps/current-work/' + uri
+
+ # Fix the stylesheet, icon and image references
+ for e in doc.getElementsByTagName('link'):
+ e.setAttribute('href', make_absolute(e.getAttribute('href')))
+ for img in doc.getElementsByTagName('img'):
+ img.setAttribute('src', make_absolute(img.getAttribute('src')))
+
+ # Convert to XHTML, because it's quicker to re-parse than HTML5
+ doc.documentElement.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
+ doc.documentElement.setAttribute('xml:lang', doc.documentElement.getAttribute('lang'))
+ doc.removeChild(doc.firstChild) # remove the DOCTYPE
+
+ open('current-work-canvas.xhtml', 'w').write(doc.toxml(encoding = 'UTF-8'))
+
+extract()
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/templates.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/templates.yaml
new file mode 100644
index 00000000000..8c8e8fda708
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/templates.yaml
@@ -0,0 +1,378 @@
+# Copyright (c) 2010 Philip Taylor
+# Released under the BSD license and W3C Test Suite License: see LICENSE.txt
+
+framed: |
+
+ Canvas test: %(name)s
+
+
+ %(fonts)s
+
+ [show output]
+ %(fonthack)s
Actual output:
+ %(fallback)s
+ %(expected)s
+
+
+ %(images)s
+
+standalone: |
+
+ Canvas test: %(name)s
+
+
+
+
+ %(fonts)s
+
+ <
+ [index]
+ >
+
%(backrefs)s
+ %(desc)s
+
+ %(notes)s
+ %(fonthack)sActual output:
+ %(fallback)s
+ %(expected)s
+
+
+ %(images)s
+
+minimal: |
+
+
+ Canvas test: %(name)s
+
+
+
+
+ %(fonts)s
+ Pass
+ Fail
+
+ %(fonthack)sThese images should be identical:
+ %(fallback)s
+ %(expected)s
+
+
+ %(images)s
+
+w3c: |
+
+
+ Canvas test: %(name)s
+
+
+
+
+ %(fonts)s
+
+ %(name)s
+ %(desc)s
+
+ %(notes)s
+ %(fonthack)sActual output:
+ %(fallback)s
+ %(expected)s
+
+
+ %(images)s
+
+mochitest: |
+
+ %(mochi_name_fn)s
+ %(mochi_desc)s
+
+
+ %(fonts)s
+
+ Canvas test: %(mochi_name)s
+ %(mochi_desc)s%(fonthack)s%(fallback)s
+
+ %(mochi_images)s
+
+mochitest.isPixel: |
+ function isPixel(ctx, x,y, r,g,b,a, pos, colour, d) {
+ var pixel = ctx.getImageData(x, y, 1, 1);
+ var pr = pixel.data[0],
+ pg = pixel.data[1],
+ pb = pixel.data[2],
+ pa = pixel.data[3];
+ ok(r-d <= pr && pr <= r+d &&
+ g-d <= pg && pg <= g+d &&
+ b-d <= pb && pb <= b+d &&
+ a-d <= pa && pa <= a+d,
+ "pixel "+pos+" is "+pr+","+pg+","+pb+","+pa+"; expected "+colour+" +/- "+d);
+ }
+
+mochitest.todo_isPixel: |
+ function todo_isPixel(ctx, x,y, r,g,b,a, pos, colour, d) {
+ var pixel = ctx.getImageData(x, y, 1, 1);
+ var pr = pixel.data[0],
+ pg = pixel.data[1],
+ pb = pixel.data[2],
+ pa = pixel.data[3];
+ todo(r-d <= pr && pr <= r+d &&
+ g-d <= pg && pg <= g+d &&
+ b-d <= pb && pb <= b+d &&
+ a-d <= pa && pa <= a+d,
+ "pixel "+pos+" is "+pr+","+pg+","+pb+","+pa+"; expected "+colour+" +/- "+d);
+ }
+
+mochitest.deferTest: |
+ function deferTest() {
+ _deferred = true;
+ }
+
+mochitest.wrapFunction: |
+ function wrapFunction(f) {
+ return function () {
+ f.apply(null, arguments);
+ SimpleTest.finish();
+ }
+ }
+
+mochitest.exception: |
+ var _thrown_outer = false;
+ try {
+
+ %s
+ } catch (e) {
+ _thrown_outer = true;
+ }
+ todo(!_thrown_outer, 'should not throw exception');
+
+mochitest.Makefile: |
+ #
+ # ***** BEGIN LICENSE BLOCK *****
+ # Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ #
+ # The contents of this file are subject to the Mozilla Public License Version
+ # 1.1 (the "License"); you may not use this file except in compliance with
+ # the License. You may obtain a copy of the License at
+ # http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS IS" basis,
+ # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ # for the specific language governing rights and limitations under the
+ # License.
+ #
+ # The Original Code is mozilla.org code.
+ #
+ # The Initial Developer of the Original Code is
+ # Mozilla Corporation.
+ # Portions created by the Initial Developer are Copyright (C) 2007
+ # the Initial Developer. All Rights Reserved.
+ #
+ # Contributor(s):
+ # Philip Taylor
+ #
+ # Alternatively, the contents of this file may be used under the terms of
+ # either of the GNU General Public License Version 2 or later (the "GPL"),
+ # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ # in which case the provisions of the GPL or the LGPL are applicable instead
+ # of those above. If you wish to allow use of your version of this file only
+ # under the terms of either the GPL or the LGPL, and not to allow others to
+ # use your version of this file under the terms of the MPL, indicate your
+ # decision by deleting the provisions above and replace them with the notice
+ # and other provisions required by the GPL or the LGPL. If you do not delete
+ # the provisions above, a recipient may use your version of this file under
+ # the terms of any one of the MPL, the GPL or the LGPL.
+ #
+ # ***** END LICENSE BLOCK *****
+
+ DEPTH = ../../..
+ topsrcdir = @top_srcdir@
+ srcdir = @srcdir@
+ VPATH = @srcdir@
+ relativesrcdir = content/canvas/test
+
+ include $(DEPTH)/config/autoconf.mk
+ include $(topsrcdir)/config/rules.mk
+
+
+index.frame: |
+
+ Canvas tests - %(category)s.*
+
+ [index]
+
%(backrefs)s.*
+
+
+# FF trunk doesn't do onload in object, so use iframe instead
+#index.frame.item: |-
+# (object fallback)
+index.frame.item: |-
+
+
+index.w3c.frame: |
+
+
Canvas tests - %(category)s.*
+
+ [index]
+
%(backrefs)s.*
+
+
+index.w3c.frame.item: |-
+
+
+index: |
+
+
Canvas tests - index
+
+
+
+ <canvas>
tests
+
+ Developed by Philip Taylor .
+ Last updated %(updated)s.
+
+
Based on the HTML
+ Draft Standard — 22 February 2010. See also the annotated specification .
+
+
See test results for some browsers.
+ (Generated semi-automatically via the report generator .)
+
+
You may want to download the source
+ code/data (e.g. to create an offline copy of the tests).
+
+
Test cases
+
+ For each test, a green background indicates success, red indicates
+ failure, blue indicates a need to manually confirm the output is as
+ expected.
+
+
The versions in the report generator are the most visually minimalist.
+ The category links below show the actual and expected renderings, and any
+ error messages. The individual test pages have links to relevant parts of
+ the specification and extra notes.
+
+
There may be many inaccuracies: tests that do not notice when part of
+ the output is incorrect; tests that are too intolerant of acceptable
+ renderings differences, or make other unreasonable assumptions; tests that
+ were written for an outdated version of the specification, and tests that
+ are just wrong. Also a number of features are not tested, most notably text
+ rendering. Please contact me (email , IRC , etc) if you find any
+ problems.
+
+index.w3c: |
+
+
Canvas tests - index
+
+
+ <canvas>
tests
+
+index.category.item: |
+ %d test%s expand
+
+index.w3c.category.item: |
+ %d test%s
+
+reportgen: |
+
+ Canvas tests - report generator
+
+
+ This is mainly for my own use, so it is not designed to be user-friendly.
+ If anyone else wants to use it for some reason, just wait
+ until "tests not yet loaded" and "tests not yet completed" get down to zero, then click the
+ pass/fail button for any test it shows where it cannot work out the answer (or use the
+ y /n keys to choose for the magenta-highlighted case), then use the
+ buttons at the bottom to collect all the results.
+
+
+
+
+results: |
+
+ Canvas tests - results
+
+
+
+
+ Test
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/tests.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/tests.yaml
new file mode 100644
index 00000000000..4a89836c06f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/tests.yaml
@@ -0,0 +1,1031 @@
+# Copyright (c) 2010 Philip Taylor
+# Released under the BSD license and W3C Test Suite License: see LICENSE.txt
+
+- name: fallback.basic
+ desc: Fallback content is inserted into the DOM
+ testing:
+ - fallback
+ code: |
+ @assert canvas.childNodes.length === 1;
+
+- name: fallback.multiple
+ desc: Fallback content with multiple elements
+ testing:
+ - fallback
+ fallback: 'FAIL
FAIL
'
+ code: |
+ @assert canvas.childNodes.length === 2;
+
+- name: fallback.nested
+ desc: Fallback content containing another canvas (mostly testing parsers)
+ testing:
+ - fallback
+ fallback: 'FAIL (fallback content)
FAIL (fallback content)
'
+ code: |
+ @assert canvas.childNodes.length === 2;
+
+- name: type.name
+ desc: HTMLCanvasElement type and toString
+ testing:
+ - canvas.type
+ code: |
+ @assert Object.prototype.toString.call(canvas) === '[object HTMLCanvasElement]';
+
+- name: type.exists
+ desc: HTMLCanvasElement is a property of window
+ notes: &bindings Defined in "Web IDL" (draft)
+ testing:
+ - canvas.type
+ code: |
+ @assert window.HTMLCanvasElement;
+
+- name: type.delete
+ desc: window.HTMLCanvasElement interface object is [[Configurable]]
+ notes: *bindings
+ testing:
+ - canvas.type
+ code: |
+ @assert delete window.HTMLCanvasElement === true;
+ @assert window.HTMLCanvasElement === undefined;
+
+- name: type.prototype
+ desc: window.HTMLCanvasElement has prototype, which is { ReadOnly, DontDelete }. prototype has getContext, which is not
+ notes: *bindings
+ testing:
+ - canvas.type
+ code: |
+ @assert window.HTMLCanvasElement.prototype;
+ @assert window.HTMLCanvasElement.prototype.getContext;
+ window.HTMLCanvasElement.prototype = null;
+ @assert window.HTMLCanvasElement.prototype;
+ delete window.HTMLCanvasElement.prototype;
+ @assert window.HTMLCanvasElement.prototype;
+ window.HTMLCanvasElement.prototype.getContext = 1;
+ @assert window.HTMLCanvasElement.prototype.getContext === 1;
+ delete window.HTMLCanvasElement.prototype.getContext;
+ @assert window.HTMLCanvasElement.prototype.getContext === undefined;
+
+- name: type.replace
+ desc: HTMLCanvasElement methods can be replaced, and the replacement methods used by canvases
+ notes: *bindings
+ testing:
+ - canvas.type
+ code: |
+ window.HTMLCanvasElement.prototype.getContext = function (name) { return 0; };
+ @assert canvas.getContext('2d') === 0;
+
+- name: type.extend
+ desc: HTMLCanvasElement methods can be added, and the new methods used by canvases
+ notes: *bindings
+ testing:
+ - canvas.type
+ code: |
+ window.HTMLCanvasElement.prototype.getZero = function () { return 0; };
+ @assert canvas.getZero() === 0;
+
+
+- name: size.attributes.idl.set.zero
+ desc: Setting width/height IDL attributes to 0
+ testing:
+ - size.width
+ - size.height
+ code: |
+ canvas.width = 0;
+ canvas.height = 0;
+ @assert canvas.width === 0;
+ @assert canvas.height === 0;
+# expected: size 0 0 # can't generate zero-sized PNG
+
+- name: size.attributes.idl
+ desc: Getting/setting width/height IDL attributes
+ testing:
+ - size.width
+ - size.height
+ webidl:
+ - es-unsigned-long
+ code: |
+ canvas.width = "100";
+ canvas.height = "100";
+ @assert canvas.width === 100;
+ @assert canvas.height === 100;
+
+ canvas.width = "+1.5e2";
+ canvas.height = "0x96";
+ @assert canvas.width === 150;
+ @assert canvas.height === 150;
+
+ canvas.width = 200 - Math.pow(2, 32);
+ canvas.height = 200 - Math.pow(2, 32);
+ @assert canvas.width === 200;
+ @assert canvas.height === 200;
+
+ canvas.width = 301.999;
+ canvas.height = 301.001;
+ @assert canvas.width === 301;
+ @assert canvas.height === 301;
+
+ canvas.width = "400x";
+ canvas.height = "foo";
+ @assert canvas.width === 0;
+ @assert canvas.height === 0;
+
+- name: size.attributes.default
+ desc: Default width/height when attributes are missing
+ testing:
+ - size.default
+ - size.missing
+ canvas: ""
+ code: |
+ @assert canvas.width === 300;
+ @assert canvas.height === 150;
+ @assert !canvas.hasAttribute('width');
+ @assert !canvas.hasAttribute('height');
+ expected: size 300 150
+
+- name: size.attributes.reflect.setidl
+ desc: Setting IDL attributes updates IDL and content attributes
+ testing:
+ - size.reflect
+ code: |
+ canvas.width = 120;
+ canvas.height = 60;
+ @assert canvas.getAttribute('width') === '120';
+ @assert canvas.getAttribute('height') === '60';
+ @assert canvas.width === 120;
+ @assert canvas.height === 60;
+ expected: size 120 60
+
+- name: size.attributes.reflect.setidlzero
+ desc: Setting IDL attributes to 0 updates IDL and content attributes
+ testing:
+ - size.reflect
+ code: |
+ canvas.width = 0;
+ canvas.height = 0;
+ @assert canvas.getAttribute('width') === '0';
+ @assert canvas.getAttribute('height') === '0';
+ @assert canvas.width === 0;
+ @assert canvas.height === 0;
+# expected: size 0 0 # can't generate zero-sized PNG
+
+- name: size.attributes.reflect.setcontent
+ desc: Setting content attributes updates IDL and content attributes
+ testing:
+ - size.reflect
+ code: |
+ canvas.setAttribute('width', '120');
+ canvas.setAttribute('height', '60');
+ @assert canvas.getAttribute('width') === '120';
+ @assert canvas.getAttribute('height') === '60';
+ @assert canvas.width === 120;
+ @assert canvas.height === 60;
+ expected: size 120 60
+
+- name: size.attributes.removed
+ desc: Removing content attributes reverts to default size
+ testing:
+ - size.missing
+ canvas: width="120" height="60"
+ code: |
+ @assert canvas.width === 120;
+ canvas.removeAttribute('width');
+ @assert canvas.width === 300;
+ expected: size 300 60
+
+- meta: |
+ cases = [
+ ("zero", "0", 0),
+ ("empty", "", None),
+ ("onlyspace", " ", None),
+ ("space", " 100", 100),
+ ("whitespace", "\n\t\f100", 100),
+ ("plus", "+100", 100),
+ ("minus", "-100", None),
+ ("octal", "0100", 100),
+ ("hex", "0x100", 0),
+ ("exp", "100e1", 100),
+ ("decimal", "100.999", 100),
+ ("percent", "100%", 100),
+ ("em", "100em", 100),
+ ("junk", "#!?", None),
+ ("trailingjunk", "100#!?", 100),
+ ]
+ def gen(name, string, exp, code):
+ testing = ["size.nonnegativeinteger"]
+ if exp is None:
+ testing.append("size.error")
+ code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n"
+ expected = "size 300 150"
+ else:
+ code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp)
+ expected = "size %s %s" % (exp, exp)
+
+ # With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width,
+ # so check the CSS display width
+ code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, )
+
+ code += "@assert canvas.getAttribute('width') === %r;\n" % string
+ code += "@assert canvas.getAttribute('height') === %r;\n" % string
+
+ if exp == 0:
+ expected = None # can't generate zero-sized PNGs for the expected image
+
+ return code, testing, expected
+
+ for name, string, exp in cases:
+ code = ""
+ code, testing, expected = gen(name, string, exp, code)
+ tests.append( {
+ "name": "size.attributes.parse.%s" % name,
+ "desc": "Parsing of non-negative integers",
+ "testing": testing,
+ "canvas": 'width="%s" height="%s"' % (string, string),
+ "code": code,
+ "expected": expected
+ } )
+
+ for name, string, exp in cases:
+ code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string)
+ code, testing, expected = gen(name, string, exp, code)
+ tests.append( {
+ "name": "size.attributes.setAttribute.%s" % name,
+ "desc": "Parsing of non-negative integers in setAttribute",
+ "testing": testing,
+ "canvas": 'width="50" height="50"',
+ "code": code,
+ "expected": expected
+ } )
+
+- name: size.attributes.style
+ desc: Canvas size is independent of CSS resizing
+ testing:
+ - size.css
+ canvas: 'width="50" height="30" style="width: 100px; height: 50px"'
+ code: |
+ @assert canvas.width === 50;
+ @assert canvas.height === 30;
+ expected: size 100 50
+
+- name: size.large
+ DISABLED: |
+ "User agents may impose implementation-specific limits on otherwise unconstrained
+ inputs, e.g. to prevent denial of service attacks, to guard against running out of memory,
+ or to work around platform-specific limitations."
+ testing:
+ - size.width
+ - size.height
+ notes: Not sure how reasonable this is, but the spec doesn't say there's an upper limit on the size.
+ code: |
+ var n = 2147483647; // 2^31 - 1, which should be supported by any sensible definition of "long"
+ canvas.width = n;
+ canvas.height = n;
+ @assert canvas.width === n;
+ @assert canvas.height === n;
+# expected: size 2147483647 2147483647 # not a good idea to generate the expected image in this case...
+
+- name: initial.colour
+ desc: Initial state is transparent black
+ testing:
+ - initial.colour
+ notes: |
+ Output should be transparent black (not transparent anything-else), but manual
+ verification can only confirm that it's transparent - it's not possible to make
+ the actual blackness visible.
+ code: |
+ @assert pixel 20,20 == 0,0,0,0;
+ expected: size 100 50 # transparent
+
+- name: initial.reset.different
+ desc: Changing size resets canvas to transparent black
+ testing:
+ - initial.reset
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ @assert pixel 20,20 == 255,0,0,255;
+ canvas.width = 50;
+ @assert pixel 20,20 == 0,0,0,0;
+ expected: size 50 50 # transparent
+
+- name: initial.reset.same
+ desc: Setting size (not changing the value) resets canvas to transparent black
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 100;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ @assert pixel 20,20 == 255,0,0,255;
+ canvas.width = 100;
+ @assert pixel 20,20 == 0,0,0,0;
+ expected: size 100 50 # transparent
+
+- name: initial.reset.path
+ desc: Resetting the canvas state resets the current path
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 100;
+ ctx.rect(0, 0, 100, 50);
+ canvas.width = 100;
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ @assert pixel 20,20 == 0,0,0,0;
+ expected: size 100 50 # transparent
+
+- name: initial.reset.clip
+ desc: Resetting the canvas state resets the current clip region
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 100;
+ ctx.rect(0, 0, 1, 1);
+ ctx.clip();
+ canvas.width = 100;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 20,20 == 0,255,0,255;
+ expected: green
+
+- name: initial.reset.transform
+ desc: Resetting the canvas state resets the current transformation matrix
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 100;
+ ctx.scale(0.1, 0.1);
+ canvas.width = 100;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 20,20 == 0,255,0,255;
+ expected: green
+
+- name: initial.reset.gradient
+ desc: Resetting the canvas state does not invalidate any existing gradients
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 50;
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#0f0');
+ canvas.width = 100;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: initial.reset.pattern
+ desc: Resetting the canvas state does not invalidate any existing patterns
+ testing:
+ - initial.reset
+ code: |
+ canvas.width = 30;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 30, 50);
+ var p = ctx.createPattern(canvas, 'repeat-x');
+ canvas.width = 100;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = p;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+# See tests2d.yaml for initial.reset.2dstate
+
+
+- name: context.emptystring
+ desc: getContext with empty string returns null
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext("") === null;
+
+- name: context.unrecognised.badname
+ desc: getContext with unrecognised context name returns null
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext('This is not an implemented context in any real browser') === null;
+
+- name: context.unrecognised.badsuffix
+ desc: Context name "2d" plus a suffix is unrecognised
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext("2d#") === null;
+
+- name: context.unrecognised.nullsuffix
+ desc: Context name "2d" plus a "\0" suffix is unrecognised
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext("2d\0") === null;
+
+- name: context.unrecognised.unicode
+ desc: Context name which kind of looks like "2d" is unrecognised
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext("2\uFF44") === null; // Fullwidth Latin Small Letter D
+
+- name: context.casesensitive
+ desc: Context name "2D" is unrecognised; matching is case sensitive
+ testing:
+ - context.unrecognised
+ code: |
+ @assert canvas.getContext('2D') === null;
+
+- name: context.arguments.missing
+ notes: *bindings
+ testing:
+ - canvas.getContext
+ code: |
+ @assert throws TypeError canvas.getContext(); @moz-todo
+
+
+
+
+- name: toDataURL.default
+ desc: toDataURL with no arguments returns a PNG
+ testing:
+ - toDataURL.noarguments
+ code: |
+ var data = canvas.toDataURL();
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.png
+ desc: toDataURL with image/png returns a PNG
+ testing:
+ - toDataURL.png
+ - toDataURL.witharguments
+ code: |
+ var data = canvas.toDataURL('image/png');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.bogustype
+ desc: toDataURL with a syntactically invalid type returns a PNG
+ testing:
+ - toDataURL.unrecognised
+ code: |
+ var data = canvas.toDataURL('bogus');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.unrecognised
+ desc: toDataURL with an unhandled type returns a PNG
+ testing:
+ - toDataURL.unrecognised
+ code: |
+ var data = canvas.toDataURL('image/example');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.lowercase.ascii
+ desc: toDataURL type is case-insensitive
+ testing:
+ - toDataURL.lowercase
+ code: |
+ var data = canvas.toDataURL('ImAgE/PnG');
+ @assert data =~ /^data:image\/png[;,]/;
+
+ // If JPEG is supported at all, it must be supported case-insensitively
+ data = canvas.toDataURL('image/jpeg');
+ if (data.match(/^data:image\/jpeg[;,]/)) {
+ data = canvas.toDataURL('ImAgE/JpEg');
+ @assert data =~ /^data:image\/jpeg[;,]/;
+ }
+
+- name: toDataURL.lowercase.unicode
+ desc: toDataURL type is ASCII-case-insensitive
+ testing:
+ - toDataURL.lowercase
+ code: |
+ // Use LATIN CAPITAL LETTER I WITH DOT ABOVE (Unicode lowercase is "i")
+ var data = canvas.toDataURL('\u0130mage/png');
+ @assert data =~ /^data:image\/png[;,]/;
+
+ var data = canvas.toDataURL('\u0130mage/jpeg');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.arguments.1
+ desc: toDataURL ignores extra arguments
+ testing:
+ - toDataURL.arguments
+ code: |
+ var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.arguments.2
+ desc: toDataURL ignores extra arguments
+ testing:
+ - toDataURL.arguments
+ code: |
+ var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception', 'and another');
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.arguments.3
+ desc: toDataURL ignores extra arguments
+ testing:
+ - toDataURL.arguments
+ code: |
+ // More arguments that should not raise exceptions
+ var data = canvas.toDataURL('image/png', null, null, null);
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.nocontext
+ desc: toDataURL works before any context has been got
+ testing:
+ - toDataURL.noarguments
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var data = canvas2.toDataURL();
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.zerosize
+ desc: toDataURL on zero-size canvas returns 'data:,'
+ testing:
+ - toDataURL.zerosize
+ canvas: width="0" height="0"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data === 'data:,';
+
+- name: toDataURL.zerowidth
+ desc: toDataURL on zero-size canvas returns 'data:,'
+ testing:
+ - toDataURL.zerosize
+ canvas: width="0"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data === 'data:,';
+
+- name: toDataURL.zeroheight
+ desc: toDataURL on zero-size canvas returns 'data:,'
+ testing:
+ - toDataURL.zerosize
+ canvas: height="0"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data === 'data:,';
+
+- name: toDataURL.large1
+ DISABLED: just testing implementation limits, and tends to crash
+ canvas: width="30000" height="1"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.large2
+ DISABLED: just testing implementation limits, and tends to crash
+ canvas: width="32767" height="1"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.large3
+ DISABLED: just testing implementation limits, and tends to crash
+ canvas: width="32768" height="1"
+ code: |
+ var data = canvas.toDataURL();
+ @assert data =~ /^data:image\/png[;,]/;
+
+- name: toDataURL.png.primarycolours
+ desc: toDataURL with PNG handles simple colours correctly
+ testing:
+ - toDataURL.png
+ code: |
+ ctx.fillStyle = '#ff0';
+ ctx.fillRect(0, 0, 25, 40);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(25, 0, 50, 40);
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(75, 0, 25, 40);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 40, 100, 10);
+ var data = canvas.toDataURL();
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 12,20 == 255,255,0,255;
+ @assert pixel 50,20 == 0,255,255,255;
+ @assert pixel 87,20 == 0,0,255,255;
+ @assert pixel 50,45 == 255,255,255,255;
+ });
+ img.src = data;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(1, 1, 0)
+ cr.rectangle(0, 0, 25, 40)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 1)
+ cr.rectangle(25, 0, 50, 40)
+ cr.fill()
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(75, 0, 25, 40)
+ cr.fill()
+ cr.set_source_rgb(1, 1, 1)
+ cr.rectangle(0, 40, 100, 10)
+ cr.fill()
+
+- name: toDataURL.png.complexcolours
+ desc: toDataURL with PNG handles non-primary and non-solid colours correctly
+ testing:
+ - toDataURL.png
+ code: |
+ // (These values are chosen to survive relatively alright through being premultiplied)
+ ctx.fillStyle = 'rgba(1, 3, 254, 1)';
+ ctx.fillRect(0, 0, 25, 25);
+ ctx.fillStyle = 'rgba(8, 252, 248, 0.75)';
+ ctx.fillRect(25, 0, 25, 25);
+ ctx.fillStyle = 'rgba(6, 10, 250, 0.502)';
+ ctx.fillRect(50, 0, 25, 25);
+ ctx.fillStyle = 'rgba(12, 16, 244, 0.25)';
+ ctx.fillRect(75, 0, 25, 25);
+ var img = new Image();
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img, 0, 25);
+ // (The alpha values do not really survive float->int conversion, so just
+ // do approximate comparisons)
+ @assert pixel 12,40 == 1,3,254,255;
+ @assert pixel 37,40 ==~ 8,252,248,191 +/- 2;
+ @assert pixel 62,40 ==~ 6,10,250,127 +/- 4;
+ @assert pixel 87,40 ==~ 12,16,244,63 +/- 8;
+ });
+ img.src = canvas.toDataURL();
+ expected: |
+ size 100 50
+ cr.set_source_rgba(1/255., 3/255., 254/255., 1)
+ cr.rectangle(0, 0, 25, 50)
+ cr.fill()
+ cr.set_source_rgba(8/255., 252/255., 248/255., 191/255.)
+ cr.rectangle(25, 0, 25, 50)
+ cr.fill()
+ cr.set_source_rgba(6/255., 10/255., 250/255., 127/255.)
+ cr.rectangle(50, 0, 25, 50)
+ cr.fill()
+ cr.set_source_rgba(12/255., 16/255., 244/255., 63/255.)
+ cr.rectangle(75, 0, 25, 50)
+ cr.fill()
+
+- name: toDataURL.jpeg.primarycolours
+ desc: toDataURL with JPEG handles simple colours correctly
+ testing:
+ - toDataURL.jpeg
+ code: |
+ ctx.fillStyle = '#ff0';
+ ctx.fillRect(0, 0, 25, 40);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(25, 0, 50, 40);
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(75, 0, 25, 40);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 40, 100, 10);
+ var data = canvas.toDataURL('image/jpeg'); // it is okay if this returns a PNG instead
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 12,20 ==~ 255,255,0,255 +/- 8;
+ @assert pixel 50,20 ==~ 0,255,255,255 +/- 8;
+ @assert pixel 87,20 ==~ 0,0,255,255 +/- 8;
+ @assert pixel 50,45 ==~ 255,255,255,255 +/- 8;
+ });
+ img.src = data;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(1, 1, 0)
+ cr.rectangle(0, 0, 25, 40)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 1)
+ cr.rectangle(25, 0, 50, 40)
+ cr.fill()
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(75, 0, 25, 40)
+ cr.fill()
+ cr.set_source_rgb(1, 1, 1)
+ cr.rectangle(0, 40, 100, 10)
+ cr.fill()
+
+- name: toDataURL.jpeg.alpha
+ desc: toDataURL with JPEG composites onto black
+ testing:
+ - toDataURL.jpeg
+ - toDataURL.noalpha
+ code: |
+ ctx.fillStyle = 'rgba(128, 255, 128, 0.5)';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'destination-over'; // should be ignored by toDataURL
+ var data = canvas.toDataURL('image/jpeg');
+ ctx.globalCompositeOperation = 'source-over';
+ if (!data.match(/^data:image\/jpeg[;,]/)) {
+ @assert true;
+ } else {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 63,127,63,255 +/- 8;
+ });
+ img.src = data;
+ }
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.25, 0.5, 0.25)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: toDataURL.jpeg.quality.basic
+ desc: toDataURL with JPEG uses the quality parameter
+ testing:
+ - toDataURL.jpeg.quality
+ mozilla: { throws }
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(0, 3, 100, 1);
+ // Check for JPEG support first
+ var data = canvas.toDataURL('image/jpeg');
+ if (!data.match(/^data:image\/jpeg[;,]/)) {
+ @assert true;
+ } else {
+ var data_hi = canvas.toDataURL('image/jpeg', 0.99);
+ var data_lo = canvas.toDataURL('image/jpeg', 0.01);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ deferTest();
+ var img_hi = new Image();
+ img_hi.onload = function ()
+ {
+ var img_lo = new Image();
+ img_lo.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img_hi, 0, 0, 50, 50, 0, 0, 50, 50);
+ ctx.drawImage(img_lo, 0, 0, 50, 50, 50, 0, 50, 50);
+ @assert data_hi.length > data_lo.length;
+ @assert pixel 25,25 ==~ 0,0,255,255 +/- 8;
+ @assert pixel 75,25 ==~ 0,0,255,255 +/- 32;
+ });
+ img_lo.src = data_lo;
+ };
+ img_hi.src = data_hi;
+ }
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 1)
+ cr.rectangle(0, 3, 100, 1)
+ cr.fill()
+
+- name: toDataURL.jpeg.quality.notnumber
+ desc: toDataURL with JPEG handles non-numeric quality parameters
+ testing:
+ - toDataURL.jpeg.nan
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(0, 3, 100, 1);
+ // Check for JPEG support first
+ var data = canvas.toDataURL('image/jpeg');
+ if (!data.match(/^data:image\/jpeg[;,]/)) {
+ @assert true;
+ } else {
+ @assert canvas.toDataURL('image/jpeg', 'bogus') === data;
+ @assert canvas.toDataURL('image/jpeg', {}) === data;
+ @assert canvas.toDataURL('image/jpeg', null) === data;
+ @assert canvas.toDataURL('image/jpeg', undefined) === data;
+ @assert canvas.toDataURL('image/jpeg', true) === data;
+ @assert canvas.toDataURL('image/jpeg', '0.01') === data;
+ }
+
+- name: toDataURL.jpeg.quality.outsiderange
+ desc: toDataURL with JPEG handles out-of-range quality parameters
+ testing:
+ - toDataURL.jpeg.range
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(0, 3, 100, 1);
+ // Check for JPEG support first
+ var data = canvas.toDataURL('image/jpeg');
+ if (!data.match(/^data:image\/jpeg[;,]/)) {
+ @assert true;
+ } else {
+ @assert canvas.toDataURL('image/jpeg', 10) === data;
+ @assert canvas.toDataURL('image/jpeg', -10) === data;
+ @assert canvas.toDataURL('image/jpeg', 1.01) === data;
+ @assert canvas.toDataURL('image/jpeg', -0.01) === data;
+
+ @assert canvas.toDataURL('image/jpeg', 1).length >= canvas.toDataURL('image/jpeg', 0.9).length;
+ @assert canvas.toDataURL('image/jpeg', 0).length <= canvas.toDataURL('image/jpeg', 0.1).length;
+ }
+
+
+# TODO: work out what security exception should be thrown
+# TODO: test same-origin vs same-host
+
+- name: security.drawImage.image.sub
+ desc: drawImage of different-origin image makes the canvas origin-unclean
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.drawImage.image
+ - security.toDataURL
+ - security.getImageData
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.drawImage.canvas.sub
+ desc: drawImage of unclean canvas makes the canvas origin-unclean
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.drawImage.canvas
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+ ctx.drawImage(canvas2, 0, 0);
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.pattern.create.sub
+ desc: Creating an unclean pattern does not make the canvas origin-unclean
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.start
+ images:
+ - http://{{domains[www]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ canvas.toDataURL();
+ ctx.getImageData(0, 0, 1, 1);
+ @assert true; // okay if there was no exception
+
+- name: security.pattern.cross.sub
+ desc: Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.start
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ var p = ctx2.createPattern(document.getElementById('yellow.png'), 'repeat');
+ ctx.fillStyle = p;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+ canvas2.toDataURL();
+ ctx2.getImageData(0, 0, 1, 1);
+
+- name: security.pattern.canvas.timing.sub
+ desc: Pattern safety depends on whether the source was origin-clean, not on whether it still is clean
+ notes: Disagrees with spec on "is" vs "was"
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.start
+ - security.fillStyle.canvas
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50);
+ var p = ctx.createPattern(canvas2, 'repeat');
+ ctx2.drawImage(document.getElementById('yellow.png'), 0, 0); // make canvas2 origin-unclean
+ ctx.fillStyle = p;
+ ctx.fillRect(0, 0, 100, 50);
+ canvas.toDataURL();
+ ctx.getImageData(0, 0, 1, 1);
+ @assert true; // okay if there was no exception
+
+- name: security.pattern.image.fillStyle.sub
+ desc: Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.fillStyle.image
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ ctx.fillStyle = p;
+ ctx.fillStyle = 'red';
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.pattern.canvas.fillStyle.sub
+ desc: Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean
+ mozilla: { bug: 354127, disabled } # relies on external resources
+ testing:
+ - security.fillStyle.canvas
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+ var p = ctx.createPattern(canvas2, 'repeat');
+ ctx.fillStyle = p;
+ ctx.fillStyle = 'red';
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.pattern.image.strokeStyle.sub
+ desc: Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - security.strokeStyle.image
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ ctx.strokeStyle = p;
+ ctx.strokeStyle = 'red';
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.pattern.canvas.strokeStyle.sub
+ desc: Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean
+ mozilla: { bug: 354127, disabled } # relies on external resources
+ testing:
+ - security.strokeStyle.canvas
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+ var p = ctx.createPattern(canvas2, 'repeat');
+ ctx.strokeStyle = p;
+ ctx.strokeStyle = 'red';
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ @assert throws SECURITY_ERR ctx.getImageData(0, 0, 1, 1);
+
+- name: security.dataURI
+ desc: 'data: URIs do not count as different-origin, and do not taint the canvas'
+ mozilla: { disabled, bug: 417836 } # can't do "todo" so just disable it
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var data = canvas.toDataURL();
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.drawImage(img, 0, 0);
+ canvas.toDataURL(); // should be permitted
+ @assert pixel 50,25 == 0,255,0,255;
+ });
+ img.src = data;
+ expected: green
+
+- name: security.reset.sub
+ desc: Resetting the canvas state does not reset the origin-clean flag
+ mozilla: { disabled } # relies on external resources
+ testing:
+ - initial.reset
+ images:
+ - http://{{domains[www2]}}:{{ports[http][0]}}/images/yellow.png
+ code: |
+ canvas.width = 50;
+ ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+ @assert throws SECURITY_ERR canvas.toDataURL();
+ canvas.width = 100;
+ @assert throws SECURITY_ERR canvas.toDataURL();
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml
new file mode 100644
index 00000000000..2c8dc3078eb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml
@@ -0,0 +1,10030 @@
+# Copyright (c) 2011 Philip Taylor
+# Released under the BSD license and W3C Test Suite License: see LICENSE.txt
+
+- name: 2d.getcontext.exists
+ desc: The 2D context is implemented
+ testing:
+ - context.2d
+ code: |
+ @assert canvas.getContext('2d') !== null;
+
+- name: 2d.getcontext.extraargs
+ desc: The 2D context ignores extra getContext arguments
+ testing:
+ - context.2d.extraargs
+ code: |
+ @assert canvas.getContext('2d', false, {}, [], 1, "2") !== null;
+
+- name: 2d.type.exists
+ desc: The 2D context interface is a property of 'window'
+ notes: &bindings Defined in "Web IDL" (draft)
+ testing:
+ - context.2d.type
+ code: |
+ @assert window.CanvasRenderingContext2D;
+
+- name: 2d.type.delete
+ desc: window.CanvasRenderingContext2D is Configurable
+ notes: *bindings
+ testing:
+ - context.2d.type
+ code: |
+ @assert window.CanvasRenderingContext2D !== undefined;
+ @assert delete window.CanvasRenderingContext2D === true;
+ @assert window.CanvasRenderingContext2D === undefined;
+
+- name: 2d.type.prototype
+ desc: window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]], and its methods are [[Configurable]].
+ notes: *bindings
+ testing:
+ - context.2d.type
+ code: |
+ @assert window.CanvasRenderingContext2D.prototype;
+ @assert window.CanvasRenderingContext2D.prototype.fill;
+ window.CanvasRenderingContext2D.prototype = null;
+ @assert window.CanvasRenderingContext2D.prototype;
+ delete window.CanvasRenderingContext2D.prototype;
+ @assert window.CanvasRenderingContext2D.prototype;
+ window.CanvasRenderingContext2D.prototype.fill = 1;
+ @assert window.CanvasRenderingContext2D.prototype.fill === 1;
+ delete window.CanvasRenderingContext2D.prototype.fill;
+ @assert window.CanvasRenderingContext2D.prototype.fill === undefined;
+
+- name: 2d.type.replace
+ desc: Interface methods can be overridden
+ notes: *bindings
+ testing:
+ - context.2d.type
+ code: |
+ var fillRect = window.CanvasRenderingContext2D.prototype.fillRect;
+ window.CanvasRenderingContext2D.prototype.fillRect = function (x, y, w, h)
+ {
+ this.fillStyle = '#0f0';
+ fillRect.call(this, x, y, w, h);
+ };
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.type.extend
+ desc: Interface methods can be added
+ notes: *bindings
+ testing:
+ - context.2d.type
+ code: |
+ window.CanvasRenderingContext2D.prototype.fillRectGreen = function (x, y, w, h)
+ {
+ this.fillStyle = '#0f0';
+ this.fillRect(x, y, w, h);
+ };
+ ctx.fillStyle = '#f00';
+ ctx.fillRectGreen(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.getcontext.unique
+ desc: getContext('2d') returns the same object
+ testing:
+ - context.unique
+ code: |
+ @assert canvas.getContext('2d') === canvas.getContext('2d');
+
+- name: 2d.getcontext.shared
+ desc: getContext('2d') returns objects which share canvas state
+ testing:
+ - context.unique
+ code: |
+ var ctx2 = canvas.getContext('2d');
+ ctx.fillStyle = '#f00';
+ ctx2.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.voidreturn
+ desc: void methods return undefined
+ notes: *bindings
+ images:
+ - yellow.png
+ code: |
+ @assert ctx.save() === undefined;
+ @assert ctx.restore() === undefined;
+ @assert ctx.scale(1, 1) === undefined;
+ @assert ctx.rotate(0) === undefined;
+ @assert ctx.translate(0, 0) === undefined;
+ if (ctx.transform) { // (avoid spurious failures, since the aim here is not to test that all features are supported)
+ @assert ctx.transform(1, 0, 0, 1, 0, 0) === undefined;
+ }
+ if (ctx.setTransform) {
+ @assert ctx.setTransform(1, 0, 0, 1, 0, 0) === undefined;
+ }
+ @assert ctx.clearRect(0, 0, 0, 0) === undefined;
+ @assert ctx.fillRect(0, 0, 0, 0) === undefined;
+ @assert ctx.strokeRect(0, 0, 0, 0) === undefined;
+ @assert ctx.beginPath() === undefined;
+ @assert ctx.closePath() === undefined;
+ @assert ctx.moveTo(0, 0) === undefined;
+ @assert ctx.lineTo(0, 0) === undefined;
+ @assert ctx.quadraticCurveTo(0, 0, 0, 0) === undefined;
+ @assert ctx.bezierCurveTo(0, 0, 0, 0, 0, 0) === undefined;
+ @assert ctx.arcTo(0, 0, 0, 0, 1) === undefined;
+ @assert ctx.rect(0, 0, 0, 0) === undefined;
+ @assert ctx.arc(0, 0, 1, 0, 0, true) === undefined;
+ @assert ctx.fill() === undefined;
+ @assert ctx.stroke() === undefined;
+ @assert ctx.clip() === undefined;
+ if (ctx.fillText) {
+ @assert ctx.fillText('test', 0, 0) === undefined;
+ @assert ctx.strokeText('test', 0, 0) === undefined;
+ }
+ if (ctx.putImageData) {
+ @assert ctx.putImageData(ctx.getImageData(0, 0, 1, 1), 0, 0) === undefined;
+ }
+ @assert ctx.drawImage(document.getElementById('yellow.png'), 0, 0, 1, 1, 0, 0, 0, 0) === undefined;
+ @assert ctx.drawImage(canvas, 0, 0, 1, 1, 0, 0, 0, 0) === undefined;
+ @assert ctx.createLinearGradient(0, 0, 0, 0).addColorStop(0, 'white') === undefined;
+
+- name: 2d.missingargs
+ desc: Missing arguments cause TypeError
+ code: |
+ @assert throws TypeError ctx.scale();
+ @assert throws TypeError ctx.scale(1);
+ @assert throws TypeError ctx.rotate();
+ @assert throws TypeError ctx.translate();
+ @assert throws TypeError ctx.translate(0);
+ if (ctx.transform) { // (avoid spurious failures, since the aim here is not to test that all features are supported)
+ @assert throws TypeError ctx.transform();
+ @assert throws TypeError ctx.transform(1);
+ @assert throws TypeError ctx.transform(1, 0);
+ @assert throws TypeError ctx.transform(1, 0, 0);
+ @assert throws TypeError ctx.transform(1, 0, 0, 1);
+ @assert throws TypeError ctx.transform(1, 0, 0, 1, 0);
+ }
+ if (ctx.setTransform) {
+ @assert throws TypeError ctx.setTransform();
+ @assert throws TypeError ctx.setTransform(1);
+ @assert throws TypeError ctx.setTransform(1, 0);
+ @assert throws TypeError ctx.setTransform(1, 0, 0);
+ @assert throws TypeError ctx.setTransform(1, 0, 0, 1);
+ @assert throws TypeError ctx.setTransform(1, 0, 0, 1, 0);
+ }
+ @assert throws TypeError ctx.createLinearGradient();
+ @assert throws TypeError ctx.createLinearGradient(0);
+ @assert throws TypeError ctx.createLinearGradient(0, 0);
+ @assert throws TypeError ctx.createLinearGradient(0, 0, 1);
+ @assert throws TypeError ctx.createRadialGradient();
+ @assert throws TypeError ctx.createRadialGradient(0);
+ @assert throws TypeError ctx.createRadialGradient(0, 0);
+ @assert throws TypeError ctx.createRadialGradient(0, 0, 1);
+ @assert throws TypeError ctx.createRadialGradient(0, 0, 1, 0);
+ @assert throws TypeError ctx.createRadialGradient(0, 0, 1, 0, 0);
+ @assert throws TypeError ctx.createPattern(canvas);
+ @assert throws TypeError ctx.clearRect();
+ @assert throws TypeError ctx.clearRect(0);
+ @assert throws TypeError ctx.clearRect(0, 0);
+ @assert throws TypeError ctx.clearRect(0, 0, 0);
+ @assert throws TypeError ctx.fillRect();
+ @assert throws TypeError ctx.fillRect(0);
+ @assert throws TypeError ctx.fillRect(0, 0);
+ @assert throws TypeError ctx.fillRect(0, 0, 0);
+ @assert throws TypeError ctx.strokeRect();
+ @assert throws TypeError ctx.strokeRect(0);
+ @assert throws TypeError ctx.strokeRect(0, 0);
+ @assert throws TypeError ctx.strokeRect(0, 0, 0);
+ @assert throws TypeError ctx.moveTo();
+ @assert throws TypeError ctx.moveTo(0);
+ @assert throws TypeError ctx.lineTo();
+ @assert throws TypeError ctx.lineTo(0);
+ @assert throws TypeError ctx.quadraticCurveTo();
+ @assert throws TypeError ctx.quadraticCurveTo(0);
+ @assert throws TypeError ctx.quadraticCurveTo(0, 0);
+ @assert throws TypeError ctx.quadraticCurveTo(0, 0, 0);
+ @assert throws TypeError ctx.bezierCurveTo();
+ @assert throws TypeError ctx.bezierCurveTo(0);
+ @assert throws TypeError ctx.bezierCurveTo(0, 0);
+ @assert throws TypeError ctx.bezierCurveTo(0, 0, 0);
+ @assert throws TypeError ctx.bezierCurveTo(0, 0, 0, 0);
+ @assert throws TypeError ctx.bezierCurveTo(0, 0, 0, 0, 0);
+ @assert throws TypeError ctx.arcTo();
+ @assert throws TypeError ctx.arcTo(0);
+ @assert throws TypeError ctx.arcTo(0, 0);
+ @assert throws TypeError ctx.arcTo(0, 0, 0);
+ @assert throws TypeError ctx.arcTo(0, 0, 0, 0);
+ @assert throws TypeError ctx.rect();
+ @assert throws TypeError ctx.rect(0);
+ @assert throws TypeError ctx.rect(0, 0);
+ @assert throws TypeError ctx.rect(0, 0, 0);
+ @assert throws TypeError ctx.arc();
+ @assert throws TypeError ctx.arc(0);
+ @assert throws TypeError ctx.arc(0, 0);
+ @assert throws TypeError ctx.arc(0, 0, 1);
+ @assert throws TypeError ctx.arc(0, 0, 1, 0);
+ // (6th argument to arc is optional)
+ if (ctx.isPointInPath) {
+ @assert throws TypeError ctx.isPointInPath();
+ @assert throws TypeError ctx.isPointInPath(0);
+ }
+ if (ctx.drawFocusRing) {
+ @assert throws TypeError ctx.drawFocusRing();
+ @assert throws TypeError ctx.drawFocusRing(canvas);
+ @assert throws TypeError ctx.drawFocusRing(canvas, 0);
+ }
+ if (ctx.fillText) {
+ @assert throws TypeError ctx.fillText();
+ @assert throws TypeError ctx.fillText('test');
+ @assert throws TypeError ctx.fillText('test', 0);
+ @assert throws TypeError ctx.strokeText();
+ @assert throws TypeError ctx.strokeText('test');
+ @assert throws TypeError ctx.strokeText('test', 0);
+ @assert throws TypeError ctx.measureText();
+ }
+ @assert throws TypeError ctx.drawImage();
+ @assert throws TypeError ctx.drawImage(canvas);
+ @assert throws TypeError ctx.drawImage(canvas, 0);
+ // TODO: n >= 3 args on drawImage could be either a valid overload,
+ // or too few for another overload, or too many for another
+ // overload - what should happen?
+ if (ctx.createImageData) {
+ @assert throws TypeError ctx.createImageData();
+ @assert throws TypeError ctx.createImageData(1);
+ }
+ if (ctx.getImageData) {
+ @assert throws TypeError ctx.getImageData();
+ @assert throws TypeError ctx.getImageData(0);
+ @assert throws TypeError ctx.getImageData(0, 0);
+ @assert throws TypeError ctx.getImageData(0, 0, 1);
+ }
+ if (ctx.putImageData) {
+ var imgdata = ctx.getImageData(0, 0, 1, 1);
+ @assert throws TypeError ctx.putImageData();
+ @assert throws TypeError ctx.putImageData(imgdata);
+ @assert throws TypeError ctx.putImageData(imgdata, 0);
+ }
+ var g = ctx.createLinearGradient(0, 0, 0, 0);
+ @assert throws TypeError g.addColorStop(); @moz-todo
+ @assert throws TypeError g.addColorStop(0); @moz-todo
+
+- name: 2d.coordinatespace
+ desc: Coordinate space goes from top-left to bottom-right
+ notes: This should not be upside down.
+ manual: We can't tell that getPixelData isn't using the wrong coordinate space too.
+ testing:
+ - 2d.coordinatespace
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(0, 0, 50, 25);
+ @assert pixel 25,12 == 0,255,255,255;
+ @assert pixel 75,12 == 0,0,255,255;
+ @assert pixel 25,37 == 0,0,255,255;
+ @assert pixel 75,37 == 0,0,255,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 1)
+ cr.rectangle(0, 0, 50, 25)
+ cr.fill()
+
+- name: 2d.scaled
+ desc: CSS-scaled canvases get drawn correctly
+ canvas: 'width="50" height="25" style="width: 100px; height: 50px"'
+ manual:
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 50, 25);
+ ctx.fillStyle = '#0ff';
+ ctx.fillRect(0, 0, 25, 10);
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 1)
+ cr.rectangle(0, 0, 50, 20)
+ cr.fill()
+
+- name: 2d.canvas.reference
+ desc: CanvasRenderingContext2D.canvas refers back to its canvas
+ testing:
+ - 2d.canvas
+ code: |
+ @assert ctx.canvas === canvas;
+
+- name: 2d.canvas.readonly
+ desc: CanvasRenderingContext2D.canvas is readonly
+ testing:
+ - 2d.canvas.attribute
+ code: |
+ var c = document.createElement('canvas');
+ var d = ctx.canvas;
+ @assert c !== d;
+ ctx.canvas = c;
+ @assert ctx.canvas === d;
+
+- meta: |
+ state = [ # some non-default values to test with
+ ('strokeStyle', '"#ff0000"'),
+ ('fillStyle', '"#ff0000"'),
+ ('globalAlpha', 0.5),
+ ('lineWidth', 0.5),
+ ('lineCap', '"round"'),
+ ('lineJoin', '"round"'),
+ ('miterLimit', 0.5),
+ ('shadowOffsetX', 5),
+ ('shadowOffsetY', 5),
+ ('shadowBlur', 5),
+ ('shadowColor', '"#ff0000"'),
+ ('globalCompositeOperation', '"copy"'),
+ ('font', '"25px serif"'),
+ ('textAlign', '"center"'),
+ ('textBaseline', '"bottom"'),
+ ]
+ for key,value in state:
+ tests.append( {
+ 'name': '2d.state.saverestore.%s' % key,
+ 'desc': 'save()/restore() works for %s' % key,
+ 'testing': [ '2d.state.%s' % key ],
+ 'code':
+ """// Test that restore() undoes any modifications
+ var old = ctx.%(key)s;
+ ctx.save();
+ ctx.%(key)s = %(value)s;
+ ctx.restore();
+ @assert ctx.%(key)s === old;
+
+ // Also test that save() doesn't modify the values
+ ctx.%(key)s = %(value)s;
+ old = ctx.%(key)s;
+ // we're not interested in failures caused by get(set(x)) != x (e.g.
+ // from rounding), so compare against 'old' instead of against %(value)s
+ ctx.save();
+ @assert ctx.%(key)s === old;
+ ctx.restore();
+ """ % { 'key':key, 'value':value }
+ } )
+
+ tests.append( {
+ 'name': 'initial.reset.2dstate',
+ 'desc': 'Resetting the canvas state resets 2D state variables',
+ 'testing': [ 'initial.reset' ],
+ 'code':
+ """canvas.width = 100;
+ var default_val;
+ """ + "".join(
+ """
+ default_val = ctx.%(key)s;
+ ctx.%(key)s = %(value)s;
+ canvas.width = 100;
+ @assert ctx.%(key)s === default_val;
+ """ % { 'key':key, 'value':value }
+ for key,value in state),
+ } )
+
+- name: 2d.state.saverestore.transformation
+ desc: save()/restore() affects the current transformation matrix
+ testing:
+ - 2d.state.transformation
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.save();
+ ctx.translate(200, 0);
+ ctx.restore();
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(-200, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.state.saverestore.clip
+ desc: save()/restore() affects the clipping path
+ testing:
+ - 2d.state.clip
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.save();
+ ctx.rect(0, 0, 1, 1);
+ ctx.clip();
+ ctx.restore();
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.state.saverestore.path
+ desc: save()/restore() does not affect the current path
+ testing:
+ - 2d.state.path
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.save();
+ ctx.rect(0, 0, 100, 50);
+ ctx.restore();
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.state.saverestore.bitmap
+ desc: save()/restore() does not affect the current bitmap
+ testing:
+ - 2d.state.bitmap
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.save();
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.restore();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.state.saverestore.stack
+ desc: save()/restore() can be nested as a stack
+ testing:
+ - 2d.state.save
+ - 2d.state.restore
+ code: |
+ ctx.lineWidth = 1;
+ ctx.save();
+ ctx.lineWidth = 2;
+ ctx.save();
+ ctx.lineWidth = 3;
+ @assert ctx.lineWidth === 3;
+ ctx.restore();
+ @assert ctx.lineWidth === 2;
+ ctx.restore();
+ @assert ctx.lineWidth === 1;
+
+- name: 2d.state.saverestore.stackdepth
+ desc: save()/restore() stack depth is not unreasonably limited
+ testing:
+ - 2d.state.save
+ - 2d.state.restore
+ code: |
+ var limit = 512;
+ for (var i = 1; i < limit; ++i)
+ {
+ ctx.save();
+ ctx.lineWidth = i;
+ }
+ for (var i = limit-1; i > 0; --i)
+ {
+ @assert ctx.lineWidth === i;
+ ctx.restore();
+ }
+
+- name: 2d.state.saverestore.underflow
+ desc: restore() with an empty stack has no effect
+ testing:
+ - 2d.state.restore.underflow
+ code: |
+ for (var i = 0; i < 16; ++i)
+ ctx.restore();
+ ctx.lineWidth = 0.5;
+ ctx.restore();
+ @assert ctx.lineWidth === 0.5;
+
+
+- name: 2d.transformation.order
+ desc: Transformations are applied in the right order
+ testing:
+ - 2d.transformation.order
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.scale(2, 1);
+ ctx.rotate(Math.PI / 2);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, -50, 50, 50);
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.transformation.scale.basic
+ desc: scale() works
+ testing:
+ - 2d.transformation.scale
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.scale(2, 4);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 12.5);
+ @assert pixel 90,40 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.scale.zero
+ desc: scale() with a scale factor of zero works
+ testing:
+ - 2d.transformation.scale
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.save();
+ ctx.translate(50, 0);
+ ctx.scale(0, 1);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.restore();
+
+ ctx.save();
+ ctx.translate(0, 25);
+ ctx.scale(1, 0);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.restore();
+
+ canvas.toDataURL();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.scale.negative
+ desc: scale() with negative scale factors works
+ testing:
+ - 2d.transformation.scale
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.save();
+ ctx.scale(-1, 1);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-50, 0, 50, 50);
+ ctx.restore();
+
+ ctx.save();
+ ctx.scale(1, -1);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, -50, 50, 50);
+ ctx.restore();
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.scale.large
+ desc: scale() with large scale factors works
+ notes: Not really that large at all, but it hits the limits in Firefox.
+ testing:
+ - 2d.transformation.scale
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.scale(1e5, 1e5);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 1, 1);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.scale.nonfinite
+ desc: scale() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 10);
+ @nonfinite ctx.scale(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -10, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.scale.multiple
+ desc: Multiple scale()s combine
+ testing:
+ - 2d.transformation.scale.multiple
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.scale(Math.sqrt(2), Math.sqrt(2));
+ ctx.scale(Math.sqrt(2), Math.sqrt(2));
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 25);
+ @assert pixel 90,40 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.transformation.rotate.zero
+ desc: rotate() by 0 does nothing
+ testing:
+ - 2d.transformation.rotate
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.rotate(0);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.rotate.radians
+ desc: rotate() uses radians
+ testing:
+ - 2d.transformation.rotate.radians
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.rotate(Math.PI); // should fail obviously if this is 3.1 degrees
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -50, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.rotate.direction
+ desc: rotate() is clockwise
+ testing:
+ - 2d.transformation.rotate.direction
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.rotate(Math.PI / 2);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, -100, 50, 100);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.rotate.wrap
+ desc: rotate() wraps large positive values correctly
+ testing:
+ - 2d.transformation.rotate
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.rotate(Math.PI * (1 + 4096)); // == pi (mod 2*pi)
+ // We need about pi +/- 0.001 in order to get correct-looking results
+ // 32-bit floats can store pi*4097 with precision 2^-10, so that should
+ // be safe enough on reasonable implementations
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -50, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,2 == 0,255,0,255;
+ @assert pixel 98,47 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.rotate.wrapnegative
+ desc: rotate() wraps large negative values correctly
+ testing:
+ - 2d.transformation.rotate
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.rotate(-Math.PI * (1 + 4096));
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -50, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,2 == 0,255,0,255;
+ @assert pixel 98,47 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.rotate.nonfinite
+ desc: rotate() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 10);
+ @nonfinite ctx.rotate(<0.1 Infinity -Infinity NaN>);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -10, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.translate.basic
+ desc: translate() works
+ testing:
+ - 2d.transformation.translate
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -50, 100, 50);
+ @assert pixel 90,40 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.translate.nonfinite
+ desc: translate() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 10);
+ @nonfinite ctx.translate(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -10, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.transformation.transform.identity
+ desc: transform() with the identity matrix does nothing
+ testing:
+ - 2d.transformation.transform
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.transform(1,0, 0,1, 0,0);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.transform.skewed
+ desc: transform() with skewy matrix transforms correctly
+ testing:
+ - 2d.transformation.transform
+ code: |
+ // Create green with a red square ring inside it
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(20, 10, 60, 30);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(40, 20, 20, 10);
+
+ // Draw a skewed shape to fill that gap, to make sure it is aligned correctly
+ ctx.transform(1,4, 2,3, 5,6);
+ // Post-transform coordinates:
+ // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]];
+ // Hence pre-transform coordinates:
+ var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2],
+ [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2],
+ [-7.4,11.2]];
+ ctx.beginPath();
+ ctx.moveTo(pts[0][0], pts[0][1]);
+ for (var i = 0; i < pts.length; ++i)
+ ctx.lineTo(pts[i][0], pts[i][1]);
+ ctx.fill();
+ @assert pixel 21,11 == 0,255,0,255;
+ @assert pixel 79,11 == 0,255,0,255;
+ @assert pixel 21,39 == 0,255,0,255;
+ @assert pixel 79,39 == 0,255,0,255;
+ @assert pixel 39,19 == 0,255,0,255;
+ @assert pixel 61,19 == 0,255,0,255;
+ @assert pixel 39,31 == 0,255,0,255;
+ @assert pixel 61,31 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.transform.multiply
+ desc: transform() multiplies the CTM
+ testing:
+ - 2d.transformation.transform.multiply
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.transform(1,2, 3,4, 5,6);
+ ctx.transform(-2,1, 3/2,-1/2, 1,-2);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.transform.nonfinite
+ desc: transform() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 10);
+ @nonfinite ctx.transform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -10, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.transformation.setTransform.skewed
+ testing:
+ - 2d.transformation.setTransform
+ code: |
+ // Create green with a red square ring inside it
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(20, 10, 60, 30);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(40, 20, 20, 10);
+
+ // Draw a skewed shape to fill that gap, to make sure it is aligned correctly
+ ctx.setTransform(1,4, 2,3, 5,6);
+ // Post-transform coordinates:
+ // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]];
+ // Hence pre-transform coordinates:
+ var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2],
+ [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2],
+ [-7.4,11.2]];
+ ctx.beginPath();
+ ctx.moveTo(pts[0][0], pts[0][1]);
+ for (var i = 0; i < pts.length; ++i)
+ ctx.lineTo(pts[i][0], pts[i][1]);
+ ctx.fill();
+ @assert pixel 21,11 == 0,255,0,255;
+ @assert pixel 79,11 == 0,255,0,255;
+ @assert pixel 21,39 == 0,255,0,255;
+ @assert pixel 79,39 == 0,255,0,255;
+ @assert pixel 39,19 == 0,255,0,255;
+ @assert pixel 61,19 == 0,255,0,255;
+ @assert pixel 39,31 == 0,255,0,255;
+ @assert pixel 61,31 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.setTransform.multiple
+ testing:
+ - 2d.transformation.setTransform.identity
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.setTransform(1/2,0, 0,1/2, 0,0);
+ ctx.setTransform(2,0, 0,2, 0,0);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 25);
+ @assert pixel 75,35 == 0,255,0,255;
+ expected: green
+
+- name: 2d.transformation.setTransform.nonfinite
+ desc: setTransform() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(100, 10);
+ @nonfinite ctx.setTransform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, -10, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.composite.globalAlpha.range
+ testing:
+ - 2d.composite.globalAlpha.range
+ code: |
+ ctx.globalAlpha = 0.5;
+ var a = ctx.globalAlpha; // might not be exactly 0.5, if it is rounded/quantised, so remember for future comparisons
+ ctx.globalAlpha = 1.1;
+ @assert ctx.globalAlpha === a;
+ ctx.globalAlpha = -0.1;
+ @assert ctx.globalAlpha === a;
+ ctx.globalAlpha = 0;
+ @assert ctx.globalAlpha === 0;
+ ctx.globalAlpha = 1;
+ @assert ctx.globalAlpha === 1;
+
+- name: 2d.composite.globalAlpha.invalid
+ testing:
+ - 2d.composite.globalAlpha.range
+ code: |
+ ctx.globalAlpha = 0.5;
+ var a = ctx.globalAlpha; // might not be exactly 0.5, if it is rounded/quantised, so remember for future comparisons
+ ctx.globalAlpha = Infinity;
+ @assert ctx.globalAlpha === a;
+ ctx.globalAlpha = -Infinity;
+ @assert ctx.globalAlpha === a;
+ ctx.globalAlpha = NaN;
+ @assert ctx.globalAlpha === a;
+
+- name: 2d.composite.globalAlpha.default
+ testing:
+ - 2d.composite.globalAlpha.default
+ code: |
+ @assert ctx.globalAlpha === 1.0;
+
+- name: 2d.composite.globalAlpha.fill
+ testing:
+ - 2d.composite.globalAlpha.shape
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 2,253,0,255;
+ expected: green
+
+- name: 2d.composite.globalAlpha.image
+ testing:
+ - 2d.composite.globalAlpha.image
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ @assert pixel 50,25 ==~ 2,253,0,255;
+ expected: green
+
+- name: 2d.composite.globalAlpha.canvas
+ testing:
+ - 2d.composite.globalAlpha.image
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
+ ctx.drawImage(canvas2, 0, 0);
+ @assert pixel 50,25 ==~ 2,253,0,255;
+ expected: green
+
+- name: 2d.composite.globalAlpha.imagepattern
+ testing:
+ - 2d.composite.globalAlpha.image
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = ctx.createPattern(document.getElementById('red.png'), 'no-repeat');
+ ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 2,253,0,255;
+ expected: green
+
+- name: 2d.composite.globalAlpha.canvaspattern
+ testing:
+ - 2d.composite.globalAlpha.image
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = ctx.createPattern(canvas2, 'no-repeat');
+ ctx.globalAlpha = 0.01; // avoid any potential alpha=0 optimisations
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 2,253,0,255;
+ expected: green
+
+
+- meta: |
+ # Composite operation tests
+ #
+ ops = [
+ # name FA FB
+ ('source-over', '1', '1-aA'),
+ ('destination-over', '1-aB', '1'),
+ ('source-in', 'aB', '0'),
+ ('destination-in', '0', 'aA'),
+ ('source-out', '1-aB', '0'),
+ ('destination-out', '0', '1-aA'),
+ ('source-atop', 'aB', '1-aA'),
+ ('destination-atop', '1-aB', 'aA'),
+ ('xor', '1-aB', '1-aA'),
+ ('copy', '1', '0'),
+ ('lighter', '1', '1'),
+ ]
+
+ # The ones that change the output when src = (0,0,0,0):
+ ops_trans = [ 'source-in', 'destination-in', 'source-out', 'destination-atop', 'copy' ];
+
+ def calc_output((RA, GA, BA, aA), (RB, GB, BB, aB), FA_code, FB_code):
+ rA, gA, bA = RA*aA, GA*aA, BA*aA
+ rB, gB, bB = RB*aB, GB*aB, BB*aB
+
+ FA = eval(FA_code)
+ FB = eval(FB_code)
+
+ rO = rA*FA + rB*FB
+ gO = gA*FA + gB*FB
+ bO = bA*FA + bB*FB
+ aO = aA*FA + aB*FB
+
+ rO = min(255, rO)
+ gO = min(255, gO)
+ bO = min(255, bO)
+ aO = min(1, aO)
+
+ if aO:
+ RO = rO / aO
+ GO = gO / aO
+ BO = bO / aO
+ else: RO = GO = BO = 0
+
+ return (RO, GO, BO, aO)
+
+ def to_test((r,g,b,a)):
+ return '%d,%d,%d,%d' % (round(r), round(g), round(b), round(a*255))
+ def to_cairo((r,g,b,a)):
+ return '%f,%f,%f,%f' % (r/255., g/255., b/255., a)
+
+ for (name, src, dest) in [
+ ('solid', (255, 255, 0, 1.0), (0, 255, 255, 1.0)),
+ ('transparent', (0, 0, 255, 0.75), (0, 255, 0, 0.5)),
+ # catches the atop, xor and lighter bugs in Opera 9.10
+ ]:
+ for op, FA_code, FB_code in ops:
+ expected = calc_output(src, dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'testing': [ '2d.composite.%s' % op ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, src, to_test(expected)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % to_cairo(expected),
+ } )
+
+ for (name, src, dest) in [ ('image', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ expected = calc_output(src, dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'testing': [ '2d.composite.%s' % op ],
+ 'images': [ 'yellow75.png' ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, to_test(expected)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % to_cairo(expected),
+ } )
+
+ for (name, src, dest) in [ ('canvas', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ expected = calc_output(src, dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'testing': [ '2d.composite.%s' % op ],
+ 'images': [ 'yellow75.png' ],
+ 'code': """
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = canvas.width;
+ canvas2.height = canvas.height;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.drawImage(document.getElementById('yellow75.png'), 0, 0);
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.drawImage(canvas2, 0, 0);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, to_test(expected)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % to_cairo(expected),
+ } )
+
+
+ for (name, src, dest) in [ ('uncovered.fill', (0, 0, 255, 0.75), (0, 255, 0, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ if op not in ops_trans: continue
+ expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'desc': 'fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
+ 'testing': [ '2d.composite.%s' % op ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.fillStyle = 'rgba%s';
+ ctx.translate(0, 25);
+ ctx.fillRect(0, 50, 100, 50);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, src, to_test(expected0)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % (to_cairo(expected0)),
+ } )
+
+ for (name, src, dest) in [ ('uncovered.image', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ if op not in ops_trans: continue
+ expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'desc': 'drawImage() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
+ 'testing': [ '2d.composite.%s' % op ],
+ 'images': [ 'yellow.png' ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.drawImage(document.getElementById('yellow.png'), 40, 40, 10, 10, 40, 50, 10, 10);
+ @assert pixel 15,15 ==~ %s +/- 5;
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, to_test(expected0), to_test(expected0)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % (to_cairo(expected0)),
+ } )
+
+ for (name, src, dest) in [ ('uncovered.nocontext', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ if op not in ops_trans: continue
+ expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'desc': 'drawImage() of a canvas with no context draws pixels as (0,0,0,0), and does not leave the pixels unchanged.',
+ 'testing': [ '2d.composite.%s' % op ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ var canvas2 = document.createElement('canvas');
+ ctx.drawImage(canvas2, 0, 0);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, to_test(expected0)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % (to_cairo(expected0)),
+ } )
+
+ for (name, src, dest) in [ ('uncovered.pattern', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
+ for op, FA_code, FB_code in ops:
+ if op not in ops_trans: continue
+ expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
+ tests.append( {
+ 'name': '2d.composite.%s.%s' % (name, op),
+ 'desc': 'Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
+ 'testing': [ '2d.composite.%s' % op ],
+ 'images': [ 'yellow.png' ],
+ 'code': """
+ ctx.fillStyle = 'rgba%s';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.fillStyle = ctx.createPattern(document.getElementById('yellow.png'), 'no-repeat');
+ ctx.fillRect(0, 50, 100, 50);
+ @assert pixel 50,25 ==~ %s +/- 5;
+ """ % (dest, op, to_test(expected0)),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%s)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % (to_cairo(expected0)),
+ } )
+
+ for op, FA_code, FB_code in ops:
+ tests.append( {
+ 'name': '2d.composite.clip.%s' % (op),
+ 'desc': 'fill() does not affect pixels outside the clip region.',
+ 'testing': [ '2d.composite.%s' % op ],
+ 'code': """
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = '%s';
+ ctx.rect(-20, -20, 10, 10);
+ ctx.clip();
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ """ % (op),
+ 'expected': 'green'
+ } )
+
+- name: 2d.composite.operation.get
+ testing:
+ - 2d.composite.operation
+ code: |
+ var modes = ['source-atop', 'source-in', 'source-out', 'source-over',
+ 'destination-atop', 'destination-in', 'destination-out', 'destination-over',
+ 'lighter', 'copy', 'xor'];
+ for (var i = 0; i < modes.length; ++i)
+ {
+ ctx.globalCompositeOperation = modes[i];
+ @assert ctx.globalCompositeOperation === modes[i];
+ }
+
+- name: 2d.composite.operation.unrecognised
+ testing:
+ - 2d.composite.operation.unrecognised
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'nonexistent';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.darker
+ testing:
+ - 2d.composite.operation.unrecognised
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'darker';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.over
+ testing:
+ - 2d.composite.operation.unrecognised
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'over';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.clear
+ testing:
+ - 2d.composite.operation.unrecognised
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'clear';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.highlight
+ testing:
+ - 2d.composite.operation.unrecognised
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'highlight';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.nullsuffix
+ testing:
+ - 2d.composite.operation.exact
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'source-over\0';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.casesensitive
+ testing:
+ - 2d.composite.operation.casesensitive
+ code: |
+ ctx.globalCompositeOperation = 'xor';
+ ctx.globalCompositeOperation = 'Source-over';
+ @assert ctx.globalCompositeOperation === 'xor';
+
+- name: 2d.composite.operation.default
+ testing:
+ - 2d.composite.operation.default
+ code: |
+ @assert ctx.globalCompositeOperation === 'source-over';
+
+
+- meta: |
+ # Colour parsing tests
+
+ # Try most of the CSS3 Color values - http://www.w3.org/TR/css3-color/#colorunits
+ big_float = '1' + ('0' * 39)
+ big_double = '1' + ('0' * 310)
+ for name, string, r,g,b,a, notes in [
+ ('html4', 'limE', 0,255,0,255, ""),
+ ('hex3', '#0f0', 0,255,0,255, ""),
+ ('hex6', '#00fF00', 0,255,0,255, ""),
+ ('rgb-num', 'rgb(0,255,0)', 0,255,0,255, ""),
+ ('rgb-clamp-1', 'rgb(-1000, 1000, -1000)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'),
+ ('rgb-clamp-2', 'rgb(-200%, 200%, -200%)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'),
+ ('rgb-clamp-3', 'rgb(-2147483649, 4294967298, -18446744073709551619)', 0,255,0,255, 'Assumes colours are clamped to [0,255].'),
+ ('rgb-clamp-4', 'rgb(-'+big_float+', '+big_float+', -'+big_float+')', 0,255,0,255, 'Assumes colours are clamped to [0,255].'),
+ ('rgb-clamp-5', 'rgb(-'+big_double+', '+big_double+', -'+big_double+')', 0,255,0,255, 'Assumes colours are clamped to [0,255].'),
+ ('rgb-percent', 'rgb(0% ,100% ,0%)', 0,255,0,255, 'CSS3 Color says "The integer value 255 corresponds to 100%". (In particular, it is not 254...)'),
+ ('rgb-eof', 'rgb(0, 255, 0', 0,255,0,255, ""), # see CSS2.1 4.2 "Unexpected end of style sheet"
+ ('rgba-solid-1', 'rgba( 0 , 255 , 0 , 1 )', 0,255,0,255, ""),
+ ('rgba-solid-2', 'rgba( 0 , 255 , 0 , 1.0 )', 0,255,0,255, ""),
+ ('rgba-solid-3', 'rgba( 0 , 255 , 0 , +1 )', 0,255,0,255, ""),
+ ('rgba-solid-4', 'rgba( -0 , 255 , +0 , 1 )', 0,255,0,255, ""),
+ ('rgba-num-1', 'rgba( 0 , 255 , 0 , .499 )', 0,255,0,127, ""),
+ ('rgba-num-2', 'rgba( 0 , 255 , 0 , 0.499 )', 0,255,0,127, ""),
+ ('rgba-percent', 'rgba(0%,100%,0%,0.499)', 0,255,0,127, ""), # 0.499*255 rounds to 127, both down and nearest, so it should be safe
+ ('rgba-clamp-1', 'rgba(0, 255, 0, -2)', 0,0,0,0, ""),
+ ('rgba-clamp-2', 'rgba(0, 255, 0, 2)', 0,255,0,255, ""),
+ ('rgba-eof', 'rgba(0, 255, 0, 1', 0,255,0,255, ""),
+ ('transparent-1', 'transparent', 0,0,0,0, ""),
+ ('transparent-2', 'TrAnSpArEnT', 0,0,0,0, ""),
+ ('hsl-1', 'hsl(120, 100%, 50%)', 0,255,0,255, ""),
+ ('hsl-2', 'hsl( -240 , 100% , 50% )', 0,255,0,255, ""),
+ ('hsl-3', 'hsl(360120, 100%, 50%)', 0,255,0,255, ""),
+ ('hsl-4', 'hsl(-360240, 100%, 50%)', 0,255,0,255, ""),
+ ('hsl-5', 'hsl(120.0, 100.0%, 50.0%)', 0,255,0,255, ""),
+ ('hsl-6', 'hsl(+120, +100%, +50%)', 0,255,0,255, ""),
+ ('hsl-clamp-1', 'hsl(120, 200%, 50%)', 0,255,0,255, ""),
+ ('hsl-clamp-2', 'hsl(120, -200%, 49.9%)', 127,127,127,255, ""),
+ ('hsl-clamp-3', 'hsl(120, 100%, 200%)', 255,255,255,255, ""),
+ ('hsl-clamp-4', 'hsl(120, 100%, -200%)', 0,0,0,255, ""),
+ ('hsla-1', 'hsla(120, 100%, 50%, 0.499)', 0,255,0,127, ""),
+ ('hsla-2', 'hsla( 120.0 , 100.0% , 50.0% , 1 )', 0,255,0,255, ""),
+ ('hsla-clamp-1', 'hsla(120, 200%, 50%, 1)', 0,255,0,255, ""),
+ ('hsla-clamp-2', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""),
+ ('hsla-clamp-3', 'hsla(120, 100%, 200%, 1)', 255,255,255,255, ""),
+ ('hsla-clamp-4', 'hsla(120, 100%, -200%, 1)', 0,0,0,255, ""),
+ ('hsla-clamp-5', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""),
+ ('hsla-clamp-6', 'hsla(120, 100%, 0%, -2)', 0,0,0,0, ""),
+ ('svg-1', 'gray', 128,128,128,255, ""),
+ ('svg-2', 'grey', 128,128,128,255, ""),
+ # currentColor is handled later
+ ]:
+ # TODO: test by retrieving fillStyle, instead of actually drawing?
+ # TODO: test strokeStyle, shadowColor in the same way
+ test = {
+ 'name': '2d.fillStyle.parse.%s' % name,
+ 'testing': [ '2d.colours.parse' ],
+ 'notes': notes,
+ 'code': """
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = '%s';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == %d,%d,%d,%d;
+ """ % (string, r,g,b,a),
+ 'expected': """size 100 50
+ cr.set_source_rgba(%f, %f, %f, %f)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ """ % (r/255., g/255., b/255., a/255.),
+ }
+ tests.append(test)
+
+ # Also test that invalid colours are ignored
+ for name, string in [
+ ('hex1', '#f'),
+ ('hex2', '#f0'),
+ ('hex3', '#g00'),
+ ('hex4', '#ff00'),
+ ('hex5', '#ff000'),
+ ('hex6', '#fg0000'),
+ ('hex7', '#ff0000f'),
+ ('hex8', '#ff0000ff'),
+ ('rgb-1', 'rgb(255.0, 0, 0)'),
+ ('rgb-2', 'rgb(255, 0.0, 0)'),
+ ('rgb-3', 'rgb(255.0, 0, 0,)'),
+ ('rgb-4', 'rgb(100%, 0, 0)'),
+ ('rgb-5', 'rgb(255 0 0)'),
+ ('rgb-6', 'rgb(255, - 1, 0)'),
+ ('rgb-7', 'rgb(255, 0, 0, 1)'),
+ ('rgba-1', 'rgba(255, 0, 0)'),
+ ('rgba-2', 'rgba(255.0, 0, 0, 1)'),
+ ('rgba-3', 'rgba(100%, 0, 0, 1)'),
+ ('rgba-4', 'rgba(255, 0, 0, 100%)'),
+ ('rgba-5', 'rgba(255, 0, 0, 1. 0)'),
+ ('rgba-6', 'rgba(255, 0, 0, 1.)'),
+ ('rgba-7', 'rgba(255, 0, 0, '),
+ ('hsl-1', 'hsl(0%, 100%, 50%)'),
+ ('hsl-2', 'hsl(z, 100%, 50%)'),
+ ('hsl-3', 'hsl(0, 0, 50%)'),
+ ('hsl-4', 'hsl(0, 100%, 0)'),
+ ('hsl-5', 'hsl(0, 100%, 100%, 1)'),
+ ('hsl-6', 'hsl(0, 100.%, 50%)'),
+ ('hsla-1', 'hsla(0%, 100%, 50%, 1)'),
+ ('hsla-2', 'hsla(0, 0, 50%, 1)'),
+ ('name-1', 'darkbrown'),
+ ('name-2', 'firebrick1'),
+ ('name-3', 'red blue'),
+ ('name-4', '"red"'),
+ ('name-5', '"red'),
+ ]:
+ test = {
+ 'name': '2d.fillStyle.parse.invalid.%s' % name,
+ 'testing': [ '2d.colours.parse' ],
+ 'code': """
+ ctx.fillStyle = '#0f0';
+ try { ctx.fillStyle = '%s'; } catch (e) { } // this shouldn't throw, but it shouldn't matter here if it does
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ """ % string,
+ 'expected': 'green'
+ }
+ tests.append(test)
+
+ # Some can't have positive tests, only negative tests, because we don't know what colour they're meant to be
+ for name, string in [
+ ('system', 'ThreeDDarkShadow'),
+ #('flavor', 'flavor'), # removed from latest CSS3 Color drafts
+ ]:
+ test = {
+ 'name': '2d.fillStyle.parse.%s' % name,
+ 'testing': [ '2d.colours.parse' ],
+ 'code': """
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = '%s';
+ @assert ctx.fillStyle =~ /^#(?!(FF0000|ff0000|f00)$)/; // test that it's not red
+ """ % (string,),
+ }
+ tests.append(test)
+
+- name: 2d.fillStyle.parse.current.basic
+ desc: currentColor is computed from the canvas element
+ testing:
+ - 2d.colours.parse
+ - 2d.currentColor.onset
+ code: |
+ canvas.setAttribute('style', 'color: #0f0');
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'currentColor';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillStyle.parse.current.changed
+ desc: currentColor is computed when the attribute is set, not when it is painted
+ testing:
+ - 2d.colours.parse
+ - 2d.currentColor.onset
+ code: |
+ canvas.setAttribute('style', 'color: #0f0');
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'currentColor';
+ canvas.setAttribute('style', 'color: #f00');
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillStyle.parse.current.removed
+ desc: currentColor is solid black when the canvas element is not in a document
+ testing:
+ - 2d.colours.parse
+ - 2d.currentColor.outofdoc
+ code: |
+ // Try not to let it undetectably incorrectly pick up opaque-black
+ // from other parts of the document:
+ document.body.parentNode.setAttribute('style', 'color: #f00');
+ document.body.setAttribute('style', 'color: #f00');
+ canvas.setAttribute('style', 'color: #f00');
+
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillStyle = 'currentColor';
+ ctx2.fillRect(0, 0, 100, 50);
+ ctx.drawImage(canvas2, 0, 0);
+
+ document.body.parentNode.removeAttribute('style');
+ document.body.removeAttribute('style');
+
+ @assert pixel 50,25 == 0,0,0,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.fillStyle.invalidstring
+ testing:
+ - 2d.colours.invalidstring
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillStyle = 'invalid';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillStyle.invalidtype
+ testing:
+ - 2d.colours.invalidtype
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillStyle = null;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillStyle.get.solid
+ testing:
+ - 2d.colours.getcolour
+ - 2d.serializecolour.solid
+ code: |
+ ctx.fillStyle = '#fa0';
+ @assert ctx.fillStyle === '#ffaa00';
+
+- name: 2d.fillStyle.get.semitransparent
+ testing:
+ - 2d.colours.getcolour
+ - 2d.serializecolour.transparent
+ code: |
+ ctx.fillStyle = 'rgba(255,255,255,0.45)';
+ @assert ctx.fillStyle =~ /^rgba\(255, 255, 255, 0\.4\d+\)$/;
+
+- name: 2d.fillStyle.get.transparent
+ testing:
+ - 2d.colours.getcolour
+ - 2d.serializecolour.transparent
+ code: |
+ ctx.fillStyle = 'rgba(0,0,0,0)';
+ @assert ctx.fillStyle === 'rgba(0, 0, 0, 0)';
+
+- name: 2d.fillStyle.default
+ testing:
+ - 2d.colours.default
+ code: |
+ @assert ctx.fillStyle === '#000000';
+
+- name: 2d.strokeStyle.default
+ testing:
+ - 2d.colours.default
+ code: |
+ @assert ctx.strokeStyle === '#000000';
+
+
+- name: 2d.gradient.object.type
+ desc: window.CanvasGradient exists and has the right properties
+ testing:
+ - 2d.canvasGradient.type
+ notes: *bindings
+ code: |
+ @assert window.CanvasGradient !== undefined;
+ @assert window.CanvasGradient.prototype.addColorStop !== undefined;
+
+- name: 2d.gradient.object.return
+ desc: createLinearGradient() and createRadialGradient() returns objects implementing CanvasGradient
+ testing:
+ - 2d.gradient.linear.return
+ - 2d.gradient.radial.return
+ code: |
+ window.CanvasGradient.prototype.thisImplementsCanvasGradient = true;
+
+ var g1 = ctx.createLinearGradient(0, 0, 100, 0);
+ @assert g1.addColorStop !== undefined;
+ @assert g1.thisImplementsCanvasGradient === true;
+
+ var g2 = ctx.createRadialGradient(0, 0, 10, 0, 0, 20);
+ @assert g2.addColorStop !== undefined;
+ @assert g2.thisImplementsCanvasGradient === true;
+
+- name: 2d.gradient.interpolate.solid
+ testing:
+ - 2d.gradient.interpolate.linear
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.interpolate.colour
+ testing:
+ - 2d.gradient.interpolate.linear
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, '#ff0');
+ g.addColorStop(1, '#00f');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 25,25 ==~ 191,191,63,255 +/- 3;
+ @assert pixel 50,25 ==~ 127,127,127,255 +/- 3;
+ @assert pixel 75,25 ==~ 63,63,191,255 +/- 3;
+ expected: |
+ size 100 50
+ g = cairo.LinearGradient(0, 0, 100, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.alpha
+ testing:
+ - 2d.gradient.interpolate.linear
+ code: |
+ ctx.fillStyle = '#ff0';
+ ctx.fillRect(0, 0, 100, 50);
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, 'rgba(0,0,255, 0)');
+ g.addColorStop(1, 'rgba(0,0,255, 1)');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 25,25 ==~ 191,191,63,255 +/- 3;
+ @assert pixel 50,25 ==~ 127,127,127,255 +/- 3;
+ @assert pixel 75,25 ==~ 63,63,191,255 +/- 3;
+ expected: |
+ size 100 50
+ g = cairo.LinearGradient(0, 0, 100, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.colouralpha
+ testing:
+ - 2d.gradient.interpolate.alpha
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, 'rgba(255,255,0, 0)');
+ g.addColorStop(1, 'rgba(0,0,255, 1)');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 25,25 ==~ 191,191,63,63 +/- 3;
+ @assert pixel 50,25 ==~ 127,127,127,127 +/- 3;
+ @assert pixel 75,25 ==~ 63,63,191,191 +/- 3;
+ expected: |
+ size 100 50
+ g = cairo.LinearGradient(0, 0, 100, 0)
+ g.add_color_stop_rgba(0, 1,1,0, 0)
+ g.add_color_stop_rgba(1, 0,0,1, 1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.outside
+ testing:
+ - 2d.gradient.outside.first
+ - 2d.gradient.outside.last
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(25, 0, 75, 0);
+ g.addColorStop(0.4, '#0f0');
+ g.addColorStop(0.6, '#0f0');
+
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 20,25 ==~ 0,255,0,255;
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 80,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.fill
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.rect(0, 0, 100, 50);
+ ctx.fill();
+ @assert pixel 40,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.stroke
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.strokeStyle = g;
+ ctx.rect(20, 20, 60, 10);
+ ctx.stroke();
+ @assert pixel 19,19 == 0,255,0,255;
+ @assert pixel 20,19 == 0,255,0,255;
+ @assert pixel 21,19 == 0,255,0,255;
+ @assert pixel 19,20 == 0,255,0,255;
+ @assert pixel 20,20 == 0,255,0,255;
+ @assert pixel 21,20 == 0,255,0,255;
+ @assert pixel 19,21 == 0,255,0,255;
+ @assert pixel 20,21 == 0,255,0,255;
+ @assert pixel 21,21 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.fillRect
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 40,20 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.strokeRect
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.strokeStyle = g;
+ ctx.strokeRect(20, 20, 60, 10);
+ @assert pixel 19,19 == 0,255,0,255;
+ @assert pixel 20,19 == 0,255,0,255;
+ @assert pixel 21,19 == 0,255,0,255;
+ @assert pixel 19,20 == 0,255,0,255;
+ @assert pixel 20,20 == 0,255,0,255;
+ @assert pixel 21,20 == 0,255,0,255;
+ @assert pixel 19,21 == 0,255,0,255;
+ @assert pixel 20,21 == 0,255,0,255;
+ @assert pixel 21,21 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.fillText
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.font = '100px sans-serif';
+ ctx.fillText("AA", 0, 50);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.gradient.interpolate.zerosize.strokeText
+ testing:
+ - 2d.gradient.linear.zerosize
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.strokeStyle = g;
+ ctx.font = '100px sans-serif';
+ ctx.strokeText("AA", 0, 50);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+
+- name: 2d.gradient.interpolate.vertical
+ testing:
+ - 2d.gradient.interpolate.linear
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 0, 50);
+ g.addColorStop(0, '#ff0');
+ g.addColorStop(1, '#00f');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,12 ==~ 191,191,63,255 +/- 10;
+ @assert pixel 50,25 ==~ 127,127,127,255 +/- 5;
+ @assert pixel 50,37 ==~ 63,63,191,255 +/- 10;
+ expected: |
+ size 100 50
+ g = cairo.LinearGradient(0, 0, 0, 50)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.multiple
+ testing:
+ - 2d.gradient.interpolate.linear
+ code: |
+ canvas.width = 200;
+ var g = ctx.createLinearGradient(0, 0, 200, 0);
+ g.addColorStop(0, '#ff0');
+ g.addColorStop(0.5, '#0ff');
+ g.addColorStop(1, '#f0f');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 200, 50);
+ @assert pixel 50,25 ==~ 127,255,127,255 +/- 3;
+ @assert pixel 100,25 ==~ 0,255,255,255 +/- 3;
+ @assert pixel 150,25 ==~ 127,127,255,255 +/- 3;
+ expected: |
+ size 200 50
+ g = cairo.LinearGradient(0, 0, 200, 0)
+ g.add_color_stop_rgb(0.0, 1,1,0)
+ g.add_color_stop_rgb(0.5, 0,1,1)
+ g.add_color_stop_rgb(1.0, 1,0,1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 200, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.overlap
+ testing:
+ - 2d.gradient.interpolate.overlap
+ code: |
+ canvas.width = 200;
+ var g = ctx.createLinearGradient(0, 0, 200, 0);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0, '#ff0');
+ g.addColorStop(0.25, '#00f');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.25, '#ff0');
+ g.addColorStop(0.5, '#00f');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.75, '#00f');
+ g.addColorStop(0.75, '#f00');
+ g.addColorStop(0.75, '#ff0');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.5, '#ff0');
+ g.addColorStop(1, '#00f');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 200, 50);
+ @assert pixel 49,25 ==~ 0,0,255,255 +/- 16;
+ @assert pixel 51,25 ==~ 255,255,0,255 +/- 16;
+ @assert pixel 99,25 ==~ 0,0,255,255 +/- 16;
+ @assert pixel 101,25 ==~ 255,255,0,255 +/- 16;
+ @assert pixel 149,25 ==~ 0,0,255,255 +/- 16;
+ @assert pixel 151,25 ==~ 255,255,0,255 +/- 16;
+ expected: |
+ size 200 50
+ g = cairo.LinearGradient(0, 0, 50, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(0, 0, 50, 50)
+ cr.fill()
+
+ g = cairo.LinearGradient(50, 0, 100, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(50, 0, 50, 50)
+ cr.fill()
+
+ g = cairo.LinearGradient(100, 0, 150, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(100, 0, 50, 50)
+ cr.fill()
+
+ g = cairo.LinearGradient(150, 0, 200, 0)
+ g.add_color_stop_rgb(0, 1,1,0)
+ g.add_color_stop_rgb(1, 0,0,1)
+ cr.set_source(g)
+ cr.rectangle(150, 0, 50, 50)
+ cr.fill()
+
+- name: 2d.gradient.interpolate.overlap2
+ testing:
+ - 2d.gradient.interpolate.overlap
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ var ps = [ 0, 1/10, 1/4, 1/3, 1/2, 3/4, 1 ];
+ for (var p = 0; p < ps.length; ++p)
+ {
+ g.addColorStop(ps[p], '#0f0');
+ for (var i = 0; i < 15; ++i)
+ g.addColorStop(ps[p], '#f00');
+ g.addColorStop(ps[p], '#0f0');
+ }
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 30,25 == 0,255,0,255;
+ @assert pixel 40,25 == 0,255,0,255;
+ @assert pixel 60,25 == 0,255,0,255;
+ @assert pixel 80,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.empty
+ testing:
+ - 2d.gradient.empty
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var g = ctx.createLinearGradient(0, 0, 0, 50);
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.object.update
+ testing:
+ - 2d.gradient.update
+ code: |
+ var g = ctx.createLinearGradient(-100, 0, 200, 0);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ g.addColorStop(0.1, '#0f0');
+ g.addColorStop(0.9, '#0f0');
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.object.compare
+ testing:
+ - 2d.gradient.object
+ code: |
+ var g1 = ctx.createLinearGradient(0, 0, 100, 0);
+ var g2 = ctx.createLinearGradient(0, 0, 100, 0);
+ @assert g1 !== g2;
+ ctx.fillStyle = g1;
+ @assert ctx.fillStyle === g1;
+
+- name: 2d.gradient.object.crosscanvas
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var g = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.object.current
+ testing:
+ - 2d.currentColor.gradient
+ code: |
+ canvas.setAttribute('style', 'color: #f00');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ g.addColorStop(0, 'currentColor');
+ g.addColorStop(1, 'currentColor');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,0,0,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.gradient.object.invalidoffset
+ testing:
+ - 2d.gradient.invalidoffset
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ @assert throws INDEX_SIZE_ERR g.addColorStop(-1, '#000');
+ @assert throws INDEX_SIZE_ERR g.addColorStop(2, '#000');
+ @assert throws INDEX_SIZE_ERR g.addColorStop(Infinity, '#000');
+ @assert throws INDEX_SIZE_ERR g.addColorStop(-Infinity, '#000');
+ @assert throws INDEX_SIZE_ERR g.addColorStop(NaN, '#000');
+
+- name: 2d.gradient.object.invalidcolour
+ testing:
+ - 2d.gradient.invalidcolour
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 100, 0);
+ @assert throws SYNTAX_ERR g.addColorStop(0, "");
+ @assert throws SYNTAX_ERR g.addColorStop(0, 'null');
+ @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined');
+ @assert throws SYNTAX_ERR g.addColorStop(0, null);
+ @assert throws SYNTAX_ERR g.addColorStop(0, undefined);
+
+
+- name: 2d.gradient.linear.nonfinite
+ desc: createLinearGradient() throws TypeError if arguments are not finite
+ notes: *bindings
+ testing:
+ - 2d.gradient.linear.nonfinite
+ code: |
+ @nonfinite @assert throws TypeError ctx.createLinearGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
+
+- name: 2d.gradient.linear.transform.1
+ desc: Linear gradient coordinates are relative to the coordinate space at the time of filling
+ testing:
+ - 2d.gradient.linear.transform
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 200, 0);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.75, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.translate(-50, 0);
+ ctx.fillRect(50, 0, 100, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.linear.transform.2
+ desc: Linear gradient coordinates are relative to the coordinate space at the time of filling
+ testing:
+ - 2d.gradient.linear.transform
+ code: |
+ ctx.translate(100, 0);
+ var g = ctx.createLinearGradient(0, 0, 200, 0);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.75, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.translate(-150, 0);
+ ctx.fillRect(50, 0, 100, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.linear.transform.3
+ desc: Linear gradient transforms do not experience broken caching effects
+ testing:
+ - 2d.gradient.linear.transform
+ code: |
+ var g = ctx.createLinearGradient(0, 0, 200, 0);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.25, '#0f0');
+ g.addColorStop(0.75, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.translate(-50, 0);
+ ctx.fillRect(50, 0, 100, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.negative
+ desc: createRadialGradient() throws INDEX_SIZE_ERR if either radius is negative
+ testing:
+ - 2d.gradient.radial.negative
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1);
+ @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1);
+ @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1);
+
+- name: 2d.gradient.radial.nonfinite
+ desc: createRadialGradient() throws TypeError if arguments are not finite
+ notes: *bindings
+ testing:
+ - 2d.gradient.radial.nonfinite
+ code: |
+ @nonfinite @assert throws TypeError ctx.createRadialGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>);
+
+- name: 2d.gradient.radial.inside1
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(50, 25, 100, 50, 25, 200);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.inside2
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.inside3
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.993, '#f00');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.outside1
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(200, 25, 10, 200, 25, 20);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.outside2
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.outside3
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(0.001, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.touch1
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(150, 25, 50, 200, 25, 100);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255; @moz-todo
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ @assert pixel 98,25 == 0,255,0,255; @moz-todo
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.radial.touch2
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.01, '#0f0');
+ g.addColorStop(0.99, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.touch3
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(120, -15, 25, 140, -30, 50);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255; @moz-todo
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ @assert pixel 98,25 == 0,255,0,255; @moz-todo
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.radial.equal
+ testing:
+ - 2d.gradient.radial.equal
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(50, 25, 20, 50, 25, 20);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255; @moz-todo
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ @assert pixel 98,25 == 0,255,0,255; @moz-todo
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.radial.cone.behind
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(120, 25, 10, 211, 25, 100);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255; @moz-todo
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ @assert pixel 98,25 == 0,255,0,255; @moz-todo
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.radial.cone.front
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(311, 25, 10, 210, 25, 100);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.cone.bottom
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 101);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.cone.top
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(230, 25, 100, 100, 25, 101);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.cone.beside
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(0, 100, 40, 100, 100, 50);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255; @moz-todo
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ @assert pixel 98,25 == 0,255,0,255; @moz-todo
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.gradient.radial.cone.cylinder
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 100);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.cone.shape1
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ var tol = 1; // tolerance to avoid antialiasing artifacts
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(30+tol, 40);
+ ctx.lineTo(110, -20+tol);
+ ctx.lineTo(110, 100-tol);
+ ctx.fill();
+
+ var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(1, '#0f0');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.cone.shape2
+ testing:
+ - 2d.gradient.radial.rendering
+ code: |
+ var tol = 1; // tolerance to avoid antialiasing artifacts
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(30-tol, 40);
+ ctx.lineTo(110, -20-tol);
+ ctx.lineTo(110, 100+tol);
+ ctx.fill();
+
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,1 == 0,255,0,255; @moz-todo
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.transform.1
+ desc: Radial gradient coordinates are relative to the coordinate space at the time of filling
+ testing:
+ - 2d.gradient.radial.transform
+ code: |
+ var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.51, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.translate(50, 25);
+ ctx.scale(10, 10);
+ ctx.fillRect(-5, -2.5, 10, 5);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.transform.2
+ desc: Radial gradient coordinates are relative to the coordinate space at the time of filling
+ testing:
+ - 2d.gradient.radial.transform
+ code: |
+ ctx.translate(100, 0);
+ var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.51, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.translate(-50, 25);
+ ctx.scale(10, 10);
+ ctx.fillRect(-5, -2.5, 10, 5);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.gradient.radial.transform.3
+ desc: Radial gradient transforms do not experience broken caching effects
+ testing:
+ - 2d.gradient.radial.transform
+ code: |
+ var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
+ g.addColorStop(0, '#0f0');
+ g.addColorStop(0.5, '#0f0');
+ g.addColorStop(0.51, '#f00');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.translate(50, 25);
+ ctx.scale(10, 10);
+ ctx.fillRect(-5, -2.5, 10, 5);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+
+
+
+
+
+- name: 2d.pattern.basic.type
+ testing:
+ - 2d.pattern.return
+ images:
+ - green.png
+ code: |
+ @assert window.CanvasPattern !== undefined;
+
+ window.CanvasPattern.prototype.thisImplementsCanvasPattern = true;
+
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ @assert pattern.thisImplementsCanvasPattern;
+
+- name: 2d.pattern.basic.image
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.basic.canvas
+ testing:
+ - 2d.pattern.painting
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ var pattern = ctx.createPattern(canvas2, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.basic.zerocanvas
+ testing:
+ - 2d.pattern.zerocanvas
+ code: |
+ canvas.width = 0;
+ canvas.height = 10;
+ @assert canvas.width === 0;
+ @assert canvas.height === 10;
+ @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
+
+ canvas.width = 10;
+ canvas.height = 0;
+ @assert canvas.width === 10;
+ @assert canvas.height === 0;
+ @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
+
+ canvas.width = 0;
+ canvas.height = 0;
+ @assert canvas.width === 0;
+ @assert canvas.height === 0;
+ @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
+
+- name: 2d.pattern.basic.nocontext
+ testing:
+ - 2d.pattern.painting
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var pattern = ctx.createPattern(canvas2, 'no-repeat');
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.image.undefined
+ testing:
+ - 2d.pattern.IDL
+ notes: *bindings
+ code: |
+ @assert throws TypeError ctx.createPattern(undefined, 'repeat');
+
+- name: 2d.pattern.image.null
+ testing:
+ - 2d.pattern.IDL
+ notes: *bindings
+ code: |
+ @assert throws TypeError ctx.createPattern(null, 'repeat');
+
+- name: 2d.pattern.image.string
+ testing:
+ - 2d.pattern.IDL
+ notes: *bindings
+ code: |
+ @assert throws TypeError ctx.createPattern('../images/red.png', 'repeat');
+
+- name: 2d.pattern.image.incomplete.nosrc
+ testing:
+ - 2d.pattern.incomplete.image
+ mozilla: { throws }
+ code: |
+ var img = new Image();
+ @assert ctx.createPattern(img, 'repeat') === null;
+
+- name: 2d.pattern.image.incomplete.immediate
+ testing:
+ - 2d.pattern.incomplete.image
+ images:
+ - red.png
+ code: |
+ var img = new Image();
+ img.src = '../images/red.png';
+ // This triggers the "update the image data" algorithm.
+ // The image will not go to the "completely available" state
+ // until a fetch task in the networking task source is processed,
+ // so the image must not be fully decodable yet:
+ @assert ctx.createPattern(img, 'repeat') === null; @moz-todo
+
+- name: 2d.pattern.image.incomplete.reload
+ testing:
+ - 2d.pattern.incomplete.image
+ images:
+ - yellow.png
+ - red.png
+ code: |
+ var img = document.getElementById('yellow.png');
+ img.src = '../images/red.png';
+ // This triggers the "update the image data" algorithm,
+ // and resets the image to the "unavailable" state.
+ // The image will not go to the "completely available" state
+ // until a fetch task in the networking task source is processed,
+ // so the image must not be fully decodable yet:
+ @assert ctx.createPattern(img, 'repeat') === null; @moz-todo
+
+- name: 2d.pattern.image.incomplete.emptysrc
+ testing:
+ - 2d.pattern.incomplete.image
+ images:
+ - red.png
+ mozilla: { throws }
+ code: |
+ var img = document.getElementById('red.png');
+ img.src = "";
+ @assert ctx.createPattern(img, 'repeat') === null;
+
+- name: 2d.pattern.image.incomplete.removedsrc
+ testing:
+ - 2d.pattern.incomplete.image
+ images:
+ - red.png
+ mozilla: { throws }
+ code: |
+ var img = document.getElementById('red.png');
+ img.removeAttribute('src');
+ @assert ctx.createPattern(img, 'repeat') === null;
+
+- name: 2d.pattern.image.broken
+ testing:
+ - 2d.pattern.incomplete.image
+ images:
+ - broken.png
+ code: |
+ var img = document.getElementById('broken.png');
+ @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat');
+
+- name: 2d.pattern.repeat.empty
+ testing:
+ - 2d.pattern.missing
+ images:
+ - green-1x1.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('green-1x1.png');
+ var pattern = ctx.createPattern(img, "");
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 200, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.repeat.null
+ testing:
+ - 2d.pattern.unrecognised
+ code: |
+ @assert ctx.createPattern(canvas, null) != null;
+
+- name: 2d.pattern.repeat.undefined
+ testing:
+ - 2d.pattern.unrecognised
+ code: |
+ @assert throws SYNTAX_ERR ctx.createPattern(canvas, undefined);
+
+- name: 2d.pattern.repeat.unrecognised
+ testing:
+ - 2d.pattern.unrecognised
+ code: |
+ @assert throws SYNTAX_ERR ctx.createPattern(canvas, "invalid");
+
+- name: 2d.pattern.repeat.unrecognisednull
+ testing:
+ - 2d.pattern.unrecognised
+ code: |
+ @assert throws SYNTAX_ERR ctx.createPattern(canvas, "null");
+
+- name: 2d.pattern.repeat.case
+ testing:
+ - 2d.pattern.exact
+ code: |
+ @assert throws SYNTAX_ERR ctx.createPattern(canvas, "Repeat");
+
+- name: 2d.pattern.repeat.nullsuffix
+ testing:
+ - 2d.pattern.exact
+ code: |
+ @assert throws SYNTAX_ERR ctx.createPattern(canvas, "repeat\0");
+
+- name: 2d.pattern.modify.image1
+ testing:
+ - 2d.pattern.modify
+ images:
+ - green.png
+ code: |
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ });
+ img.src = '/images/red.png';
+ expected: green
+
+- name: 2d.pattern.modify.image2
+ testing:
+ - 2d.pattern.modify
+ images:
+ - green.png
+ code: |
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+ deferTest();
+ img.onload = t.step_func_done(function ()
+ {
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ });
+ img.src = '/images/red.png';
+ expected: green
+
+- name: 2d.pattern.modify.canvas1
+ testing:
+ - 2d.pattern.modify
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ var pattern = ctx.createPattern(canvas2, 'no-repeat');
+
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.modify.canvas2
+ testing:
+ - 2d.pattern.modify
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ var pattern = ctx.createPattern(canvas2, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.crosscanvas
+ images:
+ - green.png
+ code: |
+ var img = document.getElementById('green.png');
+
+ var pattern = document.createElement('canvas').getContext('2d').createPattern(img, 'no-repeat');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.norepeat.basic
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.norepeat.outside
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, -50, 100, 50);
+ ctx.fillRect(-100, 0, 100, 50);
+ ctx.fillRect(0, 50, 100, 50);
+ ctx.fillRect(100, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.norepeat.coord1
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.translate(50, 0);
+ ctx.fillRect(-50, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.norepeat.coord2
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green.png
+ code: |
+ var img = document.getElementById('green.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 50, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+
+ ctx.fillStyle = pattern;
+ ctx.translate(50, 0);
+ ctx.fillRect(-50, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.norepeat.coord3
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.translate(50, 25);
+ ctx.fillRect(-50, -25, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 25);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeat.basic
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green-16x16.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('green-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeat.outside
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green-16x16.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('green-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.translate(50, 25);
+ ctx.fillRect(-50, -25, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeat.coord1
+ testing:
+ - 2d.pattern.painting
+ images:
+ - rgrg-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('rgrg-256x256.png');
+ var pattern = ctx.createPattern(img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.translate(-128, -78);
+ ctx.fillRect(128, 78, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeat.coord2
+ testing:
+ - 2d.pattern.painting
+ images:
+ - ggrr-256x256.png
+ code: |
+ var img = document.getElementById('ggrr-256x256.png');
+ var pattern = ctx.createPattern(img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeat.coord3
+ testing:
+ - 2d.pattern.painting
+ images:
+ - rgrg-256x256.png
+ code: |
+ var img = document.getElementById('rgrg-256x256.png');
+ var pattern = ctx.createPattern(img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(-128, -78);
+ ctx.fillRect(128, 78, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeatx.basic
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 16);
+
+ var img = document.getElementById('green-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-x');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeatx.outside
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-x');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 16);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeatx.coord1
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-x');
+ ctx.fillStyle = pattern;
+ ctx.translate(0, 16);
+ ctx.fillRect(0, -16, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 16);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeaty.basic
+ testing:
+ - 2d.pattern.painting
+ images:
+ - green-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 16, 50);
+
+ var img = document.getElementById('green-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-y');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeaty.outside
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-y');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 16, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.repeaty.coord1
+ testing:
+ - 2d.pattern.painting
+ images:
+ - red-16x16.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('red-16x16.png');
+ var pattern = ctx.createPattern(img, 'repeat-y');
+ ctx.fillStyle = pattern;
+ ctx.translate(48, 0);
+ ctx.fillRect(-48, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 16, 50);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.orientation.image
+ desc: Image patterns do not get flipped when painted
+ testing:
+ - 2d.pattern.painting
+ images:
+ - rrgg-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var img = document.getElementById('rrgg-256x256.png');
+ var pattern = ctx.createPattern(img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.save();
+ ctx.translate(0, -103);
+ ctx.fillRect(0, 103, 100, 50);
+ ctx.restore();
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 25);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.pattern.paint.orientation.canvas
+ desc: Canvas patterns do not get flipped when painted
+ testing:
+ - 2d.pattern.painting
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 25);
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 25, 100, 25);
+
+ var pattern = ctx.createPattern(canvas2, 'no-repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 25);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.pattern.animated.gif
+ desc: createPattern() of an animated GIF draws the first frame
+ testing:
+ - 2d.pattern.animated.image
+ images:
+ - anim-gr.gif
+ code: |
+ deferTest();
+ setTimeout(function () {
+ var pattern = ctx.createPattern(document.getElementById('anim-gr.gif'), 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 50, 50);
+ setTimeout(t.step_func_done(function () {
+ ctx.fillRect(50, 0, 50, 50);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 250);
+ }, 250);
+ expected: green
+
+
+
+
+- name: 2d.line.defaults
+ testing:
+ - 2d.lineWidth.default
+ - 2d.lineCap.default
+ - 2d.lineJoin.default
+ - 2d.miterLimit.default
+ code: |
+ @assert ctx.lineWidth === 1;
+ @assert ctx.lineCap === 'butt';
+ @assert ctx.lineJoin === 'miter';
+ @assert ctx.miterLimit === 10;
+
+- name: 2d.line.width.basic
+ desc: lineWidth determines the width of line strokes
+ testing:
+ - 2d.lineWidth
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 20;
+ // Draw a green line over a red box, to check the line is not too small
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(15, 15, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(25, 15);
+ ctx.lineTo(25, 35);
+ ctx.stroke();
+
+ // Draw a green box over a red line, to check the line is not too large
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(75, 15);
+ ctx.lineTo(75, 35);
+ ctx.stroke();
+ ctx.fillRect(65, 15, 20, 20);
+
+ @assert pixel 14,25 == 0,255,0,255;
+ @assert pixel 15,25 == 0,255,0,255;
+ @assert pixel 16,25 == 0,255,0,255;
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 34,25 == 0,255,0,255;
+ @assert pixel 35,25 == 0,255,0,255;
+ @assert pixel 36,25 == 0,255,0,255;
+
+ @assert pixel 64,25 == 0,255,0,255;
+ @assert pixel 65,25 == 0,255,0,255;
+ @assert pixel 66,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ @assert pixel 84,25 == 0,255,0,255;
+ @assert pixel 85,25 == 0,255,0,255;
+ @assert pixel 86,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.width.transformed
+ desc: Line stroke widths are affected by scale transformations
+ testing:
+ - 2d.lineWidth
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 4;
+ // Draw a green line over a red box, to check the line is not too small
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(15, 15, 20, 20);
+ ctx.save();
+ ctx.scale(5, 1);
+ ctx.beginPath();
+ ctx.moveTo(5, 15);
+ ctx.lineTo(5, 35);
+ ctx.stroke();
+ ctx.restore();
+
+ // Draw a green box over a red line, to check the line is not too large
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.save();
+ ctx.scale(-5, 1);
+ ctx.beginPath();
+ ctx.moveTo(-15, 15);
+ ctx.lineTo(-15, 35);
+ ctx.stroke();
+ ctx.restore();
+ ctx.fillRect(65, 15, 20, 20);
+
+ @assert pixel 14,25 == 0,255,0,255;
+ @assert pixel 15,25 == 0,255,0,255;
+ @assert pixel 16,25 == 0,255,0,255;
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 34,25 == 0,255,0,255;
+ @assert pixel 35,25 == 0,255,0,255;
+ @assert pixel 36,25 == 0,255,0,255;
+
+ @assert pixel 64,25 == 0,255,0,255;
+ @assert pixel 65,25 == 0,255,0,255;
+ @assert pixel 66,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ @assert pixel 84,25 == 0,255,0,255;
+ @assert pixel 85,25 == 0,255,0,255;
+ @assert pixel 86,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.width.scaledefault
+ desc: Default lineWidth strokes are affected by scale transformations
+ testing:
+ - 2d.lineWidth
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.scale(50, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.moveTo(0, 0.5);
+ ctx.lineTo(2, 0.5);
+ ctx.stroke();
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ @assert pixel 50,5 == 0,255,0,255;
+ @assert pixel 50,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.width.valid
+ desc: Setting lineWidth to valid values works
+ testing:
+ - 2d.lineWidth.set
+ - 2d.lineWidth.get
+ code: |
+ ctx.lineWidth = 1.5;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = "1e1";
+ @assert ctx.lineWidth === 10;
+
+ ctx.lineWidth = 1/1024;
+ @assert ctx.lineWidth === 1/1024;
+
+ ctx.lineWidth = 1000;
+ @assert ctx.lineWidth === 1000;
+
+- name: 2d.line.width.invalid
+ desc: Setting lineWidth to invalid values is ignored
+ testing:
+ - 2d.lineWidth.invalid
+ code: |
+ ctx.lineWidth = 1.5;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = 1.5;
+ ctx.lineWidth = 0;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = 1.5;
+ ctx.lineWidth = -1;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = 1.5;
+ ctx.lineWidth = Infinity;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = 1.5;
+ ctx.lineWidth = -Infinity;
+ @assert ctx.lineWidth === 1.5;
+
+ ctx.lineWidth = 1.5;
+ ctx.lineWidth = NaN;
+ @assert ctx.lineWidth === 1.5;
+
+- name: 2d.line.cap.butt
+ desc: lineCap 'butt' is rendered correctly
+ testing:
+ - 2d.lineCap.butt
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineCap = 'butt';
+ ctx.lineWidth = 20;
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(15, 15, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(25, 15);
+ ctx.lineTo(25, 35);
+ ctx.stroke();
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(75, 15);
+ ctx.lineTo(75, 35);
+ ctx.stroke();
+ ctx.fillRect(65, 15, 20, 20);
+
+ @assert pixel 25,14 == 0,255,0,255;
+ @assert pixel 25,15 == 0,255,0,255;
+ @assert pixel 25,16 == 0,255,0,255;
+ @assert pixel 25,34 == 0,255,0,255;
+ @assert pixel 25,35 == 0,255,0,255;
+ @assert pixel 25,36 == 0,255,0,255;
+
+ @assert pixel 75,14 == 0,255,0,255;
+ @assert pixel 75,15 == 0,255,0,255;
+ @assert pixel 75,16 == 0,255,0,255;
+ @assert pixel 75,34 == 0,255,0,255;
+ @assert pixel 75,35 == 0,255,0,255;
+ @assert pixel 75,36 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.cap.round
+ desc: lineCap 'round' is rendered correctly
+ testing:
+ - 2d.lineCap.round
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var tol = 1; // tolerance to avoid antialiasing artifacts
+
+ ctx.lineCap = 'round';
+ ctx.lineWidth = 20;
+
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+
+ ctx.beginPath();
+ ctx.moveTo(35-tol, 15);
+ ctx.arc(25, 15, 10-tol, 0, Math.PI, true);
+ ctx.arc(25, 35, 10-tol, Math.PI, 0, true);
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(25, 15);
+ ctx.lineTo(25, 35);
+ ctx.stroke();
+
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+
+ ctx.beginPath();
+ ctx.moveTo(75, 15);
+ ctx.lineTo(75, 35);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(85+tol, 15);
+ ctx.arc(75, 15, 10+tol, 0, Math.PI, true);
+ ctx.arc(75, 35, 10+tol, Math.PI, 0, true);
+ ctx.fill();
+
+ @assert pixel 17,6 == 0,255,0,255;
+ @assert pixel 25,6 == 0,255,0,255;
+ @assert pixel 32,6 == 0,255,0,255;
+ @assert pixel 17,43 == 0,255,0,255;
+ @assert pixel 25,43 == 0,255,0,255;
+ @assert pixel 32,43 == 0,255,0,255;
+
+ @assert pixel 67,6 == 0,255,0,255;
+ @assert pixel 75,6 == 0,255,0,255;
+ @assert pixel 82,6 == 0,255,0,255;
+ @assert pixel 67,43 == 0,255,0,255;
+ @assert pixel 75,43 == 0,255,0,255;
+ @assert pixel 82,43 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.cap.square
+ desc: lineCap 'square' is rendered correctly
+ testing:
+ - 2d.lineCap.square
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineCap = 'square';
+ ctx.lineWidth = 20;
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(15, 5, 20, 40);
+ ctx.beginPath();
+ ctx.moveTo(25, 15);
+ ctx.lineTo(25, 35);
+ ctx.stroke();
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(75, 15);
+ ctx.lineTo(75, 35);
+ ctx.stroke();
+ ctx.fillRect(65, 5, 20, 40);
+
+ @assert pixel 25,4 == 0,255,0,255;
+ @assert pixel 25,5 == 0,255,0,255;
+ @assert pixel 25,6 == 0,255,0,255;
+ @assert pixel 25,44 == 0,255,0,255;
+ @assert pixel 25,45 == 0,255,0,255;
+ @assert pixel 25,46 == 0,255,0,255;
+
+ @assert pixel 75,4 == 0,255,0,255;
+ @assert pixel 75,5 == 0,255,0,255;
+ @assert pixel 75,6 == 0,255,0,255;
+ @assert pixel 75,44 == 0,255,0,255;
+ @assert pixel 75,45 == 0,255,0,255;
+ @assert pixel 75,46 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.cap.open
+ desc: Line caps are drawn at the corners of an unclosed rectangle
+ testing:
+ - 2d.lineCap.end
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineCap = 'square';
+ ctx.lineWidth = 400;
+
+ ctx.beginPath();
+ ctx.moveTo(200, 200);
+ ctx.lineTo(200, 1000);
+ ctx.lineTo(1000, 1000);
+ ctx.lineTo(1000, 200);
+ ctx.lineTo(200, 200);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.cap.closed
+ desc: Line caps are not drawn at the corners of an unclosed rectangle
+ testing:
+ - 2d.lineCap.end
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineCap = 'square';
+ ctx.lineWidth = 400;
+
+ ctx.beginPath();
+ ctx.moveTo(200, 200);
+ ctx.lineTo(200, 1000);
+ ctx.lineTo(1000, 1000);
+ ctx.lineTo(1000, 200);
+ ctx.closePath();
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.cap.valid
+ desc: Setting lineCap to valid values works
+ testing:
+ - 2d.lineCap.set
+ - 2d.lineCap.get
+ code: |
+ ctx.lineCap = 'butt'
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'round';
+ @assert ctx.lineCap === 'round';
+
+ ctx.lineCap = 'square';
+ @assert ctx.lineCap === 'square';
+
+- name: 2d.line.cap.invalid
+ desc: Setting lineCap to invalid values is ignored
+ testing:
+ - 2d.lineCap.invalid
+ code: |
+ ctx.lineCap = 'butt'
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = 'invalid';
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = 'ROUND';
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = 'round\0';
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = 'round ';
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = "";
+ @assert ctx.lineCap === 'butt';
+
+ ctx.lineCap = 'butt';
+ ctx.lineCap = 'bevel';
+ @assert ctx.lineCap === 'butt';
+
+- name: 2d.line.join.bevel
+ desc: lineJoin 'bevel' is rendered correctly
+ testing:
+ - 2d.lineJoin.common
+ - 2d.lineJoin.bevel
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var tol = 1; // tolerance to avoid antialiasing artifacts
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineWidth = 20;
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+
+ ctx.fillRect(10, 10, 20, 20);
+ ctx.fillRect(20, 20, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(30, 20);
+ ctx.lineTo(40-tol, 20);
+ ctx.lineTo(30, 10+tol);
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(10, 20);
+ ctx.lineTo(30, 20);
+ ctx.lineTo(30, 40);
+ ctx.stroke();
+
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+
+ ctx.beginPath();
+ ctx.moveTo(60, 20);
+ ctx.lineTo(80, 20);
+ ctx.lineTo(80, 40);
+ ctx.stroke();
+
+ ctx.fillRect(60, 10, 20, 20);
+ ctx.fillRect(70, 20, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(80, 20);
+ ctx.lineTo(90+tol, 20);
+ ctx.lineTo(80, 10-tol);
+ ctx.fill();
+
+ @assert pixel 34,16 == 0,255,0,255;
+ @assert pixel 34,15 == 0,255,0,255;
+ @assert pixel 35,15 == 0,255,0,255;
+ @assert pixel 36,15 == 0,255,0,255;
+ @assert pixel 36,14 == 0,255,0,255;
+
+ @assert pixel 84,16 == 0,255,0,255;
+ @assert pixel 84,15 == 0,255,0,255;
+ @assert pixel 85,15 == 0,255,0,255;
+ @assert pixel 86,15 == 0,255,0,255;
+ @assert pixel 86,14 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.round
+ desc: lineJoin 'round' is rendered correctly
+ testing:
+ - 2d.lineJoin.round
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var tol = 1; // tolerance to avoid antialiasing artifacts
+
+ ctx.lineJoin = 'round';
+ ctx.lineWidth = 20;
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+
+ ctx.fillRect(10, 10, 20, 20);
+ ctx.fillRect(20, 20, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(30, 20);
+ ctx.arc(30, 20, 10-tol, 0, 2*Math.PI, true);
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(10, 20);
+ ctx.lineTo(30, 20);
+ ctx.lineTo(30, 40);
+ ctx.stroke();
+
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+
+ ctx.beginPath();
+ ctx.moveTo(60, 20);
+ ctx.lineTo(80, 20);
+ ctx.lineTo(80, 40);
+ ctx.stroke();
+
+ ctx.fillRect(60, 10, 20, 20);
+ ctx.fillRect(70, 20, 20, 20);
+ ctx.beginPath();
+ ctx.moveTo(80, 20);
+ ctx.arc(80, 20, 10+tol, 0, 2*Math.PI, true);
+ ctx.fill();
+
+ @assert pixel 36,14 == 0,255,0,255;
+ @assert pixel 36,13 == 0,255,0,255;
+ @assert pixel 37,13 == 0,255,0,255;
+ @assert pixel 38,13 == 0,255,0,255;
+ @assert pixel 38,12 == 0,255,0,255;
+
+ @assert pixel 86,14 == 0,255,0,255;
+ @assert pixel 86,13 == 0,255,0,255;
+ @assert pixel 87,13 == 0,255,0,255;
+ @assert pixel 88,13 == 0,255,0,255;
+ @assert pixel 88,12 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.miter
+ desc: lineJoin 'miter' is rendered correctly
+ testing:
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineJoin = 'miter';
+ ctx.lineWidth = 20;
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+
+ ctx.fillRect(10, 10, 30, 20);
+ ctx.fillRect(20, 10, 20, 30);
+
+ ctx.beginPath();
+ ctx.moveTo(10, 20);
+ ctx.lineTo(30, 20);
+ ctx.lineTo(30, 40);
+ ctx.stroke();
+
+
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+
+ ctx.beginPath();
+ ctx.moveTo(60, 20);
+ ctx.lineTo(80, 20);
+ ctx.lineTo(80, 40);
+ ctx.stroke();
+
+ ctx.fillRect(60, 10, 30, 20);
+ ctx.fillRect(70, 10, 20, 30);
+
+ @assert pixel 38,12 == 0,255,0,255;
+ @assert pixel 39,11 == 0,255,0,255;
+ @assert pixel 40,10 == 0,255,0,255;
+ @assert pixel 41,9 == 0,255,0,255;
+ @assert pixel 42,8 == 0,255,0,255;
+
+ @assert pixel 88,12 == 0,255,0,255;
+ @assert pixel 89,11 == 0,255,0,255;
+ @assert pixel 90,10 == 0,255,0,255;
+ @assert pixel 91,9 == 0,255,0,255;
+ @assert pixel 92,8 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.open
+ desc: Line joins are not drawn at the corner of an unclosed rectangle
+ testing:
+ - 2d.lineJoin.joins
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineJoin = 'miter';
+ ctx.lineWidth = 200;
+
+ ctx.beginPath();
+ ctx.moveTo(100, 50);
+ ctx.lineTo(100, 1000);
+ ctx.lineTo(1000, 1000);
+ ctx.lineTo(1000, 50);
+ ctx.lineTo(100, 50);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.closed
+ desc: Line joins are drawn at the corner of a closed rectangle
+ testing:
+ - 2d.lineJoin.joinclosed
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineJoin = 'miter';
+ ctx.lineWidth = 200;
+
+ ctx.beginPath();
+ ctx.moveTo(100, 50);
+ ctx.lineTo(100, 1000);
+ ctx.lineTo(1000, 1000);
+ ctx.lineTo(1000, 50);
+ ctx.closePath();
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.parallel
+ desc: Line joins are drawn at 180-degree joins
+ testing:
+ - 2d.lineJoin.joins
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 300;
+ ctx.lineJoin = 'round';
+ ctx.beginPath();
+ ctx.moveTo(-100, 25);
+ ctx.lineTo(0, 25);
+ ctx.lineTo(-100, 25);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.join.valid
+ desc: Setting lineJoin to valid values works
+ testing:
+ - 2d.lineJoin.set
+ - 2d.lineJoin.get
+ code: |
+ ctx.lineJoin = 'bevel'
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'round';
+ @assert ctx.lineJoin === 'round';
+
+ ctx.lineJoin = 'miter';
+ @assert ctx.lineJoin === 'miter';
+
+- name: 2d.line.join.invalid
+ desc: Setting lineJoin to invalid values is ignored
+ testing:
+ - 2d.lineJoin.invalid
+ code: |
+ ctx.lineJoin = 'bevel'
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = 'invalid';
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = 'ROUND';
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = 'round\0';
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = 'round ';
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = "";
+ @assert ctx.lineJoin === 'bevel';
+
+ ctx.lineJoin = 'bevel';
+ ctx.lineJoin = 'butt';
+ @assert ctx.lineJoin === 'bevel';
+
+- name: 2d.line.miter.exceeded
+ desc: Miter joins are not drawn when the miter limit is exceeded
+ testing:
+ - 2d.lineJoin.miterLimit
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 400;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#f00';
+ ctx.miterLimit = 1.414;
+ ctx.beginPath();
+ ctx.moveTo(200, 1000);
+ ctx.lineTo(200, 200);
+ ctx.lineTo(1000, 201); // slightly non-right-angle to avoid being a special case
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.acute
+ desc: Miter joins are drawn correctly with acute angles
+ testing:
+ - 2d.lineJoin.miterLimit
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#0f0';
+ ctx.miterLimit = 2.614;
+ ctx.beginPath();
+ ctx.moveTo(100, 1000);
+ ctx.lineTo(100, 100);
+ ctx.lineTo(1000, 1000);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.miterLimit = 2.613;
+ ctx.beginPath();
+ ctx.moveTo(100, 1000);
+ ctx.lineTo(100, 100);
+ ctx.lineTo(1000, 1000);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.obtuse
+ desc: Miter joins are drawn correctly with obtuse angles
+ testing:
+ - 2d.lineJoin.miterLimit
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 1600;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#0f0';
+ ctx.miterLimit = 1.083;
+ ctx.beginPath();
+ ctx.moveTo(800, 10000);
+ ctx.lineTo(800, 300);
+ ctx.lineTo(10000, -8900);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.miterLimit = 1.082;
+ ctx.beginPath();
+ ctx.moveTo(800, 10000);
+ ctx.lineTo(800, 300);
+ ctx.lineTo(10000, -8900);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.rightangle
+ desc: Miter joins are not drawn when the miter limit is exceeded, on exact right angles
+ testing:
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 400;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#f00';
+ ctx.miterLimit = 1.414;
+ ctx.beginPath();
+ ctx.moveTo(200, 1000);
+ ctx.lineTo(200, 200);
+ ctx.lineTo(1000, 200);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.lineedge
+ desc: Miter joins are not drawn when the miter limit is exceeded at the corners of a zero-height rectangle
+ testing:
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#f00';
+ ctx.miterLimit = 1.414;
+ ctx.beginPath();
+ ctx.strokeRect(100, 25, 200, 0);
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.within
+ desc: Miter joins are drawn when the miter limit is not quite exceeded
+ testing:
+ - 2d.lineJoin.miter
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 400;
+ ctx.lineJoin = 'miter';
+
+ ctx.strokeStyle = '#0f0';
+ ctx.miterLimit = 1.416;
+ ctx.beginPath();
+ ctx.moveTo(200, 1000);
+ ctx.lineTo(200, 200);
+ ctx.lineTo(1000, 201);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.miter.valid
+ desc: Setting miterLimit to valid values works
+ testing:
+ - 2d.miterLimit.set
+ - 2d.miterLimit.get
+ code: |
+ ctx.miterLimit = 1.5;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = "1e1";
+ @assert ctx.miterLimit === 10;
+
+ ctx.miterLimit = 1/1024;
+ @assert ctx.miterLimit === 1/1024;
+
+ ctx.miterLimit = 1000;
+ @assert ctx.miterLimit === 1000;
+
+- name: 2d.line.miter.invalid
+ desc: Setting miterLimit to invalid values is ignored
+ testing:
+ - 2d.miterLimit.invalid
+ code: |
+ ctx.miterLimit = 1.5;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = 1.5;
+ ctx.miterLimit = 0;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = 1.5;
+ ctx.miterLimit = -1;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = 1.5;
+ ctx.miterLimit = Infinity;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = 1.5;
+ ctx.miterLimit = -Infinity;
+ @assert ctx.miterLimit === 1.5;
+
+ ctx.miterLimit = 1.5;
+ ctx.miterLimit = NaN;
+ @assert ctx.miterLimit === 1.5;
+
+- name: 2d.line.cross
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'bevel';
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(110, 50);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(100, 60);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.line.union
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 24);
+ ctx.lineTo(100, 25);
+ ctx.lineTo(0, 26);
+ ctx.closePath();
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 25,1 == 0,255,0,255;
+ @assert pixel 48,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 25,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ expected: green
+
+
+
+
+
+
+
+- name: 2d.shadow.attributes.shadowBlur.initial
+ testing:
+ - 2d.shadow.blur.get
+ - 2d.shadow.blur.initial
+ code: |
+ @assert ctx.shadowBlur === 0;
+
+- name: 2d.shadow.attributes.shadowBlur.valid
+ testing:
+ - 2d.shadow.blur.get
+ - 2d.shadow.blur.set
+ code: |
+ ctx.shadowBlur = 1;
+ @assert ctx.shadowBlur === 1;
+
+ ctx.shadowBlur = 0.5;
+ @assert ctx.shadowBlur === 0.5;
+
+ ctx.shadowBlur = 1e6;
+ @assert ctx.shadowBlur === 1e6;
+
+ ctx.shadowBlur = 0;
+ @assert ctx.shadowBlur === 0;
+
+- name: 2d.shadow.attributes.shadowBlur.invalid
+ testing:
+ - 2d.shadow.blur.invalid
+ code: |
+ ctx.shadowBlur = 1;
+ ctx.shadowBlur = -2;
+ @assert ctx.shadowBlur === 1;
+
+ ctx.shadowBlur = 1;
+ ctx.shadowBlur = Infinity;
+ @assert ctx.shadowBlur === 1;
+
+ ctx.shadowBlur = 1;
+ ctx.shadowBlur = -Infinity;
+ @assert ctx.shadowBlur === 1;
+
+ ctx.shadowBlur = 1;
+ ctx.shadowBlur = NaN;
+ @assert ctx.shadowBlur === 1;
+
+- name: 2d.shadow.attributes.shadowOffset.initial
+ testing:
+ - 2d.shadow.offset.initial
+ code: |
+ @assert ctx.shadowOffsetX === 0;
+ @assert ctx.shadowOffsetY === 0;
+
+- name: 2d.shadow.attributes.shadowOffset.valid
+ testing:
+ - 2d.shadow.offset.get
+ - 2d.shadow.offset.set
+ code: |
+ ctx.shadowOffsetX = 1;
+ ctx.shadowOffsetY = 2;
+ @assert ctx.shadowOffsetX === 1;
+ @assert ctx.shadowOffsetY === 2;
+
+ ctx.shadowOffsetX = 0.5;
+ ctx.shadowOffsetY = 0.25;
+ @assert ctx.shadowOffsetX === 0.5;
+ @assert ctx.shadowOffsetY === 0.25;
+
+ ctx.shadowOffsetX = -0.5;
+ ctx.shadowOffsetY = -0.25;
+ @assert ctx.shadowOffsetX === -0.5;
+ @assert ctx.shadowOffsetY === -0.25;
+
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+ @assert ctx.shadowOffsetX === 0;
+ @assert ctx.shadowOffsetY === 0;
+
+ ctx.shadowOffsetX = 1e6;
+ ctx.shadowOffsetY = 1e6;
+ @assert ctx.shadowOffsetX === 1e6;
+ @assert ctx.shadowOffsetY === 1e6;
+
+- name: 2d.shadow.attributes.shadowOffset.invalid
+ testing:
+ - 2d.shadow.offset.invalid
+ code: |
+ ctx.shadowOffsetX = 1;
+ ctx.shadowOffsetY = 2;
+ ctx.shadowOffsetX = Infinity;
+ ctx.shadowOffsetY = Infinity;
+ @assert ctx.shadowOffsetX === 1;
+ @assert ctx.shadowOffsetY === 2;
+
+ ctx.shadowOffsetX = 1;
+ ctx.shadowOffsetY = 2;
+ ctx.shadowOffsetX = -Infinity;
+ ctx.shadowOffsetY = -Infinity;
+ @assert ctx.shadowOffsetX === 1;
+ @assert ctx.shadowOffsetY === 2;
+
+ ctx.shadowOffsetX = 1;
+ ctx.shadowOffsetY = 2;
+ ctx.shadowOffsetX = NaN;
+ ctx.shadowOffsetY = NaN;
+ @assert ctx.shadowOffsetX === 1;
+ @assert ctx.shadowOffsetY === 2;
+
+- name: 2d.shadow.attributes.shadowColor.initial
+ testing:
+ - 2d.shadow.color.initial
+ code: |
+ @assert ctx.shadowColor === 'rgba(0, 0, 0, 0)';
+
+- name: 2d.shadow.attributes.shadowColor.valid
+ testing:
+ - 2d.shadow.color.get
+ - 2d.shadow.color.set
+ code: |
+ ctx.shadowColor = 'lime';
+ @assert ctx.shadowColor === '#00ff00';
+
+ ctx.shadowColor = 'RGBA(0,255, 0,0)';
+ @assert ctx.shadowColor === 'rgba(0, 255, 0, 0)';
+
+- name: 2d.shadow.attributes.shadowColor.invalid
+ testing:
+ - 2d.shadow.color.invalid
+ code: |
+ ctx.shadowColor = '#00ff00';
+ ctx.shadowColor = 'bogus';
+ @assert ctx.shadowColor === '#00ff00';
+
+ ctx.shadowColor = '#00ff00';
+ ctx.shadowColor = 'red bogus';
+ @assert ctx.shadowColor === '#00ff00';
+
+ ctx.shadowColor = '#00ff00';
+ ctx.shadowColor = ctx;
+ @assert ctx.shadowColor === '#00ff00';
+
+ ctx.shadowColor = '#00ff00';
+ ctx.shadowColor = undefined;
+ @assert ctx.shadowColor === '#00ff00';
+
+- name: 2d.shadow.enable.off.1
+ desc: Shadows are not drawn when only shadowColor is set
+ testing:
+ - 2d.shadow.enable
+ - 2d.shadow.render
+ code: |
+ ctx.shadowColor = '#f00';
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.enable.off.2
+ desc: Shadows are not drawn when only shadowColor is set
+ testing:
+ - 2d.shadow.enable
+ - 2d.shadow.render
+ code: |
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#f00';
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.enable.blur
+ desc: Shadows are drawn if shadowBlur is set
+ testing:
+ - 2d.shadow.enable
+ - 2d.shadow.render
+ code: |
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowBlur = 0.1;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.enable.x
+ desc: Shadows are drawn if shadowOffsetX is set
+ testing:
+ - 2d.shadow.enable
+ - 2d.shadow.render
+ code: |
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 0.1;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.enable.y
+ desc: Shadows are drawn if shadowOffsetY is set
+ testing:
+ - 2d.shadow.enable
+ - 2d.shadow.render
+ code: |
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 0.1;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.offset.positiveX
+ desc: Shadows can be offset with positive x
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 50;
+ ctx.fillRect(0, 0, 50, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.offset.negativeX
+ desc: Shadows can be offset with negative x
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = -50;
+ ctx.fillRect(50, 0, 50, 50);
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.offset.positiveY
+ desc: Shadows can be offset with positive y
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 25;
+ ctx.fillRect(0, 0, 100, 25);
+ @assert pixel 50,12 == 0,255,0,255;
+ @assert pixel 50,37 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.offset.negativeY
+ desc: Shadows can be offset with negative y
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = -25;
+ ctx.fillRect(0, 25, 100, 25);
+ @assert pixel 50,12 == 0,255,0,255;
+ @assert pixel 50,37 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.outside
+ desc: Shadows of shapes outside the visible area can be offset onto the visible area
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 100;
+ ctx.fillRect(-100, 0, 25, 50);
+ ctx.shadowOffsetX = -100;
+ ctx.fillRect(175, 0, 25, 50);
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 100;
+ ctx.fillRect(25, -100, 50, 25);
+ ctx.shadowOffsetY = -100;
+ ctx.fillRect(25, 125, 50, 25);
+ @assert pixel 12,25 == 0,255,0,255;
+ @assert pixel 87,25 == 0,255,0,255;
+ @assert pixel 50,12 == 0,255,0,255;
+ @assert pixel 50,37 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.clip.1
+ desc: Shadows of clipped shapes are still drawn within the clipping region
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(50, 0, 50, 50);
+ ctx.clip();
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 50;
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.restore();
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.clip.2
+ desc: Shadows are not drawn outside the clipping region
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, 0, 50, 50);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(0, 0, 50, 50);
+ ctx.clip();
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetX = 50;
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.restore();
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.clip.3
+ desc: Shadows of clipped shapes are still drawn within the clipping region
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, 0, 50, 50);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(0, 0, 50, 50);
+ ctx.clip();
+ ctx.fillStyle = '#f00';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 50;
+ ctx.fillRect(-50, 0, 50, 50);
+ ctx.restore();
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.basic
+ desc: Shadows are drawn for strokes
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.beginPath();
+ ctx.lineWidth = 50;
+ ctx.moveTo(0, -25);
+ ctx.lineTo(100, -25);
+ ctx.stroke();
+
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.cap.1
+ desc: Shadows are not drawn for areas outside stroke caps
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetY = 50;
+ ctx.beginPath();
+ ctx.lineWidth = 50;
+ ctx.lineCap = 'butt';
+ ctx.moveTo(-50, -25);
+ ctx.lineTo(0, -25);
+ ctx.moveTo(100, -25);
+ ctx.lineTo(150, -25);
+ ctx.stroke();
+
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.cap.2
+ desc: Shadows are drawn for stroke caps
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.beginPath();
+ ctx.lineWidth = 50;
+ ctx.lineCap = 'square';
+ ctx.moveTo(25, -25);
+ ctx.lineTo(75, -25);
+ ctx.stroke();
+
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.join.1
+ desc: Shadows are not drawn for areas outside stroke joins
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetX = 100;
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'bevel';
+ ctx.beginPath();
+ ctx.moveTo(-200, -50);
+ ctx.lineTo(-150, -50);
+ ctx.lineTo(-151, -100);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.join.2
+ desc: Shadows are drawn for stroke joins
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetX = 100;
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'miter';
+ ctx.beginPath();
+ ctx.moveTo(-200, -50);
+ ctx.lineTo(-150, -50);
+ ctx.lineTo(-151, -100);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.stroke.join.3
+ desc: Shadows are drawn for stroke joins respecting miter limit
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetX = 100;
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'miter';
+ ctx.miterLimit = 0.1;
+ ctx.beginPath();
+ ctx.moveTo(-200, -50);
+ ctx.lineTo(-150, -50);
+ ctx.lineTo(-151, -100); // (not an exact right angle, to avoid some other bug in Firefox 3)
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 48,48 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.image.basic
+ desc: Shadows are drawn for images
+ testing:
+ - 2d.shadow.render
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.drawImage(document.getElementById('red.png'), 0, -50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.image.transparent.1
+ desc: Shadows are not drawn for transparent images
+ testing:
+ - 2d.shadow.render
+ images:
+ - transparent.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetY = 50;
+ ctx.drawImage(document.getElementById('transparent.png'), 0, -50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.image.transparent.2
+ desc: Shadows are not drawn for transparent parts of images
+ testing:
+ - 2d.shadow.render
+ images:
+ - redtransparent.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.drawImage(document.getElementById('redtransparent.png'), 50, -50);
+ ctx.shadowColor = '#f00';
+ ctx.drawImage(document.getElementById('redtransparent.png'), -50, -50);
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.image.alpha
+ desc: Shadows are drawn correctly for partially-transparent images
+ testing:
+ - 2d.shadow.render
+ images:
+ - transparent50.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#00f';
+ ctx.drawImage(document.getElementById('transparent50.png'), 0, -50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.image.section
+ desc: Shadows are not drawn for areas outside image source rectangles
+ testing:
+ - 2d.shadow.render
+ images:
+ - redtransparent.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#f00';
+ ctx.drawImage(document.getElementById('redtransparent.png'), 50, 0, 50, 50, 0, -50, 50, 50);
+
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.image.scale
+ desc: Shadows are drawn correctly for scaled images
+ testing:
+ - 2d.shadow.render
+ images:
+ - redtransparent.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.drawImage(document.getElementById('redtransparent.png'), 0, 0, 100, 50, -10, -50, 240, 50);
+
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.canvas.basic
+ desc: Shadows are drawn for canvases
+ testing:
+ - 2d.shadow.render
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.drawImage(canvas2, 0, -50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.canvas.transparent.1
+ desc: Shadows are not drawn for transparent canvases
+ testing:
+ - 2d.shadow.render
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetY = 50;
+ ctx.drawImage(canvas2, 0, -50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.canvas.transparent.2
+ desc: Shadows are not drawn for transparent parts of canvases
+ testing:
+ - 2d.shadow.render
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#f00';
+ ctx2.fillRect(0, 0, 50, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.drawImage(canvas2, 50, -50);
+ ctx.shadowColor = '#f00';
+ ctx.drawImage(canvas2, -50, -50);
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.canvas.alpha
+ desc: Shadows are drawn correctly for partially-transparent canvases
+ testing:
+ - 2d.shadow.render
+ images:
+ - transparent50.png
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = 'rgba(255, 0, 0, 0.5)';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#00f';
+ ctx.drawImage(canvas2, 0, -50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.pattern.basic
+ desc: Shadows are drawn for fill patterns
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ images:
+ - red.png
+ code: |
+ var pattern = ctx.createPattern(document.getElementById('red.png'), 'repeat');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.pattern.transparent.1
+ desc: Shadows are not drawn for transparent fill patterns
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ images:
+ - transparent.png
+ code: |
+ var pattern = ctx.createPattern(document.getElementById('transparent.png'), 'repeat');
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetY = 50;
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.pattern.transparent.2
+ desc: Shadows are not drawn for transparent parts of fill patterns
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ images:
+ - redtransparent.png
+ code: |
+ var pattern = ctx.createPattern(document.getElementById('redtransparent.png'), 'repeat');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.pattern.alpha
+ desc: Shadows are drawn correctly for partially-transparent fill patterns
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ images:
+ - transparent50.png
+ code: |
+ var pattern = ctx.createPattern(document.getElementById('transparent50.png'), 'repeat');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#00f';
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.gradient.basic
+ desc: Shadows are drawn for gradient fills
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ code: |
+ var gradient = ctx.createLinearGradient(0, 0, 100, 0);
+ gradient.addColorStop(0, '#f00');
+ gradient.addColorStop(1, '#f00');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowOffsetY = 50;
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.gradient.transparent.1
+ desc: Shadows are not drawn for transparent gradient fills
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ code: |
+ var gradient = ctx.createLinearGradient(0, 0, 100, 0);
+ gradient.addColorStop(0, 'rgba(0,0,0,0)');
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetY = 50;
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.gradient.transparent.2
+ desc: Shadows are not drawn for transparent parts of gradient fills
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ code: |
+ var gradient = ctx.createLinearGradient(0, 0, 100, 0);
+ gradient.addColorStop(0, '#f00');
+ gradient.addColorStop(0.499, '#f00');
+ gradient.addColorStop(0.5, 'rgba(0,0,0,0)');
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 25,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 75,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.gradient.alpha
+ desc: Shadows are drawn correctly for partially-transparent gradient fills
+ testing:
+ - 2d.shadow.render
+ # http://bugs.webkit.org/show_bug.cgi?id=15266
+ code: |
+ var gradient = ctx.createLinearGradient(0, 0, 100, 0);
+ gradient.addColorStop(0, 'rgba(255,0,0,0.5)');
+ gradient.addColorStop(1, 'rgba(255,0,0,0.5)');
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#00f';
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.transform.1
+ desc: Shadows take account of transformations
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.translate(100, 100);
+ ctx.fillRect(-100, -150, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.transform.2
+ desc: Shadow offsets are not affected by transformations
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowOffsetY = 50;
+ ctx.shadowColor = '#0f0';
+ ctx.rotate(Math.PI)
+ ctx.fillRect(-100, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.blur.low
+ desc: Shadows look correct for small blurs
+ manual:
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#ff0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#00f';
+ ctx.shadowOffsetY = 25;
+ for (var x = 0; x < 100; ++x) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(x, 0, 1, 50);
+ ctx.clip();
+ ctx.shadowBlur = x;
+ ctx.fillRect(-200, -200, 500, 200);
+ ctx.restore();
+ }
+ expected: |
+ size 100 50
+ import math
+ cr.set_source_rgb(0, 0, 1)
+ cr.rectangle(0, 0, 1, 25)
+ cr.fill()
+ cr.set_source_rgb(1, 1, 0)
+ cr.rectangle(0, 25, 1, 25)
+ cr.fill()
+ for x in range(1, 100):
+ sigma = x/2.0
+ filter = [math.exp(-i*i / (2*sigma*sigma)) / (math.sqrt(2*math.pi)*sigma) for i in range(-24, 26)]
+ accum = [0]
+ for f in filter:
+ accum.append(accum[-1] + f)
+ for y in range(0, 50):
+ cr.set_source_rgb(accum[y], accum[y], 1-accum[y])
+ cr.rectangle(x, y, 1, 1)
+ cr.fill()
+
+- name: 2d.shadow.blur.high
+ desc: Shadows look correct for large blurs
+ manual:
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#ff0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#00f';
+ ctx.shadowOffsetY = 0;
+ ctx.shadowBlur = 100;
+ ctx.fillRect(-200, -200, 200, 400);
+ expected: |
+ size 100 50
+ import math
+ sigma = 100.0/2
+ filter = [math.exp(-i*i / (2*sigma*sigma)) / (math.sqrt(2*math.pi)*sigma) for i in range(-200, 100)]
+ accum = [0]
+ for f in filter:
+ accum.append(accum[-1] + f)
+ for x in range(0, 100):
+ cr.set_source_rgb(accum[x+200], accum[x+200], 1-accum[x+200])
+ cr.rectangle(x, 0, 1, 50)
+ cr.fill()
+
+- name: 2d.shadow.alpha.1
+ desc: Shadow colour alpha components are used
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = 'rgba(255, 0, 0, 0.01)';
+ ctx.shadowOffsetY = 50;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 0,255,0,255 +/- 4;
+ expected: green
+
+- name: 2d.shadow.alpha.2
+ desc: Shadow colour alpha components are used
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = 'rgba(0, 0, 255, 0.5)';
+ ctx.shadowOffsetY = 50;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.alpha.3
+ desc: Shadows are affected by globalAlpha
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching)
+ ctx.shadowColor = '#00f';
+ ctx.shadowOffsetY = 50;
+ ctx.globalAlpha = 0.5;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.alpha.4
+ desc: Shadows with alpha components are correctly affected by globalAlpha
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching)
+ ctx.shadowColor = 'rgba(0, 0, 255, 0.707)';
+ ctx.shadowOffsetY = 50;
+ ctx.globalAlpha = 0.707;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.alpha.5
+ desc: Shadows of shapes with alpha components are drawn correctly
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = 'rgba(64, 0, 0, 0.5)';
+ ctx.shadowColor = '#00f';
+ ctx.shadowOffsetY = 50;
+ ctx.fillRect(0, -50, 100, 50);
+
+ @assert pixel 50,25 ==~ 127,0,127,255;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0.5, 0, 0.5)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.shadow.composite.1
+ desc: Shadows are drawn using globalCompositeOperation
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'xor';
+ ctx.shadowColor = '#f00';
+ ctx.shadowOffsetX = 100;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-100, 0, 200, 50);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.composite.2
+ desc: Shadows are drawn using globalCompositeOperation
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'xor';
+ ctx.shadowColor = '#f00';
+ ctx.shadowBlur = 1;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(-10, -10, 120, 70);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.shadow.composite.3
+ desc: Areas outside shadows are drawn correctly with destination-out
+ testing:
+ - 2d.shadow.render
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'destination-out';
+ ctx.shadowColor = '#f00';
+ ctx.shadowBlur = 10;
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(200, 0, 100, 50);
+
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+
+
+
+
+
+- name: 2d.clearRect.basic
+ desc: clearRect clears to transparent black
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.clearRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.clearRect.path
+ desc: clearRect does not affect the current path
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.rect(0, 0, 100, 50);
+ ctx.clearRect(0, 0, 16, 16);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.clearRect.zero
+ desc: clearRect of zero pixels has no effect
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.clearRect(0, 0, 100, 0);
+ ctx.clearRect(0, 0, 0, 50);
+ ctx.clearRect(0, 0, 0, 0);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.clearRect.negative
+ desc: clearRect of negative sizes works
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.clearRect(0, 0, 50, 25);
+ ctx.clearRect(100, 0, -50, 25);
+ ctx.clearRect(0, 50, 50, -25);
+ ctx.clearRect(100, 50, -50, -25);
+ @assert pixel 25,12 == 0,0,0,0;
+ @assert pixel 75,12 == 0,0,0,0;
+ @assert pixel 25,37 == 0,0,0,0;
+ @assert pixel 75,37 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.clearRect.transform
+ desc: clearRect is affected by transforms
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.scale(10, 10);
+ ctx.translate(0, 5);
+ ctx.clearRect(0, -5, 10, 5);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.clearRect.globalalpha
+ desc: clearRect is not affected by globalAlpha
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalAlpha = 0.1;
+ ctx.clearRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.clearRect.globalcomposite
+ desc: clearRect is not affected by globalCompositeOperation
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.clearRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.clearRect.clip
+ desc: clearRect is affected by clipping regions
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(0, 0, 16, 16);
+ ctx.clip();
+
+ ctx.clearRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 16, 16);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.clearRect.shadow
+ desc: clearRect does not draw shadows
+ testing:
+ - 2d.clearRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#f00';
+ ctx.shadowBlur = 0;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 50;
+ ctx.clearRect(0, -50, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.clearRect.nonfinite
+ desc: clearRect() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @nonfinite ctx.clearRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.fillRect.basic
+ desc: fillRect works
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.path
+ desc: fillRect does not affect the current path
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.beginPath();
+ ctx.rect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.zero
+ desc: fillRect of zero pixels has no effect
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 0);
+ ctx.fillRect(0, 0, 0, 50);
+ ctx.fillRect(0, 0, 0, 0);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.negative
+ desc: fillRect of negative sizes works
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 25);
+ ctx.fillRect(100, 0, -50, 25);
+ ctx.fillRect(0, 50, 50, -25);
+ ctx.fillRect(100, 50, -50, -25);
+ @assert pixel 25,12 == 0,255,0,255;
+ @assert pixel 75,12 == 0,255,0,255;
+ @assert pixel 25,37 == 0,255,0,255;
+ @assert pixel 75,37 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.transform
+ desc: fillRect is affected by transforms
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.scale(10, 10);
+ ctx.translate(0, 5);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, -5, 10, 5);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+# don't bother testing globalalpha, globalcomposite because they're already heavily used by other test cases
+
+- name: 2d.fillRect.clip
+ desc: fillRect is affected by clipping regions
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(0, 0, 16, 16);
+ ctx.clip();
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 16, 16);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.shadow
+ desc: fillRect draws shadows
+ testing:
+ - 2d.fillRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.shadowColor = '#0f0';
+ ctx.shadowBlur = 0;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 50;
+ ctx.fillRect(0, -50, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.fillRect.nonfinite
+ desc: fillRect() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ @nonfinite ctx.fillRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.strokeRect.basic
+ desc: strokeRect works
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(25, 24, 50, 2);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.path
+ desc: strokeRect does not affect the current path
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.beginPath();
+ ctx.rect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 5;
+ ctx.strokeRect(0, 0, 16, 16);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.zero.1
+ desc: strokeRect of 0x0 pixels draws nothing
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 250;
+ ctx.strokeRect(50, 25, 0, 0);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.strokeRect.zero.2
+ desc: strokeRect of 0x0 pixels draws nothing, including caps and joins
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 250;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+ ctx.strokeRect(50, 25, 0, 0);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.strokeRect.zero.3
+ desc: strokeRect of Nx0 pixels draws a straight line
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(0, 25, 100, 0);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.zero.4
+ desc: strokeRect of Nx0 pixels draws a closed line with no caps
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 250;
+ ctx.lineCap = 'round';
+ ctx.strokeRect(100, 25, 100, 0);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.strokeRect.zero.5
+ desc: strokeRect of Nx0 pixels draws a closed line with joins
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 250;
+ ctx.lineJoin = 'round';
+ ctx.strokeRect(100, 25, 100, 0);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.negative
+ desc: strokeRect of negative sizes works
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 25;
+ ctx.strokeRect(12, 12, 26, 1);
+ ctx.strokeRect(88, 12, -26, 1);
+ ctx.strokeRect(12, 38, 26, -1);
+ ctx.strokeRect(88, 38, -26, -1);
+ @assert pixel 25,12 == 0,255,0,255;
+ @assert pixel 75,12 == 0,255,0,255;
+ @assert pixel 25,37 == 0,255,0,255;
+ @assert pixel 75,37 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.transform
+ desc: fillRect is affected by transforms
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.scale(10, 10);
+ ctx.translate(0, 5);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 5;
+ ctx.strokeRect(2.5, -2.6, 5, 0.2);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.globalalpha
+ desc: strokeRect is affected by globalAlpha
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.globalAlpha = 0;
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(25, 24, 50, 2);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.strokeRect.globalcomposite
+ desc: strokeRect is not affected by globalCompositeOperation
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(25, 24, 50, 2);
+ @assert pixel 50,25 == 0,0,0,0;
+ expected: clear
+
+- name: 2d.strokeRect.clip
+ desc: strokeRect is affected by clipping regions
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(0, 0, 16, 16);
+ ctx.clip();
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 16, 16);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.shadow
+ desc: strokeRect draws shadows
+ testing:
+ - 2d.strokeRect
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.shadowColor = '#0f0';
+ ctx.shadowBlur = 0;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 50;
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.strokeRect(0, -75, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.strokeRect.nonfinite
+ desc: strokeRect() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 150;
+ @nonfinite ctx.strokeRect(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.path.initial
+ testing:
+ - 2d.path.initial
+ #mozilla: { bug: TODO }
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.closePath();
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.beginPath
+ testing:
+ - 2d.path.beginPath
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.rect(0, 0, 100, 50);
+ ctx.beginPath();
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.moveTo.basic
+ testing:
+ - 2d.path.moveTo
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.rect(0, 0, 10, 50);
+ ctx.moveTo(100, 0);
+ ctx.lineTo(10, 0);
+ ctx.lineTo(10, 50);
+ ctx.lineTo(100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 90,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.moveTo.newsubpath
+ testing:
+ - 2d.path.moveTo
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.moveTo(100, 0);
+ ctx.moveTo(100, 50);
+ ctx.moveTo(0, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.moveTo.multiple
+ testing:
+ - 2d.path.moveTo
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.moveTo(0, 25);
+ ctx.moveTo(100, 25);
+ ctx.moveTo(0, 25);
+ ctx.lineTo(100, 25);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.moveTo.nonfinite
+ desc: moveTo() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.moveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.closePath.empty
+ testing:
+ - 2d.path.closePath.empty
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.closePath();
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.closePath.newline
+ testing:
+ - 2d.path.closePath.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.moveTo(-100, 25);
+ ctx.lineTo(-100, -100);
+ ctx.lineTo(200, -100);
+ ctx.lineTo(200, 25);
+ ctx.closePath();
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.closePath.nextpoint
+ testing:
+ - 2d.path.closePath.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.moveTo(-100, 25);
+ ctx.lineTo(-100, -1000);
+ ctx.closePath();
+ ctx.lineTo(1000, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.lineTo.ensuresubpath.1
+ desc: If there is no subpath, the point is added and nothing is drawn
+ testing:
+ - 2d.path.lineTo.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.lineTo(100, 50);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.lineTo.ensuresubpath.2
+ desc: If there is no subpath, the point is added and used for subsequent drawing
+ testing:
+ - 2d.path.lineTo.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.lineTo(0, 25);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.lineTo.basic
+ testing:
+ - 2d.path.lineTo.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.lineTo.nextpoint
+ testing:
+ - 2d.path.lineTo.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(-100, -100);
+ ctx.lineTo(0, 25);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.lineTo.nonfinite
+ desc: lineTo() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.lineTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.ensuresubpath.1
+ desc: If there is no subpath, the first control point is added (and nothing is drawn up to it)
+ testing:
+ - 2d.path.quadratic.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.quadraticCurveTo(100, 50, 200, 50);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 95,45 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.ensuresubpath.2
+ desc: If there is no subpath, the first control point is added
+ testing:
+ - 2d.path.quadratic.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.quadraticCurveTo(0, 25, 100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.basic
+ testing:
+ - 2d.path.quadratic.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.quadraticCurveTo(100, 25, 100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.shape
+ testing:
+ - 2d.path.quadratic.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 55;
+ ctx.beginPath();
+ ctx.moveTo(-1000, 1050);
+ ctx.quadraticCurveTo(0, -1000, 1200, 1050);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.scaled
+ testing:
+ - 2d.path.quadratic.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.scale(1000, 1000);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 0.055;
+ ctx.beginPath();
+ ctx.moveTo(-1, 1.05);
+ ctx.quadraticCurveTo(0, -1, 1.2, 1.05);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.quadraticCurveTo.nonfinite
+ desc: quadraticCurveTo() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.quadraticCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.ensuresubpath.1
+ desc: If there is no subpath, the first control point is added (and nothing is drawn up to it)
+ testing:
+ - 2d.path.bezier.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.bezierCurveTo(100, 50, 200, 50, 200, 50);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 95,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.ensuresubpath.2
+ desc: If there is no subpath, the first control point is added
+ testing:
+ - 2d.path.bezier.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.bezierCurveTo(0, 25, 100, 25, 100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.basic
+ testing:
+ - 2d.path.bezier.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.bezierCurveTo(100, 25, 100, 25, 100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.shape
+ testing:
+ - 2d.path.bezier.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 55;
+ ctx.beginPath();
+ ctx.moveTo(-2000, 3100);
+ ctx.bezierCurveTo(-2000, -1000, 2100, -1000, 2100, 3100);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.scaled
+ testing:
+ - 2d.path.bezier.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.scale(1000, 1000);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 0.055;
+ ctx.beginPath();
+ ctx.moveTo(-2, 3.1);
+ ctx.bezierCurveTo(-2, -1, 2.1, -1, 2.1, 3.1);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.bezierCurveTo.nonfinite
+ desc: bezierCurveTo() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.bezierCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.ensuresubpath.1
+ desc: If there is no subpath, the first control point is added (and nothing is drawn up to it)
+ testing:
+ - 2d.path.arcTo.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arcTo(100, 50, 200, 50, 0.1);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.ensuresubpath.2
+ desc: If there is no subpath, the first control point is added
+ testing:
+ - 2d.path.arcTo.empty
+ - 2d.path.ensure
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.arcTo(0, 25, 50, 250, 0.1); // adds (x1,y1), draws nothing
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.coincide.1
+ desc: arcTo() has no effect if P0 = P1
+ testing:
+ - 2d.path.arcTo.coincide.01
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(0, 25, 50, 1000, 1);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.arcTo(50, 25, 100, 25, 1);
+ ctx.stroke();
+
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.coincide.2
+ desc: arcTo() draws a straight line to P1 if P1 = P2
+ testing:
+ - 2d.path.arcTo.coincide.12
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, 100, 25, 1);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.collinear.1
+ desc: arcTo() with all points on a line, and P1 between P0/P2, draws a straight line to P1
+ testing:
+ - 2d.path.arcTo.collinear
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, 200, 25, 1);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(-100, 25);
+ ctx.arcTo(0, 25, 100, 25, 1);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.collinear.2
+ desc: arcTo() with all points on a line, and P2 between P0/P1, draws a straight line to P1
+ testing:
+ - 2d.path.arcTo.collinear
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, 10, 25, 1);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 25);
+ ctx.arcTo(200, 25, 110, 25, 1);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.collinear.3
+ desc: arcTo() with all points on a line, and P0 between P1/P2, draws a straight line to P1
+ testing:
+ - 2d.path.arcTo.collinear
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, -100, 25, 1);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 25);
+ ctx.arcTo(200, 25, 0, 25, 1);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(-100, 25);
+ ctx.arcTo(0, 25, -200, 25, 1);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.shape.curve1
+ desc: arcTo() curves in the right kind of shape
+ testing:
+ - 2d.path.arcTo.shape
+ code: |
+ var tol = 1.5; // tolerance to avoid antialiasing artifacts
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(10, 25);
+ ctx.arcTo(75, 25, 75, 60, 20);
+ ctx.stroke();
+
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.rect(10, 20, 45, 10);
+ ctx.moveTo(80, 45);
+ ctx.arc(55, 45, 25+tol, 0, -Math.PI/2, true);
+ ctx.arc(55, 45, 15-tol, -Math.PI/2, 0, false);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 55,19 == 0,255,0,255;
+ @assert pixel 55,20 == 0,255,0,255;
+ @assert pixel 55,21 == 0,255,0,255;
+ @assert pixel 64,22 == 0,255,0,255;
+ @assert pixel 65,21 == 0,255,0,255;
+ @assert pixel 72,28 == 0,255,0,255;
+ @assert pixel 73,27 == 0,255,0,255;
+ @assert pixel 78,36 == 0,255,0,255;
+ @assert pixel 79,35 == 0,255,0,255;
+ @assert pixel 80,44 == 0,255,0,255;
+ @assert pixel 80,45 == 0,255,0,255;
+ @assert pixel 80,46 == 0,255,0,255;
+ @assert pixel 65,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.shape.curve2
+ desc: arcTo() curves in the right kind of shape
+ testing:
+ - 2d.path.arcTo.shape
+ code: |
+ var tol = 1.5; // tolerance to avoid antialiasing artifacts
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.rect(10, 20, 45, 10);
+ ctx.moveTo(80, 45);
+ ctx.arc(55, 45, 25-tol, 0, -Math.PI/2, true);
+ ctx.arc(55, 45, 15+tol, -Math.PI/2, 0, false);
+ ctx.fill();
+
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(10, 25);
+ ctx.arcTo(75, 25, 75, 60, 20);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 55,19 == 0,255,0,255;
+ @assert pixel 55,20 == 0,255,0,255;
+ @assert pixel 55,21 == 0,255,0,255;
+ @assert pixel 64,22 == 0,255,0,255;
+ @assert pixel 65,21 == 0,255,0,255;
+ @assert pixel 72,28 == 0,255,0,255;
+ @assert pixel 73,27 == 0,255,0,255;
+ @assert pixel 78,36 == 0,255,0,255;
+ @assert pixel 79,35 == 0,255,0,255;
+ @assert pixel 80,44 == 0,255,0,255;
+ @assert pixel 80,45 == 0,255,0,255;
+ @assert pixel 80,46 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.shape.start
+ desc: arcTo() draws a straight line from P0 to P1
+ testing:
+ - 2d.path.arcTo.shape
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(200, 25, 200, 50, 10);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.shape.end
+ desc: arcTo() does not draw anything from P1 to P2
+ testing:
+ - 2d.path.arcTo.shape
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.beginPath();
+ ctx.moveTo(-100, -100);
+ ctx.arcTo(-100, 25, 200, 25, 10);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.negative
+ desc: arcTo() with negative radius throws an exception
+ testing:
+ - 2d.path.arcTo.negative
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.arcTo(0, 0, 0, 0, -1);
+
+- name: 2d.path.arcTo.zero.1
+ desc: arcTo() with zero radius draws a straight line from P0 to P1
+ testing:
+ - 2d.path.arcTo.zeroradius
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, 100, 100, 0);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(0, -25);
+ ctx.arcTo(50, -25, 50, 50, 0);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.zero.2
+ desc: arcTo() with zero radius draws a straight line from P0 to P1, even when all points are collinear
+ testing:
+ - 2d.path.arcTo.zeroradius
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arcTo(100, 25, -100, 25, 0);
+ ctx.stroke();
+
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 25);
+ ctx.arcTo(200, 25, 50, 25, 0);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.transformation
+ desc: arcTo joins up to the last subpath point correctly
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 50);
+ ctx.translate(100, 0);
+ ctx.arcTo(50, 50, 50, 0, 50);
+ ctx.lineTo(-100, 0);
+ ctx.fill();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.scale
+ desc: arcTo scales the curve, not just the control points
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 50);
+ ctx.translate(100, 0);
+ ctx.scale(0.1, 1);
+ ctx.arcTo(50, 50, 50, 0, 50);
+ ctx.lineTo(-1000, 0);
+ ctx.fill();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arcTo.nonfinite
+ desc: arcTo() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.arcTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.path.arc.empty
+ desc: arc() with an empty path does not draw a straight line to the start point
+ testing:
+ - 2d.path.arc.nonempty
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arc(200, 25, 5, 0, 2*Math.PI, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.nonempty
+ desc: arc() with a non-empty path does draw a straight line to the start point
+ testing:
+ - 2d.path.arc.nonempty
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arc(200, 25, 5, 0, 2*Math.PI, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.end
+ desc: arc() adds the end point of the arc to the subpath
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(-100, 0);
+ ctx.arc(-100, 0, 25, -Math.PI/2, Math.PI/2, true);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.default
+ desc: arc() with missing last argument defaults to clockwise
+ testing:
+ - 2d.path.arc.omitted
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 0);
+ ctx.arc(100, 0, 150, -Math.PI, Math.PI/2);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.1
+ desc: arc() draws pi/2 .. -pi anticlockwise correctly
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 0);
+ ctx.arc(100, 0, 150, Math.PI/2, -Math.PI, true);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.2
+ desc: arc() draws -3pi/2 .. -pi anticlockwise correctly
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 0);
+ ctx.arc(100, 0, 150, -3*Math.PI/2, -Math.PI, true);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.3
+ desc: arc() wraps angles mod 2pi when anticlockwise and end > start+2pi
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 0);
+ ctx.arc(100, 0, 150, (512+1/2)*Math.PI, (1024-1)*Math.PI, true);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.4
+ desc: arc() draws a full circle when clockwise and end > start+2pi
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.arc(50, 25, 60, (512+1/2)*Math.PI, (1024-1)*Math.PI, false);
+ ctx.fill();
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.5
+ desc: arc() wraps angles mod 2pi when clockwise and start > end+2pi
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(100, 0);
+ ctx.arc(100, 0, 150, (1024-1)*Math.PI, (512+1/2)*Math.PI, false);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.angle.6
+ desc: arc() draws a full circle when anticlockwise and start > end+2pi
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.arc(50, 25, 60, (1024-1)*Math.PI, (512+1/2)*Math.PI, true);
+ ctx.fill();
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.zero.1
+ desc: arc() draws nothing when startAngle = endAngle and anticlockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 0, true);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.zero.2
+ desc: arc() draws nothing when startAngle = endAngle and clockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 0, false);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.twopie.1
+ desc: arc() draws nothing when end = start + 2pi-e and anticlockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, true);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.twopie.2
+ desc: arc() draws a full circle when end = start + 2pi-e and clockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, false);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.twopie.3
+ desc: arc() draws a full circle when end = start + 2pi+e and anticlockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, true);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.twopie.4
+ desc: arc() draws nothing when end = start + 2pi+e and clockwise
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, false);
+ ctx.stroke();
+ @assert pixel 50,20 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.shape.1
+ desc: arc() from 0 to pi does not draw anything in the wrong half
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arc(50, 50, 50, 0, Math.PI, false);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 20,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.shape.2
+ desc: arc() from 0 to pi draws stuff in the right half
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 100;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.arc(50, 50, 50, 0, Math.PI, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 20,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.shape.3
+ desc: arc() from 0 to -pi/2 does not draw anything in the wrong quadrant
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 100;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arc(0, 50, 50, 0, -Math.PI/2, false);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255; @moz-todo
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.shape.4
+ desc: arc() from 0 to -pi/2 draws stuff in the right quadrant
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 150;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.arc(-50, 50, 100, 0, -Math.PI/2, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.shape.5
+ desc: arc() from 0 to 5pi does not draw crazy things
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 200;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arc(300, 0, 100, 0, 5*Math.PI, false);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.selfintersect.1
+ desc: arc() with lineWidth > 2*radius is drawn sensibly
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 200;
+ ctx.strokeStyle = '#f00';
+ ctx.beginPath();
+ ctx.arc(100, 50, 25, 0, -Math.PI/2, true);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0, 0, 25, 0, -Math.PI/2, true);
+ ctx.stroke();
+ @assert pixel 1,1 == 0,255,0,255; @moz-todo
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.selfintersect.2
+ desc: arc() with lineWidth > 2*radius is drawn sensibly
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 180;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.arc(-50, 50, 25, 0, -Math.PI/2, true);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(100, 0, 25, 0, -Math.PI/2, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,10 == 0,255,0,255;
+ @assert pixel 97,1 == 0,255,0,255;
+ @assert pixel 97,2 == 0,255,0,255;
+ @assert pixel 97,3 == 0,255,0,255;
+ @assert pixel 2,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.negative
+ desc: arc() with negative radius throws INDEX_SIZE_ERR
+ testing:
+ - 2d.path.arc.negative
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.arc(0, 0, -1, 0, 0, true);
+
+- name: 2d.path.arc.zeroradius
+ desc: arc() with zero radius draws a line to the start point
+ testing:
+ - 2d.path.arc.zero
+ code: |
+ ctx.fillStyle = '#f00'
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.lineWidth = 50;
+ ctx.strokeStyle = '#0f0';
+ ctx.beginPath();
+ ctx.moveTo(0, 25);
+ ctx.arc(200, 25, 0, 0, Math.PI, true);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.scale.1
+ desc: Non-uniformly scaled arcs are the right shape
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.scale(2, 0.5);
+ ctx.fillStyle = '#0f0';
+ ctx.beginPath();
+ ctx.arc(25, 50, 56, 0, 2*Math.PI, false);
+ ctx.fill();
+ ctx.fillStyle = '#f00';
+ ctx.beginPath();
+ ctx.moveTo(-25, 50);
+ ctx.arc(-25, 50, 24, 0, 2*Math.PI, false);
+ ctx.moveTo(75, 50);
+ ctx.arc(75, 50, 24, 0, 2*Math.PI, false);
+ ctx.moveTo(25, -25);
+ ctx.arc(25, -25, 24, 0, 2*Math.PI, false);
+ ctx.moveTo(25, 125);
+ ctx.arc(25, 125, 24, 0, 2*Math.PI, false);
+ ctx.fill();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.scale.2
+ desc: Highly scaled arcs are the right shape
+ testing:
+ - 2d.path.arc.draw
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.scale(100, 100);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 1.2;
+ ctx.beginPath();
+ ctx.arc(0, 0, 0.6, 0, Math.PI/2, false);
+ ctx.stroke();
+
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 50,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 98,25 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 50,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.arc.nonfinite
+ desc: arc() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.arc(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <2*Math.PI Infinity -Infinity NaN>, );
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.path.rect.basic
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.rect(0, 0, 100, 50);
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.newsubpath
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.beginPath();
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.moveTo(-100, 25);
+ ctx.lineTo(-50, 25);
+ ctx.rect(200, 25, 1, 1);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.closed
+ testing:
+ - 2d.path.rect.closed
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 200;
+ ctx.lineJoin = 'miter';
+ ctx.rect(100, 50, 100, 100);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.end.1
+ testing:
+ - 2d.path.rect.newsubpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.rect(200, 100, 400, 1000);
+ ctx.lineTo(-2000, -1000);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.end.2
+ testing:
+ - 2d.path.rect.newsubpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 450;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'bevel';
+ ctx.rect(150, 150, 2000, 2000);
+ ctx.lineTo(160, 160);
+ ctx.stroke();
+ @assert pixel 1,1 == 0,255,0,255;
+ @assert pixel 98,1 == 0,255,0,255;
+ @assert pixel 1,48 == 0,255,0,255;
+ @assert pixel 98,48 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.1
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.rect(0, 50, 100, 0);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.2
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.rect(50, -100, 0, 250);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.3
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.beginPath();
+ ctx.rect(50, 25, 0, 0);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.4
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 50;
+ ctx.rect(100, 25, 0, 0);
+ ctx.lineTo(0, 25);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.5
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.moveTo(0, 0);
+ ctx.rect(100, 25, 0, 0);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.rect.zero.6
+ testing:
+ - 2d.path.rect.subpath
+ #mozilla: { bug: TODO }
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.lineJoin = 'miter';
+ ctx.miterLimit = 1.5;
+ ctx.lineWidth = 200;
+ ctx.beginPath();
+ ctx.rect(100, 25, 1000, 0);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.rect.negative
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.beginPath();
+ ctx.fillStyle = '#0f0';
+ ctx.rect(0, 0, 50, 25);
+ ctx.rect(100, 0, -50, 25);
+ ctx.rect(0, 50, 50, -25);
+ ctx.rect(100, 50, -50, -25);
+ ctx.fill();
+ @assert pixel 25,12 == 0,255,0,255;
+ @assert pixel 75,12 == 0,255,0,255;
+ @assert pixel 25,37 == 0,255,0,255;
+ @assert pixel 75,37 == 0,255,0,255;
+
+- name: 2d.path.rect.winding
+ testing:
+ - 2d.path.rect.subpath
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.beginPath();
+ ctx.fillStyle = '#f00';
+ ctx.rect(0, 0, 50, 50);
+ ctx.rect(100, 50, -50, -50);
+ ctx.rect(0, 25, 100, -25);
+ ctx.rect(100, 25, -100, 25);
+ ctx.fill();
+ @assert pixel 25,12 == 0,255,0,255;
+ @assert pixel 75,12 == 0,255,0,255;
+ @assert pixel 25,37 == 0,255,0,255;
+ @assert pixel 75,37 == 0,255,0,255;
+
+- name: 2d.path.rect.selfintersect
+ #mozilla: { bug: TODO }
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 90;
+ ctx.beginPath();
+ ctx.rect(45, 20, 10, 10);
+ ctx.stroke();
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.rect.nonfinite
+ desc: rect() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ @nonfinite ctx.rect(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 90,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.overlap
+ testing:
+ - 2d.path.fill.basic
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.rect(0, 0, 100, 50);
+ ctx.closePath();
+ ctx.rect(10, 10, 80, 30);
+ ctx.fill();
+
+ @assert pixel 50,25 ==~ 0,127,0,255 +/- 1;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0.5, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.path.fill.winding.add
+ testing:
+ - 2d.path.fill.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.lineTo(-10, -10);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(100, 0);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.winding.subtract.1
+ testing:
+ - 2d.path.fill.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.lineTo(-10, -10);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.winding.subtract.2
+ testing:
+ - 2d.path.fill.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.moveTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.winding.subtract.3
+ testing:
+ - 2d.path.fill.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.lineTo(-10, -10);
+ ctx.lineTo(-20, -20);
+ ctx.lineTo(120, -20);
+ ctx.lineTo(120, 70);
+ ctx.lineTo(-20, 70);
+ ctx.lineTo(-20, -20);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.closed.basic
+ testing:
+ - 2d.path.fill.closed
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.fill.closed.unaffected
+ testing:
+ - 2d.path.fill.closed
+ code: |
+ ctx.fillStyle = '#00f';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+ ctx.lineTo(100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fill();
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 90,10 == 0,255,0,255;
+ @assert pixel 10,40 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.overlap
+ desc: Stroked subpaths are combined before being drawn
+ testing:
+ - 2d.path.stroke.basic
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.lineWidth = 50;
+ ctx.moveTo(0, 20);
+ ctx.lineTo(100, 20);
+ ctx.moveTo(0, 30);
+ ctx.lineTo(100, 30);
+ ctx.stroke();
+
+ @assert pixel 50,25 ==~ 0,127,0,255 +/- 1;
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0.5, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.path.stroke.union
+ desc: Strokes in opposite directions are unioned, not subtracted
+ testing:
+ - 2d.path.stroke.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 40;
+ ctx.moveTo(0, 10);
+ ctx.lineTo(100, 10);
+ ctx.moveTo(100, 40);
+ ctx.lineTo(0, 40);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.unaffected
+ desc: Stroking does not start a new path or subpath
+ testing:
+ - 2d.path.stroke.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.lineWidth = 50;
+ ctx.moveTo(-100, 25);
+ ctx.lineTo(-100, -100);
+ ctx.lineTo(200, -100);
+ ctx.lineTo(200, 25);
+ ctx.strokeStyle = '#f00';
+ ctx.stroke();
+
+ ctx.closePath();
+ ctx.strokeStyle = '#0f0';
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.scale1
+ desc: Stroke line widths are scaled by the current transformation matrix
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(25, 12.5, 50, 25);
+ ctx.save();
+ ctx.scale(50, 25);
+ ctx.strokeStyle = '#0f0';
+ ctx.stroke();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.rect(-25, -12.5, 150, 75);
+ ctx.save();
+ ctx.scale(50, 25);
+ ctx.strokeStyle = '#f00';
+ ctx.stroke();
+ ctx.restore();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.scale2
+ desc: Stroke line widths are scaled by the current transformation matrix
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(25, 12.5, 50, 25);
+ ctx.save();
+ ctx.rotate(Math.PI/2);
+ ctx.scale(25, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.stroke();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.rect(-25, -12.5, 150, 75);
+ ctx.save();
+ ctx.rotate(Math.PI/2);
+ ctx.scale(25, 50);
+ ctx.strokeStyle = '#f00';
+ ctx.stroke();
+ ctx.restore();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.skew
+ desc: Strokes lines are skewed by the current transformation matrix
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(49, -50);
+ ctx.lineTo(201, -50);
+ ctx.rotate(Math.PI/4);
+ ctx.scale(1, 283);
+ ctx.strokeStyle = '#0f0';
+ ctx.stroke();
+ ctx.restore();
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.translate(-150, 0);
+ ctx.moveTo(49, -50);
+ ctx.lineTo(199, -50);
+ ctx.rotate(Math.PI/4);
+ ctx.scale(1, 142);
+ ctx.strokeStyle = '#f00';
+ ctx.stroke();
+ ctx.restore();
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.translate(-150, 0);
+ ctx.moveTo(49, -50);
+ ctx.lineTo(199, -50);
+ ctx.rotate(Math.PI/4);
+ ctx.scale(1, 142);
+ ctx.strokeStyle = '#f00';
+ ctx.stroke();
+ ctx.restore();
+
+ @assert pixel 0,0 == 0,255,0,255;
+ @assert pixel 50,0 == 0,255,0,255;
+ @assert pixel 99,0 == 0,255,0,255;
+ @assert pixel 0,25 == 0,255,0,255;
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 99,25 == 0,255,0,255;
+ @assert pixel 0,49 == 0,255,0,255;
+ @assert pixel 50,49 == 0,255,0,255;
+ @assert pixel 99,49 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.empty
+ desc: Empty subpaths are not stroked
+ testing:
+ - 2d.path.stroke.empty
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.moveTo(40, 25);
+ ctx.moveTo(60, 25);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.stroke.prune.line
+ desc: Zero-length line segments from lineTo are removed before stroking
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.lineTo(50, 25);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.stroke.prune.closed
+ desc: Zero-length line segments from closed paths are removed before stroking
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.lineTo(50, 25);
+ ctx.closePath();
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.stroke.prune.curve
+ desc: Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.quadraticCurveTo(50, 25, 50, 25);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.stroke.prune.arc
+ desc: Zero-length line segments from arcTo and arc are removed before stroking
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.moveTo(50, 25);
+ ctx.arcTo(50, 25, 150, 25, 10);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(60, 25);
+ ctx.arc(50, 25, 10, 0, 0, false);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.stroke.prune.rect
+ desc: Zero-length line segments from rect and strokeRect are removed before stroking
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 100;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ ctx.beginPath();
+ ctx.rect(50, 25, 0, 0);
+ ctx.stroke();
+
+ ctx.strokeRect(50, 25, 0, 0);
+
+ @assert pixel 50,25 == 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.path.stroke.prune.corner
+ desc: Zero-length line segments are removed before stroking with miters
+ testing:
+ - 2d.path.stroke.prune
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 400;
+ ctx.lineJoin = 'miter';
+ ctx.miterLimit = 1.4;
+
+ ctx.beginPath();
+ ctx.moveTo(-1000, 200);
+ ctx.lineTo(-100, 200);
+ ctx.lineTo(-100, 200);
+ ctx.lineTo(-100, 200);
+ ctx.lineTo(-100, 1000);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.path.transformation.basic
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.translate(-100, 0);
+ ctx.rect(100, 0, 100, 50);
+ ctx.translate(0, -100);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.transformation.multiple
+ # TODO: change this name
+ desc: Transformations are applied while building paths, not when drawing
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.translate(-100, 0);
+ ctx.rect(0, 0, 100, 50);
+ ctx.fill();
+ ctx.translate(100, 0);
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.strokeStyle = '#f00';
+ ctx.lineWidth = 50;
+ ctx.translate(0, -50);
+ ctx.moveTo(0, 25);
+ ctx.lineTo(100, 25);
+ ctx.stroke();
+ ctx.translate(0, 50);
+ ctx.stroke();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.transformation.changing
+ desc: Transformations are applied while building paths, not when drawing
+ testing:
+ - 2d.path.transformation
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.moveTo(0, 0);
+ ctx.translate(100, 0);
+ ctx.lineTo(0, 0);
+ ctx.translate(0, 50);
+ ctx.lineTo(0, 0);
+ ctx.translate(-100, 0);
+ ctx.lineTo(0, 0);
+ ctx.translate(1000, 1000);
+ ctx.rotate(Math.PI/2);
+ ctx.scale(0.1, 0.1);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+- name: 2d.path.clip.empty
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.clip();
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.basic.1
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(0, 0, 100, 50);
+ ctx.clip();
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.basic.2
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(-100, 0, 100, 50);
+ ctx.clip();
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.intersect
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.rect(0, 0, 50, 50);
+ ctx.clip();
+ ctx.beginPath();
+ ctx.rect(50, 0, 50, 50)
+ ctx.clip();
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.winding.1
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.lineTo(-10, -10);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.clip();
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.winding.2
+ testing:
+ - 2d.path.clip.basic
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.beginPath();
+ ctx.moveTo(-10, -10);
+ ctx.lineTo(110, -10);
+ ctx.lineTo(110, 60);
+ ctx.lineTo(-10, 60);
+ ctx.lineTo(-10, -10);
+ ctx.clip();
+
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.lineTo(0, 0);
+ ctx.clip();
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.path.clip.unaffected
+ testing:
+ - 2d.path.clip.closed
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(100, 50);
+ ctx.lineTo(100, 0);
+ ctx.clip();
+
+ ctx.lineTo(0, 0);
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+
+- name: 2d.path.isPointInPath.basic.1
+ desc: isPointInPath() detects whether the point is inside the path
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.rect(0, 0, 20, 20);
+ @assert ctx.isPointInPath(10, 10) === true;
+ @assert ctx.isPointInPath(30, 10) === false;
+
+- name: 2d.path.isPointInPath.basic.2
+ desc: isPointInPath() detects whether the point is inside the path
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.rect(20, 0, 20, 20);
+ @assert ctx.isPointInPath(10, 10) === false;
+ @assert ctx.isPointInPath(30, 10) === true;
+
+- name: 2d.path.isPointInPath.edge
+ desc: isPointInPath() counts points on the path as being inside
+ testing:
+ - 2d.path.isPointInPath.edge
+ code: |
+ ctx.rect(0, 0, 20, 20);
+ @assert ctx.isPointInPath(0, 0) === true;
+ @assert ctx.isPointInPath(10, 0) === true;
+ @assert ctx.isPointInPath(20, 0) === true;
+ @assert ctx.isPointInPath(20, 10) === true;
+ @assert ctx.isPointInPath(20, 20) === true;
+ @assert ctx.isPointInPath(10, 20) === true;
+ @assert ctx.isPointInPath(0, 20) === true;
+ @assert ctx.isPointInPath(0, 10) === true;
+ @assert ctx.isPointInPath(10, -0.01) === false;
+ @assert ctx.isPointInPath(10, 20.01) === false;
+ @assert ctx.isPointInPath(-0.01, 10) === false;
+ @assert ctx.isPointInPath(20.01, 10) === false;
+
+- name: 2d.path.isPointInPath.empty
+ desc: isPointInPath() works when there is no path
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ @assert ctx.isPointInPath(0, 0) === false;
+
+- name: 2d.path.isPointInPath.subpath
+ desc: isPointInPath() uses the current path, not just the subpath
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.rect(0, 0, 20, 20);
+ ctx.beginPath();
+ ctx.rect(20, 0, 20, 20);
+ ctx.closePath();
+ ctx.rect(40, 0, 20, 20);
+ @assert ctx.isPointInPath(10, 10) === false;
+ @assert ctx.isPointInPath(30, 10) === true;
+ @assert ctx.isPointInPath(50, 10) === true;
+
+- name: 2d.path.isPointInPath.outside
+ desc: isPointInPath() works on paths outside the canvas
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.rect(0, -100, 20, 20);
+ ctx.rect(20, -10, 20, 20);
+ @assert ctx.isPointInPath(10, -110) === false;
+ @assert ctx.isPointInPath(10, -90) === true;
+ @assert ctx.isPointInPath(10, -70) === false;
+ @assert ctx.isPointInPath(30, -20) === false;
+ @assert ctx.isPointInPath(30, 0) === true;
+ @assert ctx.isPointInPath(30, 20) === false;
+
+- name: 2d.path.isPointInPath.unclosed
+ desc: isPointInPath() works on unclosed subpaths
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.moveTo(0, 0);
+ ctx.lineTo(20, 0);
+ ctx.lineTo(20, 20);
+ ctx.lineTo(0, 20);
+ @assert ctx.isPointInPath(10, 10) === true;
+ @assert ctx.isPointInPath(30, 10) === false;
+
+- name: 2d.path.isPointInPath.arc
+ desc: isPointInPath() works on arcs
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.arc(50, 25, 10, 0, Math.PI, false);
+ @assert ctx.isPointInPath(50, 10) === false;
+ @assert ctx.isPointInPath(50, 20) === false;
+ @assert ctx.isPointInPath(50, 30) === true;
+ @assert ctx.isPointInPath(50, 40) === false;
+ @assert ctx.isPointInPath(30, 20) === false;
+ @assert ctx.isPointInPath(70, 20) === false;
+ @assert ctx.isPointInPath(30, 30) === false;
+ @assert ctx.isPointInPath(70, 30) === false;
+
+- name: 2d.path.isPointInPath.bigarc
+ desc: isPointInPath() works on unclosed arcs larger than 2pi
+ opera: { bug: 320937 }
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.arc(50, 25, 10, 0, 7, false);
+ @assert ctx.isPointInPath(50, 10) === false;
+ @assert ctx.isPointInPath(50, 20) === true;
+ @assert ctx.isPointInPath(50, 30) === true;
+ @assert ctx.isPointInPath(50, 40) === false;
+ @assert ctx.isPointInPath(30, 20) === false;
+ @assert ctx.isPointInPath(70, 20) === false;
+ @assert ctx.isPointInPath(30, 30) === false;
+ @assert ctx.isPointInPath(70, 30) === false;
+
+- name: 2d.path.isPointInPath.bezier
+ desc: isPointInPath() works on Bezier curves
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.moveTo(25, 25);
+ ctx.bezierCurveTo(50, -50, 50, 100, 75, 25);
+ @assert ctx.isPointInPath(25, 20) === false;
+ @assert ctx.isPointInPath(25, 30) === false;
+ @assert ctx.isPointInPath(30, 20) === true;
+ @assert ctx.isPointInPath(30, 30) === false;
+ @assert ctx.isPointInPath(40, 2) === false;
+ @assert ctx.isPointInPath(40, 20) === true;
+ @assert ctx.isPointInPath(40, 30) === false;
+ @assert ctx.isPointInPath(40, 47) === false;
+ @assert ctx.isPointInPath(45, 20) === true;
+ @assert ctx.isPointInPath(45, 30) === false;
+ @assert ctx.isPointInPath(55, 20) === false;
+ @assert ctx.isPointInPath(55, 30) === true;
+ @assert ctx.isPointInPath(60, 2) === false;
+ @assert ctx.isPointInPath(60, 20) === false;
+ @assert ctx.isPointInPath(60, 30) === true;
+ @assert ctx.isPointInPath(60, 47) === false;
+ @assert ctx.isPointInPath(70, 20) === false;
+ @assert ctx.isPointInPath(70, 30) === true;
+ @assert ctx.isPointInPath(75, 20) === false;
+ @assert ctx.isPointInPath(75, 30) === false;
+
+- name: 2d.path.isPointInPath.winding
+ desc: isPointInPath() uses the non-zero winding number rule
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ // Create a square ring, using opposite windings to make a hole in the centre
+ ctx.moveTo(0, 0);
+ ctx.lineTo(50, 0);
+ ctx.lineTo(50, 50);
+ ctx.lineTo(0, 50);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(10, 10);
+ ctx.lineTo(10, 40);
+ ctx.lineTo(40, 40);
+ ctx.lineTo(40, 10);
+ ctx.lineTo(10, 10);
+
+ @assert ctx.isPointInPath(5, 5) === true;
+ @assert ctx.isPointInPath(25, 5) === true;
+ @assert ctx.isPointInPath(45, 5) === true;
+ @assert ctx.isPointInPath(5, 25) === true;
+ @assert ctx.isPointInPath(25, 25) === false;
+ @assert ctx.isPointInPath(45, 25) === true;
+ @assert ctx.isPointInPath(5, 45) === true;
+ @assert ctx.isPointInPath(25, 45) === true;
+ @assert ctx.isPointInPath(45, 45) === true;
+
+- name: 2d.path.isPointInPath.transform.1
+ desc: isPointInPath() handles transformations correctly
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.translate(50, 0);
+ ctx.rect(0, 0, 20, 20);
+ @assert ctx.isPointInPath(-40, 10) === false;
+ @assert ctx.isPointInPath(10, 10) === false;
+ @assert ctx.isPointInPath(49, 10) === false;
+ @assert ctx.isPointInPath(51, 10) === true;
+ @assert ctx.isPointInPath(69, 10) === true;
+ @assert ctx.isPointInPath(71, 10) === false;
+
+- name: 2d.path.isPointInPath.transform.2
+ desc: isPointInPath() handles transformations correctly
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.rect(50, 0, 20, 20);
+ ctx.translate(50, 0);
+ @assert ctx.isPointInPath(-40, 10) === false;
+ @assert ctx.isPointInPath(10, 10) === false;
+ @assert ctx.isPointInPath(49, 10) === false;
+ @assert ctx.isPointInPath(51, 10) === true;
+ @assert ctx.isPointInPath(69, 10) === true;
+ @assert ctx.isPointInPath(71, 10) === false;
+
+- name: 2d.path.isPointInPath.transform.3
+ desc: isPointInPath() handles transformations correctly
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.scale(-1, 1);
+ ctx.rect(-70, 0, 20, 20);
+ @assert ctx.isPointInPath(-40, 10) === false;
+ @assert ctx.isPointInPath(10, 10) === false;
+ @assert ctx.isPointInPath(49, 10) === false;
+ @assert ctx.isPointInPath(51, 10) === true;
+ @assert ctx.isPointInPath(69, 10) === true;
+ @assert ctx.isPointInPath(71, 10) === false;
+
+- name: 2d.path.isPointInPath.transform.4
+ desc: isPointInPath() handles transformations correctly
+ testing:
+ - 2d.path.isPointInPath
+ code: |
+ ctx.translate(50, 0);
+ ctx.rect(50, 0, 20, 20);
+ ctx.translate(0, 50);
+ @assert ctx.isPointInPath(60, 10) === false;
+ @assert ctx.isPointInPath(110, 10) === true;
+ @assert ctx.isPointInPath(110, 60) === false;
+
+- name: 2d.path.isPointInPath.nonfinite
+ desc: isPointInPath() returns false for non-finite arguments
+ testing:
+ - 2d.path.isPointInPath.nonfinite
+ code: |
+ ctx.rect(-100, -50, 200, 100);
+ @assert ctx.isPointInPath(Infinity, 0) === false;
+ @assert ctx.isPointInPath(-Infinity, 0) === false;
+ @assert ctx.isPointInPath(NaN, 0) === false;
+ @assert ctx.isPointInPath(0, Infinity) === false;
+ @assert ctx.isPointInPath(0, -Infinity) === false;
+ @assert ctx.isPointInPath(0, NaN) === false;
+ @assert ctx.isPointInPath(NaN, NaN) === false;
+
+
+- name: 2d.drawImage.3arg
+ testing:
+ - 2d.drawImage.defaultsource
+ - 2d.drawImage.defaultdest
+ images:
+ - red.png
+ - green.png
+ code: |
+ ctx.drawImage(document.getElementById('green.png'), 0, 0);
+ ctx.drawImage(document.getElementById('red.png'), -100, 0);
+ ctx.drawImage(document.getElementById('red.png'), 100, 0);
+ ctx.drawImage(document.getElementById('red.png'), 0, -50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 50);
+
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.5arg
+ testing:
+ - 2d.drawImage.defaultsource
+ images:
+ - red.png
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 50, 0, 50, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 50, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.9arg.basic
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 0, 0, 100, 50, 0, 0, 100, 50);
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.9arg.sourcepos
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - rgrg-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('rgrg-256x256.png'), 140, 20, 100, 50, 0, 0, 100, 50);
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.9arg.sourcesize
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - rgrg-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('rgrg-256x256.png'), 0, 0, 256, 256, 0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 51, 26);
+ ctx.fillRect(49, 24, 51, 26);
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ @assert pixel 20,20 ==~ 0,255,0,255;
+ @assert pixel 80,20 ==~ 0,255,0,255;
+ @assert pixel 20,30 ==~ 0,255,0,255;
+ @assert pixel 80,30 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.9arg.destpos
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - red.png
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 0, 0, 100, 50, 0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, -100, 0, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 100, 0, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, -50, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, 50, 100, 50);
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.9arg.destsize
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - red.png
+ - green.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 1, 1, 1, 1, 0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, -50, 0, 50, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 100, 0, 50, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, -25, 100, 25);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50, 0, 50, 100, 25);
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.canvas
+ testing:
+ - 2d.drawImage.paint
+ code: |
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 100;
+ canvas2.height = 50;
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50);
+
+ ctx.fillStyle = '#f00';
+ ctx.drawImage(canvas2, 0, 0);
+
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.self.1
+ testing:
+ - 2d.drawImage.self
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50);
+ ctx.drawImage(canvas, 50, 0);
+
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.self.2
+ testing:
+ - 2d.drawImage.self
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 1, 100, 49);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 1);
+ ctx.drawImage(canvas, 0, 1);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 2);
+
+ @assert pixel 0,0 ==~ 0,255,0,255;
+ @assert pixel 99,0 ==~ 0,255,0,255;
+ @assert pixel 0,49 ==~ 0,255,0,255;
+ @assert pixel 99,49 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.null
+ testing:
+ - 2d.drawImage.IDL
+ code: |
+ @assert throws TypeError ctx.drawImage(null, 0, 0);
+
+- name: 2d.drawImage.wrongtype
+ desc: Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError
+ notes: *bindings
+ testing:
+ - 2d.drawImage.IDL
+ code: |
+ @assert throws TypeError ctx.drawImage(undefined, 0, 0);
+ @assert throws TypeError ctx.drawImage(0, 0, 0);
+ @assert throws TypeError ctx.drawImage("", 0, 0);
+ @assert throws TypeError ctx.drawImage(document.createElement('p'), 0, 0);
+
+- name: 2d.drawImage.floatsource
+ testing:
+ - 2d.drawImage.paint
+ images:
+ - green.png
+ code: |
+ ctx.drawImage(document.getElementById('green.png'), 10.1, 10.1, 0.1, 0.1, 0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.zerosource
+ desc: drawImage with zero-sized source rectangle throws INDEX_SIZE_ERR
+ testing:
+ - 2d.drawImage.zerosource
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 0, 1, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 1, 0, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 10, 10, 0, 0, 0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.zerosource.image
+ desc: drawImage with zero-sized source rectangle from image throws INDEX_SIZE_ERR
+ testing:
+ - 2d.drawImage.zerosource
+ images:
+ - red-zerowidth.svg
+ - red-zeroheight.svg
+ - red-zerosize.svg
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zerowidth.svg'), 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zeroheight.svg'), 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red-zerosize.svg'), 0, 0, 100, 50);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.negativesource
+ desc: Negative source width/height represents the correct rectangle
+ testing:
+ - 2d.drawImage.direction
+ mozilla: { throws }
+ images:
+ - ggrr-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 78, -100, 50, 0, 0, 50, 50);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 128, -100, -50, 50, 0, 50, 50);
+ @assert pixel 1,1 ==~ 0,255,0,255;
+ @assert pixel 1,48 ==~ 0,255,0,255;
+ @assert pixel 98,1 ==~ 0,255,0,255;
+ @assert pixel 98,48 ==~ 0,255,0,255;
+ @assert pixel 48,1 ==~ 0,255,0,255;
+ @assert pixel 48,48 ==~ 0,255,0,255;
+ @assert pixel 51,1 ==~ 0,255,0,255;
+ @assert pixel 51,48 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.negativedest
+ desc: Negative destination width/height represents the correct rectangle
+ testing:
+ - 2d.drawImage.direction
+ mozilla: { throws }
+ images:
+ - ggrr-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 78, 50, 50, 0, 50, 50, -50);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 100, 128, 50, -50, 100, 50, -50, -50);
+ @assert pixel 1,1 ==~ 0,255,0,255;
+ @assert pixel 1,48 ==~ 0,255,0,255;
+ @assert pixel 98,1 ==~ 0,255,0,255;
+ @assert pixel 98,48 ==~ 0,255,0,255;
+ @assert pixel 48,1 ==~ 0,255,0,255;
+ @assert pixel 48,48 ==~ 0,255,0,255;
+ @assert pixel 51,1 ==~ 0,255,0,255;
+ @assert pixel 51,48 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.negativedir
+ desc: Negative dimensions do not affect the direction of the image
+ testing:
+ - 2d.drawImage.direction
+ mozilla: { throws }
+ images:
+ - ggrr-256x256.png
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 0, 178, 50, -100, 0, 0, 50, 100);
+ ctx.drawImage(document.getElementById('ggrr-256x256.png'), 0, 78, 50, 100, 50, 100, 50, -100);
+ @assert pixel 1,1 ==~ 0,255,0,255;
+ @assert pixel 1,48 ==~ 0,255,0,255;
+ @assert pixel 98,1 ==~ 0,255,0,255;
+ @assert pixel 98,48 ==~ 0,255,0,255;
+ @assert pixel 48,1 ==~ 0,255,0,255;
+ @assert pixel 48,48 ==~ 0,255,0,255;
+ @assert pixel 51,1 ==~ 0,255,0,255;
+ @assert pixel 51,48 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.outsidesource
+ DISABLED: fix this to match the current spec (transparent black outside source)
+ testing:
+ - 2d.drawImage.outsidesource
+ mozilla: { throws }
+ images:
+ - green.png
+ - red.png
+ code: |
+ ctx.drawImage(document.getElementById('green.png'), 10.5, 10.5, 89.5, 39.5, 0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 5.5, 5.5, -5.5, -5.5, 0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('green.png'), 100, 50, -5, -5, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), -0.001, 0, 100, 50, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, -0.001, 100, 50, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 100.001, 50, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 100, 50.001, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 50, 0, 50.001, 50, 0, 0, 100, 50); @moz-todo
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, -5, 5, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 0, 0, 5, -5, 0, 0, 100, 50);
+ @assert throws INDEX_SIZE_ERR ctx.drawImage(document.getElementById('red.png'), 110, 60, -20, -20, 0, 0, 100, 50);
+ @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.drawImage.incomplete.nosrc
+ testing:
+ - 2d.drawImage.incomplete.image
+ mozilla: { throws }
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.incomplete.immediate
+ testing:
+ - 2d.drawImage.incomplete.image
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = new Image();
+ img.src = '../images/red.png';
+ // This triggers the "update the image data" algorithm.
+ // The image will not go to the "completely available" state
+ // until a fetch task in the networking task source is processed,
+ // so the image must not be fully decodable yet:
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.drawImage.incomplete.reload
+ testing:
+ - 2d.drawImage.incomplete.image
+ images:
+ - yellow.png
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('yellow.png');
+ img.src = '../images/red.png';
+ // This triggers the "update the image data" algorithm,
+ // and resets the image to the "unavailable" state.
+ // The image will not go to the "completely available" state
+ // until a fetch task in the networking task source is processed,
+ // so the image must not be fully decodable yet:
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.drawImage.incomplete.emptysrc
+ testing:
+ - 2d.drawImage.incomplete.image
+ images:
+ - red.png
+ mozilla: { throws }
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('red.png');
+ img.src = "";
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.incomplete.removedsrc
+ testing:
+ - 2d.drawImage.incomplete.image
+ images:
+ - red.png
+ mozilla: { throws }
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('red.png');
+ img.removeAttribute('src');
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.broken
+ testing:
+ - 2d.drawImage.incomplete.image
+ images:
+ - broken.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var img = document.getElementById('broken.png');
+ ctx.drawImage(img, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.drawImage.zerocanvas
+ testing:
+ - 2d.drawImage.zerocanvas
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var canvas2 = document.createElement('canvas');
+ canvas2.width = 0;
+ canvas2.height = 10;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
+
+ canvas2.width = 10;
+ canvas2.height = 0;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
+
+ canvas2.width = 0;
+ canvas2.height = 0;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.svg
+ desc: drawImage() of an SVG image
+ testing:
+ - 2d.drawImage.svg
+ images:
+ - green.svg
+ code: |
+ ctx.drawImage(document.getElementById('green.svg'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.animated.gif
+ desc: drawImage() of an animated GIF draws the first frame
+ testing:
+ - 2d.drawImage.animated.image
+ images:
+ - anim-gr.gif
+ code: |
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.drawImage(document.getElementById('anim-gr.gif'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.drawImage.animated.apng
+ desc: drawImage() of an APNG with no poster frame draws the first frame
+ testing:
+ - 2d.drawImage.animated.image
+ images:
+ - anim-gr.png
+ code: |
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.drawImage(document.getElementById('anim-gr.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.drawImage.animated.poster
+ desc: drawImage() of an APNG draws the poster frame
+ testing:
+ - 2d.drawImage.animated.image
+ images:
+ - anim-poster-gr.png
+ code: |
+ ctx.drawImage(document.getElementById('anim-poster-gr.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+
+- name: 2d.drawImage.path
+ testing:
+ - 2d.drawImage.unaffect
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.rect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ ctx.fill();
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.transform
+ testing:
+ - 2d.drawImage.subject
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.translate(100, 0);
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+# TODO: drawImage shadows
+
+- name: 2d.drawImage.alpha
+ testing:
+ - 2d.drawImage.subject
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalAlpha = 0;
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.clip
+ testing:
+ - 2d.drawImage.subject
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.rect(-10, -10, 1, 1);
+ ctx.clip();
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.composite
+ testing:
+ - 2d.drawImage.subject
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.globalCompositeOperation = 'destination-over';
+ ctx.drawImage(document.getElementById('red.png'), 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.nowrap
+ desc: Stretched images do not get pixels wrapping around the edges
+ images:
+ - redtransparent.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.drawImage(document.getElementById('redtransparent.png'), -1950, 0, 2000, 50);
+ @assert pixel 45,25 ==~ 0,255,0,255;
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 55,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.drawImage.nonfinite
+ desc: drawImage() with Infinity/NaN is ignored
+ testing:
+ - 2d.nonfinite
+ images:
+ - red.png
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var red = document.getElementById('red.png');
+ @nonfinite ctx.drawImage(, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
+ @nonfinite ctx.drawImage(, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ @nonfinite ctx.drawImage(, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <100 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
+ @assert pixel 50,25 == 0,255,0,255;
+ expected: green
+
+
+
+- name: 2d.imageData.create2.basic
+ desc: createImageData(sw, sh) exists and returns something
+ testing:
+ - 2d.imageData.create2.object
+ code: |
+ @assert ctx.createImageData(1, 1) !== null;
+
+- name: 2d.imageData.create1.basic
+ desc: createImageData(imgdata) exists and returns something
+ testing:
+ - 2d.imageData.create1.object
+ code: |
+ @assert ctx.createImageData(ctx.createImageData(1, 1)) !== null;
+
+- name: 2d.imageData.create2.type
+ desc: createImageData(sw, sh) returns an ImageData object containing a Uint8ClampedArray object
+ testing:
+ - 2d.imageData.create2.object
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.createImageData(1, 1);
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.create1.type
+ desc: createImageData(imgdata) returns an ImageData object containing a Uint8ClampedArray object
+ testing:
+ - 2d.imageData.create1.object
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.createImageData(ctx.createImageData(1, 1));
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.create2.this
+ desc: createImageData(sw, sh) should throw when called with the wrong |this|
+ notes: *bindings
+ testing:
+ - 2d.imageData.create2.object
+ code: |
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, 1, 1); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, 1, 1); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, 1, 1); @moz-todo
+
+- name: 2d.imageData.create1.this
+ desc: createImageData(imgdata) should throw when called with the wrong |this|
+ notes: *bindings
+ testing:
+ - 2d.imageData.create2.object
+ code: |
+ var imgdata = ctx.createImageData(1, 1);
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, imgdata); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, imgdata); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, imgdata); @moz-todo
+
+- name: 2d.imageData.create2.initial
+ desc: createImageData(sw, sh) returns transparent black data of the right size
+ testing:
+ - 2d.imageData.create2.size
+ - 2d.imageData.create.initial
+ - 2d.imageData.initial
+ code: |
+ var imgdata = ctx.createImageData(10, 20);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width < imgdata.height;
+ @assert imgdata.width > 0;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata.data.length; ++i)
+ if (imgdata.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create1.initial
+ desc: createImageData(imgdata) returns transparent black data of the right size
+ testing:
+ - 2d.imageData.create1.size
+ - 2d.imageData.create.initial
+ - 2d.imageData.initial
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata1 = ctx.getImageData(0, 0, 10, 20);
+ var imgdata2 = ctx.createImageData(imgdata1);
+ @assert imgdata2.data.length === imgdata1.data.length;
+ @assert imgdata2.width === imgdata1.width;
+ @assert imgdata2.height === imgdata1.height;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata2.data.length; ++i)
+ if (imgdata2.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create2.large
+ desc: createImageData(sw, sh) works for sizes much larger than the canvas
+ testing:
+ - 2d.imageData.create2.size
+ code: |
+ var imgdata = ctx.createImageData(1000, 2000);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width < imgdata.height;
+ @assert imgdata.width > 0;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata.data.length; i += 7813) // check ~1024 points (assuming normal scaling)
+ if (imgdata.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create2.tiny
+ desc: createImageData(sw, sh) works for sizes smaller than one pixel
+ testing:
+ - 2d.imageData.create2.size
+ - 2d.imageData.one
+ code: |
+ var imgdata = ctx.createImageData(0.0001, 0.0001);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width === 1;
+ @assert imgdata.height === 1;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata.data.length; ++i)
+ if (imgdata.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create2.negative
+ desc: createImageData(sw, sh) takes the absolute magnitude of the size arguments
+ testing:
+ - 2d.imageData.create2.size
+ code: |
+ var imgdata1 = ctx.createImageData(10, 20);
+ var imgdata2 = ctx.createImageData(-10, 20);
+ var imgdata3 = ctx.createImageData(10, -20);
+ var imgdata4 = ctx.createImageData(-10, -20);
+ @assert imgdata1.data.length === imgdata2.data.length;
+ @assert imgdata2.data.length === imgdata3.data.length;
+ @assert imgdata3.data.length === imgdata4.data.length;
+
+- name: 2d.imageData.create2.zero
+ desc: createImageData(sw, sh) throws INDEX_SIZE_ERR if size is zero
+ testing:
+ - 2d.imageData.getcreate.zero
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 10);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 0);
+
+- name: 2d.imageData.create2.nonfinite
+ desc: createImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ testing:
+ - 2d.imageData.getcreate.nonfinite
+ code: |
+ @nonfinite @assert throws TypeError ctx.createImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ var posinfobj = { valueOf: function() { return Infinity; } },
+ neginfobj = { valueOf: function() { return -Infinity; } },
+ nanobj = { valueOf: function() { return -Infinity; } };
+ @nonfinite @assert throws TypeError ctx.createImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
+
+- name: 2d.imageData.create1.zero
+ desc: createImageData(null) throws TypeError
+ testing:
+ - 2d.imageData.create.null
+ code: |
+ @assert throws TypeError ctx.createImageData(null);
+
+- name: 2d.imageData.create2.round
+ desc: createImageData(w, h) is rounded the same as getImageData(0, 0, w, h)
+ testing:
+ - 2d.imageData.createround
+ code: |
+ var imgdata1 = ctx.createImageData(10.01, 10.99);
+ var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99);
+ @assert imgdata1.width === imgdata2.width;
+ @assert imgdata1.height === imgdata2.height;
+
+- name: 2d.imageData.get.basic
+ desc: getImageData() exists and returns something
+ testing:
+ - 2d.imageData.get.basic
+ code: |
+ @assert ctx.getImageData(0, 0, 100, 50) !== null;
+
+- name: 2d.imageData.get.type
+ desc: getImageData() returns an ImageData object containing a Uint8ClampedArray object
+ testing:
+ - 2d.imageData.get.object
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.getImageData(0, 0, 1, 1);
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.get.zero
+ desc: getImageData() throws INDEX_SIZE_ERR if size is zero
+ testing:
+ - 2d.imageData.getcreate.zero
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 10);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 0);
+
+- name: 2d.imageData.get.nonfinite
+ desc: getImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ testing:
+ - 2d.imageData.getcreate.nonfinite
+ code: |
+ @nonfinite @assert throws TypeError ctx.getImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ var posinfobj = { valueOf: function() { return Infinity; } },
+ neginfobj = { valueOf: function() { return -Infinity; } },
+ nanobj = { valueOf: function() { return -Infinity; } };
+ @nonfinite @assert throws TypeError ctx.getImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
+
+- name: 2d.imageData.get.source.outside
+ desc: getImageData() returns transparent black outside the canvas
+ testing:
+ - 2d.imageData.get.basic
+ - 2d.imageData.get.outside
+ code: |
+ ctx.fillStyle = '#08f';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var imgdata1 = ctx.getImageData(-10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ @assert imgdata1.data[1] === 0;
+ @assert imgdata1.data[2] === 0;
+ @assert imgdata1.data[3] === 0;
+
+ var imgdata2 = ctx.getImageData(10, -5, 1, 1);
+ @assert imgdata2.data[0] === 0;
+ @assert imgdata2.data[1] === 0;
+ @assert imgdata2.data[2] === 0;
+ @assert imgdata2.data[3] === 0;
+
+ var imgdata3 = ctx.getImageData(200, 5, 1, 1);
+ @assert imgdata3.data[0] === 0;
+ @assert imgdata3.data[1] === 0;
+ @assert imgdata3.data[2] === 0;
+ @assert imgdata3.data[3] === 0;
+
+ var imgdata4 = ctx.getImageData(10, 60, 1, 1);
+ @assert imgdata4.data[0] === 0;
+ @assert imgdata4.data[1] === 0;
+ @assert imgdata4.data[2] === 0;
+ @assert imgdata4.data[3] === 0;
+
+ var imgdata5 = ctx.getImageData(100, 10, 1, 1);
+ @assert imgdata5.data[0] === 0;
+ @assert imgdata5.data[1] === 0;
+ @assert imgdata5.data[2] === 0;
+ @assert imgdata5.data[3] === 0;
+
+ var imgdata6 = ctx.getImageData(0, 10, 1, 1);
+ @assert imgdata6.data[0] === 0;
+ @assert imgdata6.data[1] === 136;
+ @assert imgdata6.data[2] === 255;
+ @assert imgdata6.data[3] === 255;
+
+ var imgdata7 = ctx.getImageData(-10, 10, 20, 20);
+ @assert imgdata7.data[ 0*4+0] === 0;
+ @assert imgdata7.data[ 0*4+1] === 0;
+ @assert imgdata7.data[ 0*4+2] === 0;
+ @assert imgdata7.data[ 0*4+3] === 0;
+ @assert imgdata7.data[ 9*4+0] === 0;
+ @assert imgdata7.data[ 9*4+1] === 0;
+ @assert imgdata7.data[ 9*4+2] === 0;
+ @assert imgdata7.data[ 9*4+3] === 0;
+ @assert imgdata7.data[10*4+0] === 0;
+ @assert imgdata7.data[10*4+1] === 136;
+ @assert imgdata7.data[10*4+2] === 255;
+ @assert imgdata7.data[10*4+3] === 255;
+ @assert imgdata7.data[19*4+0] === 0;
+ @assert imgdata7.data[19*4+1] === 136;
+ @assert imgdata7.data[19*4+2] === 255;
+ @assert imgdata7.data[19*4+3] === 255;
+ @assert imgdata7.data[20*4+0] === 0;
+ @assert imgdata7.data[20*4+1] === 0;
+ @assert imgdata7.data[20*4+2] === 0;
+ @assert imgdata7.data[20*4+3] === 0;
+
+- name: 2d.imageData.get.source.negative
+ desc: getImageData() works with negative width and height, and returns top-to-bottom left-to-right
+ testing:
+ - 2d.imageData.get.basic
+ - 2d.pixelarray.order
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(20, 10, 60, 10);
+
+ var imgdata1 = ctx.getImageData(85, 25, -10, -10);
+ @assert imgdata1.data[0] === 255;
+ @assert imgdata1.data[1] === 255;
+ @assert imgdata1.data[2] === 255;
+ @assert imgdata1.data[3] === 255;
+ @assert imgdata1.data[imgdata1.data.length-4+0] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+1] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+2] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+3] === 255;
+
+ var imgdata2 = ctx.getImageData(0, 0, -1, -1);
+ @assert imgdata2.data[0] === 0;
+ @assert imgdata2.data[1] === 0;
+ @assert imgdata2.data[2] === 0;
+ @assert imgdata2.data[3] === 0;
+
+- name: 2d.imageData.get.source.size
+ desc: getImageData() returns bigger ImageData for bigger source rectangle
+ testing:
+ - 2d.imageData.get.basic
+ code: |
+ var imgdata1 = ctx.getImageData(0, 0, 10, 10);
+ var imgdata2 = ctx.getImageData(0, 0, 20, 20);
+ @assert imgdata2.width > imgdata1.width;
+ @assert imgdata2.height > imgdata1.height;
+
+- name: 2d.imageData.get.tiny
+ desc: getImageData() works for sizes smaller than one pixel
+ testing:
+ - 2d.imageData.one
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 0.0001, 0.0001);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width === 1;
+ @assert imgdata.height === 1;
+
+- name: 2d.imageData.get.nonpremul
+ desc: getImageData() returns non-premultiplied colours
+ testing:
+ - 2d.imageData.get.premul
+ code: |
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(10, 10, 10, 10);
+ @assert imgdata.data[0] > 200;
+ @assert imgdata.data[1] > 200;
+ @assert imgdata.data[2] > 200;
+ @assert imgdata.data[3] > 100;
+ @assert imgdata.data[3] < 200;
+
+- name: 2d.imageData.get.range
+ desc: getImageData() returns values in the range [0, 255]
+ testing:
+ - 2d.pixelarray.range
+ - 2d.pixelarray.retrieve
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(20, 10, 60, 10);
+ var imgdata1 = ctx.getImageData(10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ var imgdata2 = ctx.getImageData(30, 15, 1, 1);
+ @assert imgdata2.data[0] === 255;
+
+- name: 2d.imageData.get.clamp
+ desc: getImageData() clamps colours to the range [0, 255]
+ testing:
+ - 2d.pixelarray.range
+ code: |
+ ctx.fillStyle = 'rgb(-100, -200, -300)';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = 'rgb(256, 300, 400)';
+ ctx.fillRect(20, 10, 60, 10);
+ var imgdata1 = ctx.getImageData(10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ @assert imgdata1.data[1] === 0;
+ @assert imgdata1.data[2] === 0;
+ var imgdata2 = ctx.getImageData(30, 15, 1, 1);
+ @assert imgdata2.data[0] === 255;
+ @assert imgdata2.data[1] === 255;
+ @assert imgdata2.data[2] === 255;
+
+- name: 2d.imageData.get.length
+ desc: getImageData() returns a correctly-sized Uint8ClampedArray
+ testing:
+ - 2d.pixelarray.length
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+
+- name: 2d.imageData.get.order.cols
+ desc: getImageData() returns leftmost columns first
+ testing:
+ - 2d.pixelarray.order
+ code: |
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 2, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[Math.round(imgdata.width/2*4)] === 255;
+ @assert imgdata.data[Math.round((imgdata.height/2)*imgdata.width*4)] === 0;
+
+- name: 2d.imageData.get.order.rows
+ desc: getImageData() returns topmost rows first
+ testing:
+ - 2d.pixelarray.order
+ code: |
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 2);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[Math.floor(imgdata.width/2*4)] === 0;
+ @assert imgdata.data[(imgdata.height/2)*imgdata.width*4] === 255;
+
+- name: 2d.imageData.get.order.rgb
+ desc: getImageData() returns R then G then B
+ testing:
+ - 2d.pixelarray.order
+ - 2d.pixelarray.indexes
+ code: |
+ ctx.fillStyle = '#48c';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0x44;
+ @assert imgdata.data[1] === 0x88;
+ @assert imgdata.data[2] === 0xCC;
+ @assert imgdata.data[3] === 255;
+ @assert imgdata.data[4] === 0x44;
+ @assert imgdata.data[5] === 0x88;
+ @assert imgdata.data[6] === 0xCC;
+ @assert imgdata.data[7] === 255;
+
+- name: 2d.imageData.get.order.alpha
+ desc: getImageData() returns A in the fourth component
+ testing:
+ - 2d.pixelarray.order
+ code: |
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[3] < 200;
+ @assert imgdata.data[3] > 100;
+
+- name: 2d.imageData.get.unaffected
+ desc: getImageData() is not affected by context state
+ testing:
+ - 2d.imageData.unaffected
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50)
+ ctx.save();
+ ctx.translate(50, 0);
+ ctx.globalAlpha = 0.1;
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#f00';
+ ctx.rect(0, 0, 5, 5);
+ ctx.clip();
+ var imgdata = ctx.getImageData(0, 0, 50, 50);
+ ctx.restore();
+ ctx.putImageData(imgdata, 50, 0);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+
+- name: 2d.imageData.object.properties
+ desc: ImageData objects have the right properties
+ testing:
+ - 2d.imageData.type
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert typeof(imgdata.width) === 'number';
+ @assert typeof(imgdata.height) === 'number';
+ @assert typeof(imgdata.data) === 'object';
+
+- name: 2d.imageData.object.readonly
+ desc: ImageData objects properties are read-only
+ testing:
+ - 2d.imageData.type
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ var w = imgdata.width;
+ var h = imgdata.height;
+ var d = imgdata.data;
+ imgdata.width = 123;
+ imgdata.height = 123;
+ imgdata.data = [100,100,100,100];
+ @assert imgdata.width === w;
+ @assert imgdata.height === h;
+ @assert imgdata.data === d;
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[1] === 0;
+ @assert imgdata.data[2] === 0;
+ @assert imgdata.data[3] === 0;
+
+- name: 2d.imageData.object.ctor
+ desc: ImageData does not have a usable constructor
+ testing:
+ - 2d.imageData.type
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert throws TypeError new window.ImageData(1,1);
+
+- name: 2d.imageData.object.set
+ desc: ImageData.data can be modified
+ testing:
+ - 2d.pixelarray.modify
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ @assert imgdata.data[0] === 100;
+ imgdata.data[0] = 200;
+ @assert imgdata.data[0] === 200;
+
+- name: 2d.imageData.object.undefined
+ desc: ImageData.data converts undefined to 0
+ testing:
+ - 2d.pixelarray.modify
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = undefined;
+ @assert imgdata.data[0] === 0;
+
+- name: 2d.imageData.object.nan
+ desc: ImageData.data converts NaN to 0
+ testing:
+ - 2d.pixelarray.modify
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = NaN;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "cheese";
+ @assert imgdata.data[0] === 0;
+
+- name: 2d.imageData.object.string
+ desc: ImageData.data converts strings to numbers with ToNumber
+ testing:
+ - 2d.pixelarray.modify
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "110";
+ @assert imgdata.data[0] === 110;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "0x78";
+ @assert imgdata.data[0] === 120;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = " +130e0 ";
+ @assert imgdata.data[0] === 130;
+
+- name: 2d.imageData.object.clamp
+ desc: ImageData.data clamps numbers to [0, 255]
+ testing:
+ - 2d.pixelarray.modify
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = 300;
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -100;
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = 200+Math.pow(2, 32);
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -200-Math.pow(2, 32);
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = Math.pow(10, 39);
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -Math.pow(10, 39);
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -Infinity;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = Infinity;
+ @assert imgdata.data[0] === 255;
+
+- name: 2d.imageData.object.round
+ desc: ImageData.data rounds numbers with round-to-zero
+ testing:
+ - 2d.pixelarray.modify
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 0.499;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 0.5;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 0.501;
+ @assert imgdata.data[0] === 1;
+ imgdata.data[0] = 1.499;
+ @assert imgdata.data[0] === 1;
+ imgdata.data[0] = 1.5;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 1.501;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 2.5;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 3.5;
+ @assert imgdata.data[0] === 4;
+ imgdata.data[0] = 252.5;
+ @assert imgdata.data[0] === 252;
+ imgdata.data[0] = 253.5;
+ @assert imgdata.data[0] === 254;
+ imgdata.data[0] = 254.5;
+ @assert imgdata.data[0] === 254;
+ imgdata.data[0] = 256.5;
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = -0.5;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = -1.5;
+ @assert imgdata.data[0] === 0;
+
+
+
+- name: 2d.imageData.put.null
+ desc: putImageData() with null imagedata throws TypeError
+ testing:
+ - 2d.imageData.put.wrongtype
+ code: |
+ @assert throws TypeError ctx.putImageData(null, 0, 0);
+
+- name: 2d.imageData.put.nonfinite
+ desc: putImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ testing:
+ - 2d.imageData.put.nonfinite
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @nonfinite @assert throws TypeError ctx.putImageData(, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ @nonfinite @assert throws TypeError ctx.putImageData(, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+
+- name: 2d.imageData.put.basic
+ desc: putImageData() puts image data from getImageData() onto the canvas
+ testing:
+ - 2d.imageData.put.normal
+ - 2d.imageData.put.3arg
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.created
+ desc: putImageData() puts image data from createImageData() onto the canvas
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ var imgdata = ctx.createImageData(100, 50);
+ for (var i = 0; i < imgdata.data.length; i += 4) {
+ imgdata.data[i] = 0;
+ imgdata.data[i+1] = 255;
+ imgdata.data[i+2] = 0;
+ imgdata.data[i+3] = 255;
+ }
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.wrongtype
+ desc: putImageData() does not accept non-ImageData objects
+ testing:
+ - 2d.imageData.put.wrongtype
+ code: |
+ var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] };
+ @assert throws TypeError ctx.putImageData(imgdata, 0, 0);
+ @assert throws TypeError ctx.putImageData("cheese", 0, 0);
+ @assert throws TypeError ctx.putImageData(42, 0, 0);
+ expected: green
+
+- name: 2d.imageData.put.cross
+ desc: putImageData() accepts image data got from a different canvas
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50)
+ var imgdata = ctx2.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.alpha
+ desc: putImageData() puts non-solid image data correctly
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.25)';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,64;
+ expected: |
+ size 100 50
+ cr.set_source_rgba(0, 1, 0, 0.25)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.imageData.put.modified
+ desc: putImageData() puts modified image data correctly
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(45, 20, 10, 10)
+ var imgdata = ctx.getImageData(45, 20, 10, 10);
+ for (var i = 0, len = imgdata.width*imgdata.height*4; i < len; i += 4)
+ {
+ imgdata.data[i] = 0;
+ imgdata.data[i+1] = 255;
+ }
+ ctx.putImageData(imgdata, 45, 20);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.zero
+ desc: putImageData() with zero-sized dirty rectangle puts nothing
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0, 0, 0, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.rect1
+ desc: putImageData() only modifies areas inside the dirty rectangle, using width and height
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, 40, 20, 0, 0, 20, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.rect2
+ desc: putImageData() only modifies areas inside the dirty rectangle, using x and y
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(60, 30, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, -20, -10, 60, 30, 20, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.negative
+ desc: putImageData() handles negative-sized dirty rectangles correctly
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, 40, 20, 20, 20, -20, -20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.outside
+ desc: putImageData() handles dirty rectangles outside the canvas correctly
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+
+ ctx.putImageData(imgdata, 100, 20, 20, 20, -20, -20);
+ ctx.putImageData(imgdata, 200, 200, 0, 0, 100, 50);
+ ctx.putImageData(imgdata, 40, 20, -30, -20, 30, 20);
+ ctx.putImageData(imgdata, -30, 20, 0, 0, 30, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 98,15 ==~ 0,255,0,255;
+ @assert pixel 98,25 ==~ 0,255,0,255;
+ @assert pixel 98,45 ==~ 0,255,0,255;
+ @assert pixel 1,5 ==~ 0,255,0,255;
+ @assert pixel 1,25 ==~ 0,255,0,255;
+ @assert pixel 1,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.unchanged
+ desc: putImageData(getImageData(...), ...) has no effect
+ testing:
+ - 2d.imageData.unchanged
+ code: |
+ var i = 0;
+ for (var y = 0; y < 16; ++y) {
+ for (var x = 0; x < 16; ++x, ++i) {
+ ctx.fillStyle = 'rgba(' + i + ',' + (Math.floor(i*1.5) % 256) + ',' + (Math.floor(i*23.3) % 256) + ',' + (i/256) + ')';
+ ctx.fillRect(x, y, 1, 1);
+ }
+ }
+ var imgdata1 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
+ var olddata = [];
+ for (var i = 0; i < imgdata1.data.length; ++i)
+ olddata[i] = imgdata1.data[i];
+
+ ctx.putImageData(imgdata1, 0.1, 0.2);
+
+ var imgdata2 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
+ for (var i = 0; i < imgdata2.data.length; ++i) {
+ @assert olddata[i] === imgdata2.data[i];
+ }
+
+- name: 2d.imageData.put.unaffected
+ desc: putImageData() is not affected by context state
+ testing:
+ - 2d.imageData.unaffected
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.globalAlpha = 0.1;
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#f00';
+ ctx.shadowBlur = 1;
+ ctx.translate(100, 50);
+ ctx.scale(0.1, 0.1);
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.clip
+ desc: putImageData() is not affected by clipping regions
+ testing:
+ - 2d.imageData.unaffected
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.beginPath();
+ ctx.rect(0, 0, 50, 50);
+ ctx.clip();
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.path
+ desc: putImageData() does not affect the current path
+ testing:
+ - 2d.imageData.put.normal
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.rect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.putImageData(imgdata, 0, 0);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/tests2dtext.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/tests2dtext.yaml
new file mode 100644
index 00000000000..e2358494eed
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/tools/tests2dtext.yaml
@@ -0,0 +1,1000 @@
+# Copyright (c) 2010 Philip Taylor
+# Released under the BSD license and W3C Test Suite License: see LICENSE.txt
+
+- name: 2d.text.font.parse.basic
+ testing:
+ - 2d.text.font.parse
+ - 2d.text.font.get
+ code: |
+ ctx.font = '20px serif';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20PX SERIF';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+- name: 2d.text.font.parse.complex
+ testing:
+ - 2d.text.font.parse
+ - 2d.text.font.get
+ - 2d.text.font.lineheight
+ code: |
+ ctx.font = 'small-caps italic 400 12px/2 Unknown Font, sans-serif';
+ @assert ctx.font === 'italic small-caps 12px "Unknown Font", sans-serif'; @moz-todo
+
+ # TODO:
+ # 2d.text.font.parse.size.absolute
+ # xx-small x-small small medium large x-large xx-large
+ # 2d.text.font.parse.size.relative
+ # smaller larger
+ # 2d.text.font.parse.size.length.relative
+ # em ex px
+ # 2d.text.font.parse.size.length.absolute
+ # in cm mm pt pc
+
+- name: 2d.text.font.parse.size.percentage
+ testing:
+ - 2d.text.font.parse
+ - 2d.text.font.get
+ - 2d.text.font.fontsize
+ - 2d.text.font.size
+ canvas: 'style="font-size: 144px" width="100" height="50"'
+ code: |
+ ctx.font = '50% serif';
+ @assert ctx.font === '72px serif'; @moz-todo
+ canvas.setAttribute('style', 'font-size: 100px');
+ @assert ctx.font === '72px serif'; @moz-todo
+
+- name: 2d.text.font.parse.size.percentage.default
+ testing:
+ - 2d.text.font.undefined
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.font = '1000% serif';
+ @assert ctx2.font === '100px serif'; @moz-todo
+
+- name: 2d.text.font.parse.system
+ desc: System fonts must be computed to explicit values
+ testing:
+ - 2d.text.font.parse
+ - 2d.text.font.get
+ - 2d.text.font.systemfonts
+ code: |
+ ctx.font = 'message-box';
+ @assert ctx.font !== 'message-box';
+
+- name: 2d.text.font.parse.invalid
+ testing:
+ - 2d.text.font.invalid
+ code: |
+ ctx.font = '20px serif';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'bogus';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'inherit';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '10px {bogus}';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '10px initial';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+ ctx.font = '20px serif';
+ ctx.font = '10px default';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+ ctx.font = '20px serif';
+ ctx.font = '10px inherit';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '1em serif; background: green; margin: 10px';
+ @assert ctx.font === '20px serif';
+
+- name: 2d.text.font.default
+ testing:
+ - 2d.text.font.default
+ code: |
+ @assert ctx.font === '10px sans-serif';
+
+
+
+- name: 2d.text.align.valid
+ testing:
+ - 2d.text.align.get
+ - 2d.text.align.set
+ code: |
+ ctx.textAlign = 'start';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'end';
+ @assert ctx.textAlign === 'end';
+
+ ctx.textAlign = 'left';
+ @assert ctx.textAlign === 'left';
+
+ ctx.textAlign = 'right';
+ @assert ctx.textAlign === 'right';
+
+ ctx.textAlign = 'center';
+ @assert ctx.textAlign === 'center';
+
+- name: 2d.text.align.invalid
+ testing:
+ - 2d.text.align.invalid
+ code: |
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'bogus';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'END';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'end ';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'end\0';
+ @assert ctx.textAlign === 'start';
+
+- name: 2d.text.align.default
+ testing:
+ - 2d.text.align.default
+ code: |
+ @assert ctx.textAlign === 'start';
+
+
+- name: 2d.text.baseline.valid
+ testing:
+ - 2d.text.baseline.get
+ - 2d.text.baseline.set
+ code: |
+ ctx.textBaseline = 'top';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'hanging';
+ @assert ctx.textBaseline === 'hanging';
+
+ ctx.textBaseline = 'middle';
+ @assert ctx.textBaseline === 'middle';
+
+ ctx.textBaseline = 'alphabetic';
+ @assert ctx.textBaseline === 'alphabetic';
+
+ ctx.textBaseline = 'ideographic';
+ @assert ctx.textBaseline === 'ideographic';
+
+ ctx.textBaseline = 'bottom';
+ @assert ctx.textBaseline === 'bottom';
+
+- name: 2d.text.baseline.invalid
+ testing:
+ - 2d.text.baseline.invalid
+ code: |
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'bogus';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'MIDDLE';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'middle ';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'middle\0';
+ @assert ctx.textBaseline === 'top';
+
+- name: 2d.text.baseline.default
+ testing:
+ - 2d.text.baseline.default
+ code: |
+ @assert ctx.textBaseline === 'alphabetic';
+
+
+
+
+
+- name: 2d.text.draw.fill.basic
+ desc: fillText draws filled text
+ manual:
+ testing:
+ - 2d.text.draw
+ - 2d.text.draw.fill
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('PASS', 5, 35);
+ expected: &passfill |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 0)
+ cr.select_font_face("Arial")
+ cr.set_font_size(35)
+ cr.translate(5, 35)
+ cr.text_path("PASS")
+ cr.fill()
+
+- name: 2d.text.draw.fill.unaffected
+ desc: fillText does not start a new path or subpath
+ testing:
+ - 2d.text.draw.fill
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('FAIL', 5, 35);
+
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.text.draw.fill.rtl
+ desc: fillText respects Right-To-Left Override characters
+ manual:
+ testing:
+ - 2d.text.draw
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('\u202eFAIL \xa0 \xa0 SSAP', 5, 35);
+ expected: *passfill
+
+- name: 2d.text.draw.fill.maxWidth.large
+ desc: fillText handles maxWidth correctly
+ manual:
+ testing:
+ - 2d.text.draw.maxwidth
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('PASS', 5, 35, 200);
+ expected: *passfill
+
+- name: 2d.text.draw.fill.maxWidth.small
+ desc: fillText handles maxWidth correctly
+ testing:
+ - 2d.text.draw.maxwidth
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', -100, 35, 90);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.zero
+ desc: fillText handles maxWidth correctly
+ testing:
+ - 2d.text.draw.maxwidth
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', 5, 35, 0);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.negative
+ desc: fillText handles maxWidth correctly
+ testing:
+ - 2d.text.draw.maxwidth
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', 5, 35, -1);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.stroke.basic
+ desc: strokeText draws stroked text
+ manual:
+ testing:
+ - 2d.text.draw
+ - 2d.text.draw.stroke
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.fillStyle = '#f00';
+ ctx.lineWidth = 1;
+ ctx.font = '35px Arial, sans-serif';
+ ctx.strokeText('PASS', 5, 35);
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 0)
+ cr.select_font_face("Arial")
+ cr.set_font_size(35)
+ cr.set_line_width(1)
+ cr.translate(5, 35)
+ cr.text_path("PASS")
+ cr.stroke()
+
+- name: 2d.text.draw.stroke.unaffected
+ desc: strokeText does not start a new path or subpath
+ testing:
+ - 2d.text.draw.stroke
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+
+ ctx.font = '35px Arial, sans-serif';
+ ctx.strokeStyle = '#f00';
+ ctx.strokeText('FAIL', 5, 35);
+
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.text.draw.kern.consistent
+ desc: Stroked and filled text should have exactly the same kerning so it overlaps
+ manual:
+ testing:
+ - 2d.text.draw
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 3;
+ ctx.font = '20px Arial, sans-serif';
+ ctx.fillText('VAVAVAVAVAVAVA', -50, 25);
+ ctx.fillText('ToToToToToToTo', -50, 45);
+ ctx.strokeText('VAVAVAVAVAVAVA', -50, 25);
+ ctx.strokeText('ToToToToToToTo', -50, 45);
+ expected: green
+
+# CanvasTest is:
+# A = (0, 0) to (1em, 0.75em) (above baseline)
+# B = (0, 0) to (1em, -0.25em) (below baseline)
+# C = (0, -0.25em) to (1em, 0.75em) (the em square) plus some Xs above and below
+# D = (0, -0.25em) to (1em, 0.75em) (the em square) plus some Xs left and right
+# E = (0, -0.25em) to (1em, 0.75em) (the em square)
+# space = empty, 1em wide
+#
+# At 50px, "E" will fill the canvas vertically
+# At 67px, "A" will fill the canvas vertically
+#
+# Ideographic baseline is 0.125em above alphabetic
+# Mathematical baseline is 0.375em above alphabetic
+# Hanging baseline is 0.500em above alphabetic
+
+# WebKit doesn't block onload on font loads, so we try to make it a bit more reliable
+# by waiting with setTimeout after load before drawing
+
+- name: 2d.text.draw.fill.maxWidth.fontface
+ desc: fillText works on @font-face fonts
+ testing:
+ - 2d.text.draw.maxwidth
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillText('EEEE', -50, 37.5, 40);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.bound
+ desc: fillText handles maxWidth based on line size, not bounding box size
+ testing:
+ - 2d.text.draw.maxwidth
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('DD', 0, 37.5, 100);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.fontface
+ testing:
+ - 2d.text.font.fontface
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '67px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.fontface.repeat
+ desc: Draw with the font immediately, then wait a bit until and draw again. (This crashes some version of WebKit.)
+ testing:
+ - 2d.text.font.fontface
+ fonts:
+ - CanvasTest
+ fonthack: 0
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.font = '67px CanvasTest';
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillText('AA', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.fontface.notinpage
+ desc: "@font-face fonts should work even if they are not used in the page"
+ testing:
+ - 2d.text.font.fontface
+ fonts:
+ - CanvasTest
+ fonthack: 0
+ code: |
+ ctx.font = '67px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 25,25 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255; @moz-todo
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.top
+ desc: textBaseline top is the top of the em square (not the bounding box)
+ testing:
+ - 2d.text.baseline.top
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'top';
+ ctx.fillText('CC', 0, 0);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.bottom
+ desc: textBaseline bottom is the bottom of the em square (not the bounding box)
+ testing:
+ - 2d.text.baseline.bottom
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'bottom';
+ ctx.fillText('CC', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.middle
+ desc: textBaseline middle is the middle of the em square (not the bounding box)
+ testing:
+ - 2d.text.baseline.middle
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'middle';
+ ctx.fillText('CC', 0, 25);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.alphabetic
+ testing:
+ - 2d.text.baseline.alphabetic
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'alphabetic';
+ ctx.fillText('CC', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.ideographic
+ testing:
+ - 2d.text.baseline.ideographic
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'ideographic';
+ ctx.fillText('CC', 0, 31.25);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,45 ==~ 0,255,0,255; @moz-todo
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.baseline.hanging
+ testing:
+ - 2d.text.baseline.hanging
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'hanging';
+ ctx.fillText('CC', 0, 12.5);
+ @assert pixel 5,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.left
+ desc: textAlign left is the left of the first em square (not the bounding box)
+ testing:
+ - 2d.text.align.left
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'left';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.right
+ desc: textAlign right is the right of the last em square (not the bounding box)
+ testing:
+ - 2d.text.align.right
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'right';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.start.ltr
+ desc: textAlign start with ltr is the left edge
+ testing:
+ - 2d.text.align.left
+ fonts:
+ - CanvasTest
+ canvas: width="100" height="50" dir="ltr"
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'start';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.start.rtl
+ desc: textAlign start with rtl is the right edge
+ testing:
+ - 2d.text.align.right
+ - 2d.text.draw.direction
+ fonts:
+ - CanvasTest
+ canvas: width="100" height="50" dir="rtl"
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'start';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.end.ltr
+ desc: textAlign end with ltr is the right edge
+ testing:
+ - 2d.text.align.right
+ fonts:
+ - CanvasTest
+ canvas: width="100" height="50" dir="ltr"
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'end';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.end.rtl
+ desc: textAlign end with rtl is the left edge
+ testing:
+ - 2d.text.align.left
+ - 2d.text.draw.direction
+ fonts:
+ - CanvasTest
+ canvas: width="100" height="50" dir="rtl"
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'end';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.align.center
+ desc: textAlign center is the center of the em squares (not the bounding box)
+ testing:
+ - 2d.text.align.center
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'center';
+ ctx.fillText('DD', 50, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+
+- name: 2d.text.draw.space.basic
+ desc: U+0020 is rendered the correct size (1em wide)
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E EE', -100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.space.collapse.space
+ desc: Space characters are converted to U+0020, and collapsed (per CSS)
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E EE', -100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.space.collapse.other
+ desc: Space characters are converted to U+0020, and collapsed (per CSS)
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E \x09\x0a\x0c\x0d \x09\x0a\x0c\x0dEE', -100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255; @moz-todo
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.space.collapse.nonspace
+ desc: Non-space characters are not converted to U+0020 and collapsed
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E\x0b EE', -150, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.space.collapse.start
+ desc: Space characters at the start of a line are collapsed (per CSS)
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText(' EE', 0, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ }), 500);
+ expected: green
+
+- name: 2d.text.draw.space.collapse.end
+ desc: Space characters at the end of a line are collapsed (per CSS)
+ testing:
+ - 2d.text.draw.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ ctx.font = '50px CanvasTest';
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'right';
+ ctx.fillText('EE ', 100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255; @moz-todo
+ }), 500);
+ expected: green
+
+
+
+
+- name: 2d.text.measure.width.basic
+ testing:
+ - 2d.text.measure
+ fonts:
+ - CanvasTest
+ code: |
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText('A').width === 50;
+ @assert ctx.measureText('AA').width === 100;
+ @assert ctx.measureText('ABCD').width === 200;
+
+ ctx.font = '100px CanvasTest';
+ @assert ctx.measureText('A').width === 100;
+ }), 500);
+
+- name: 2d.text.measure.width.empty
+ desc: The empty string has zero width
+ testing:
+ - 2d.text.measure
+ fonts:
+ - CanvasTest
+ code: |
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText("").width === 0;
+ }), 500);
+
+- name: 2d.text.measure.width.space
+ desc: Space characters are converted to U+0020 and collapsed (per CSS)
+ testing:
+ - 2d.text.measure.spaces
+ fonts:
+ - CanvasTest
+ code: |
+ deferTest();
+ setTimeout(t.step_func_done(function () {
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText('A B').width === 150;
+ @assert ctx.measureText('A B').width === 150; @moz-todo
+ @assert ctx.measureText('A \x09\x0a\x0c\x0d \x09\x0a\x0c\x0dB').width === 150; @moz-todo
+ @assert ctx.measureText('A \x0b B').width >= 200;
+
+ @assert ctx.measureText(' AB').width === 100; @moz-todo
+ @assert ctx.measureText('AB ').width === 100; @moz-todo
+ }), 500);
+
+# TODO: shadows, alpha, composite, clip
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/.gitkeep b/tests/wpt/web-platform-tests/2dcontext/transformations/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.order.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.order.html
new file mode 100644
index 00000000000..8209ad66d42
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.order.html
@@ -0,0 +1,34 @@
+
+
+Canvas test: 2d.transformation.order
+
+
+
+
+
+
+2d.transformation.order
+Transformations are applied in the right order
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.direction.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.direction.html
new file mode 100644
index 00000000000..5113fa23827
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.direction.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.rotate.direction
+
+
+
+
+
+
+2d.transformation.rotate.direction
+rotate() is clockwise
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.nonfinite.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.nonfinite.html
new file mode 100644
index 00000000000..1726dcf5b1b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.nonfinite.html
@@ -0,0 +1,38 @@
+
+
+Canvas test: 2d.transformation.rotate.nonfinite
+
+
+
+
+
+
+2d.transformation.rotate.nonfinite
+rotate() with Infinity/NaN is ignored
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.radians.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.radians.html
new file mode 100644
index 00000000000..8cfeb6fd170
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.radians.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.rotate.radians
+
+
+
+
+
+
+2d.transformation.rotate.radians
+rotate() uses radians
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrap.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrap.html
new file mode 100644
index 00000000000..fbfba2a291f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrap.html
@@ -0,0 +1,38 @@
+
+
+Canvas test: 2d.transformation.rotate.wrap
+
+
+
+
+
+
+2d.transformation.rotate.wrap
+rotate() wraps large positive values correctly
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrapnegative.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrapnegative.html
new file mode 100644
index 00000000000..a695e7b397b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.wrapnegative.html
@@ -0,0 +1,35 @@
+
+
+Canvas test: 2d.transformation.rotate.wrapnegative
+
+
+
+
+
+
+2d.transformation.rotate.wrapnegative
+rotate() wraps large negative values correctly
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.zero.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.zero.html
new file mode 100644
index 00000000000..cd74260e756
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.rotate.zero.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.rotate.zero
+
+
+
+
+
+
+2d.transformation.rotate.zero
+rotate() by 0 does nothing
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.basic.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.basic.html
new file mode 100644
index 00000000000..a083a6514ae
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.basic.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.scale.basic
+
+
+
+
+
+
+2d.transformation.scale.basic
+scale() works
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.large.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.large.html
new file mode 100644
index 00000000000..926530d1f7e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.large.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.scale.large
+
+
+
+
+
+
+2d.transformation.scale.large
+scale() with large scale factors works
+
+Not really that large at all, but it hits the limits in Firefox.
+
Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.multiple.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.multiple.html
new file mode 100644
index 00000000000..9856798be91
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.multiple.html
@@ -0,0 +1,34 @@
+
+
+Canvas test: 2d.transformation.scale.multiple
+
+
+
+
+
+
+2d.transformation.scale.multiple
+Multiple scale()s combine
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.negative.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.negative.html
new file mode 100644
index 00000000000..af32851651d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.negative.html
@@ -0,0 +1,42 @@
+
+
+Canvas test: 2d.transformation.scale.negative
+
+
+
+
+
+
+2d.transformation.scale.negative
+scale() with negative scale factors works
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.nonfinite.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.nonfinite.html
new file mode 100644
index 00000000000..b9788885f0d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.nonfinite.html
@@ -0,0 +1,42 @@
+
+
+Canvas test: 2d.transformation.scale.nonfinite
+
+
+
+
+
+
+2d.transformation.scale.nonfinite
+scale() with Infinity/NaN is ignored
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.zero.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.zero.html
new file mode 100644
index 00000000000..80e79a98825
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.scale.zero.html
@@ -0,0 +1,46 @@
+
+
+Canvas test: 2d.transformation.scale.zero
+
+
+
+
+
+
+2d.transformation.scale.zero
+scale() with a scale factor of zero works
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.multiple.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.multiple.html
new file mode 100644
index 00000000000..79caa63080e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.multiple.html
@@ -0,0 +1,34 @@
+
+
+Canvas test: 2d.transformation.setTransform.multiple
+
+
+
+
+
+
+2d.transformation.setTransform.multiple
+
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.nonfinite.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.nonfinite.html
new file mode 100644
index 00000000000..4b5ebd6c737
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.nonfinite.html
@@ -0,0 +1,110 @@
+
+
+Canvas test: 2d.transformation.setTransform.nonfinite
+
+
+
+
+
+
+2d.transformation.setTransform.nonfinite
+setTransform() with Infinity/NaN is ignored
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.skewed.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.skewed.html
new file mode 100644
index 00000000000..d411e544bbd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.setTransform.skewed.html
@@ -0,0 +1,55 @@
+
+
+Canvas test: 2d.transformation.setTransform.skewed
+
+
+
+
+
+
+2d.transformation.setTransform.skewed
+
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.identity.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.identity.html
new file mode 100644
index 00000000000..bf88557b93e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.identity.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.transform.identity
+
+
+
+
+
+
+2d.transformation.transform.identity
+transform() with the identity matrix does nothing
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.multiply.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.multiply.html
new file mode 100644
index 00000000000..0313602abd8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.multiply.html
@@ -0,0 +1,34 @@
+
+
+Canvas test: 2d.transformation.transform.multiply
+
+
+
+
+
+
+2d.transformation.transform.multiply
+transform() multiplies the CTM
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.nonfinite.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.nonfinite.html
new file mode 100644
index 00000000000..1b12766cd74
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.nonfinite.html
@@ -0,0 +1,110 @@
+
+
+Canvas test: 2d.transformation.transform.nonfinite
+
+
+
+
+
+
+2d.transformation.transform.nonfinite
+transform() with Infinity/NaN is ignored
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.skewed.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.skewed.html
new file mode 100644
index 00000000000..cf723c7c202
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.transform.skewed.html
@@ -0,0 +1,55 @@
+
+
+Canvas test: 2d.transformation.transform.skewed
+
+
+
+
+
+
+2d.transformation.transform.skewed
+transform() with skewy matrix transforms correctly
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.basic.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.basic.html
new file mode 100644
index 00000000000..0238f8d0b00
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.basic.html
@@ -0,0 +1,33 @@
+
+
+Canvas test: 2d.transformation.translate.basic
+
+
+
+
+
+
+2d.transformation.translate.basic
+translate() works
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.nonfinite.html b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.nonfinite.html
new file mode 100644
index 00000000000..d0ff4d7487c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/2d.transformation.translate.nonfinite.html
@@ -0,0 +1,42 @@
+
+
+Canvas test: 2d.transformation.translate.nonfinite
+
+
+
+
+
+
+2d.transformation.translate.nonfinite
+translate() with Infinity/NaN is ignored
+
+
+Actual output:
+FAIL (fallback content)
+Expected output:
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001-ref.htm b/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001-ref.htm
new file mode 100644
index 00000000000..1201bcca9f8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001-ref.htm
@@ -0,0 +1,11 @@
+
+
+
+ HTML5 Canvas Test: scale() transformation
+
+
+
+ Description: The scale(x, y) method must add the scaling transformation described by the arguments to the transformation matrix.
+
+
+
diff --git a/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001.htm b/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001.htm
new file mode 100644
index 00000000000..4c027202e7f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/2dcontext/transformations/canvas_transformations_scale_001.htm
@@ -0,0 +1,30 @@
+
+
+
+ HTML5 Canvas Test: scale() transformation
+
+
+
+
+
+
+
+ Description: The scale(x, y) method must add the scaling transformation described by the arguments to the transformation matrix.
+ Browser does not support HTML5 Canvas.
+
+
diff --git a/tests/wpt/web-platform-tests/CONTRIBUTING.md b/tests/wpt/web-platform-tests/CONTRIBUTING.md
new file mode 100644
index 00000000000..0e7968ab6bc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/CONTRIBUTING.md
@@ -0,0 +1,29 @@
+Grant of License
+----------------
+
+By contributing to this repository, you and the company you represent, if the
+company holds any copyrights in the contribution, grant to the W3C a perpetual,
+non-exclusive, royalty-free, world-wide right and license under all of your
+copyrights in this contribution to copy, publish, use, and modify the
+contribution and to distribute the contribution under a BSD License or one with
+more restrictive terms, as well as a right and license of the same scope to any
+derivative works prepared by the W3C and based on or incorporating all or part
+of the contribution. You further agree that any derivative works of this
+contribution prepared by the W3C shall be solely owned by the W3C.
+
+You state, to the best of your knowledge, that you, or the company you
+represent, have all rights necessary to contribute the materials.
+
+W3C will retain attribution of initial authorship to you. The W3C makes no
+a-priori commitment to support or distribute contributions.
+
+Disclaimer
+----------
+
+All content from this repository is provided as is, and W3C makes no
+representations or warranties, express or implied, including, but not limited
+to, warranties of merchantability, fitness for a particular purpose,
+non-infringement, or title; nor that the contents of this repository are
+suitable for any purpose. We make no representations, express or implied, that
+the content of this repository or the use thereof indicates conformance to a
+specification. All content is provided as-is to help reach interoperability.
diff --git a/tests/wpt/web-platform-tests/DOMEvents/ClickFakeEvent.nondocument.html b/tests/wpt/web-platform-tests/DOMEvents/ClickFakeEvent.nondocument.html
new file mode 100644
index 00000000000..30e15b8e44a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/ClickFakeEvent.nondocument.html
@@ -0,0 +1,19 @@
+
+Click event on an element not in the document
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/constructors.html b/tests/wpt/web-platform-tests/DOMEvents/constructors.html
new file mode 100644
index 00000000000..b41d1d7bd0c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/constructors.html
@@ -0,0 +1,147 @@
+
+
+Event constructors
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/event-phases-order.html b/tests/wpt/web-platform-tests/DOMEvents/event-phases-order.html
new file mode 100644
index 00000000000..d2dc4048787
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/event-phases-order.html
@@ -0,0 +1,28 @@
+
+
+Event phases order
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/init-event-while-dispatching.html b/tests/wpt/web-platform-tests/DOMEvents/init-event-while-dispatching.html
new file mode 100644
index 00000000000..2aa1f6701c4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/init-event-while-dispatching.html
@@ -0,0 +1,83 @@
+
+
+Re-initializing events while dispatching them
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/Status.html b/tests/wpt/web-platform-tests/DOMEvents/tests/Status.html
new file mode 100644
index 00000000000..5599395549b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/Status.html
@@ -0,0 +1,26 @@
+
+
+
+ DOM Level 3 Events Test Status
+
+
+
+DOM Level 3 Events Test Suite Status
+
+This test suite is part of the
+Web Application WG's
+Test Repository as described in WebApps'
+Testing Wiki .
+
+
+The test suite is for the
+DOM Level 3 Events specification.
+
+
+
+ Test suite status: all of the tests in the approved
directory are Approved by WebApps' testing group
+ Test Facilitator: Alex Kuang
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/DOM.event.flow.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/DOM.event.flow.html
new file mode 100644
index 00000000000..c4d1fcfc021
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/DOM.event.flow.html
@@ -0,0 +1,64 @@
+
+
+
+ Event dispatch and DOM event flow
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventListener.eventHandler.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventListener.eventHandler.html
new file mode 100644
index 00000000000..992ff1cc973
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventListener.eventHandler.html
@@ -0,0 +1,60 @@
+
+
+
+ EventLister member: handleEvent()
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.after.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.after.dispatchEvent.html
new file mode 100644
index 00000000000..d8ab8d4f26a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.after.dispatchEvent.html
@@ -0,0 +1,44 @@
+
+
+
+ Event.defaultPrevented is reset after dipatchEvent()
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.multiple.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.multiple.dispatchEvent.html
new file mode 100644
index 00000000000..e8555bd78b9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/EventObject.multiple.dispatchEvent.html
@@ -0,0 +1,55 @@
+
+
+
+ Multiple dispatchEvent() and stopPropagation()
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/ProcessingInstruction.DOMCharacterDataModified.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/ProcessingInstruction.DOMCharacterDataModified.html
new file mode 100644
index 00000000000..329bc04c871
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/ProcessingInstruction.DOMCharacterDataModified.html
@@ -0,0 +1,32 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/dispatchEvent.click.checkbox.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/dispatchEvent.click.checkbox.html
new file mode 100644
index 00000000000..4a2af9d1929
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/dispatchEvent.click.checkbox.html
@@ -0,0 +1,80 @@
+
+
+
+ MouseEvent: Default action and synthetic click event
+
+
+
+
+
+
+
+
+ Click Here
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/domnodeinserted.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/domnodeinserted.html
new file mode 100644
index 00000000000..934a7eaaf7c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/domnodeinserted.html
@@ -0,0 +1,26 @@
+
+MutationEvent: DOMNodeInserted Event Type
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopImmediatePropagation.effect.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopImmediatePropagation.effect.html
new file mode 100644
index 00000000000..99facb969d4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopImmediatePropagation.effect.html
@@ -0,0 +1,71 @@
+
+
+
+ Event.stopImmediatePropagation() immediate effect
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.deferred.effect.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.deferred.effect.html
new file mode 100644
index 00000000000..65872200648
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.deferred.effect.html
@@ -0,0 +1,70 @@
+
+
+
+ Event.stopPropagation() deferred effect
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.dispatchEvent.html
new file mode 100644
index 00000000000..5c31a1d1330
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/stopPropagation.dispatchEvent.html
@@ -0,0 +1,65 @@
+
+
+
+ Calling stopPropagation() prior to dispatchEvent()
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 00000000000..7c0091a8f91
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,32 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/CompositionEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/CompositionEvent.html
new file mode 100644
index 00000000000..0f8242b07d5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/CompositionEvent.html
@@ -0,0 +1,69 @@
+
+
+
+ Composition Event Types: compositionstart, compositionupdate, compositionend
+
+
+
+ DOM Events
+
+ Test Description: The composition events occur in a set order relative to one another:
+ 1. compositionstart, 2. compositionupdate (multiple events), 3. compositionend.
+
+
+
+
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+ 3) Press the '{Enter}' key to complete the IME composition
+ 4) Click here to test again if not following the steps exactly
+
+
+ Test passes if the word "PASS" appears below and nothing is typed to the textbox after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrChange.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrChange.html
new file mode 100644
index 00000000000..12c45fc848e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrChange.html
@@ -0,0 +1,65 @@
+
+
+
+ MutationEvent.attrChange for DOMAttrModified Event
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent.attrChange indicates the type of change which triggered the DOMAttrModified event.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrName.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrName.html
new file mode 100644
index 00000000000..ca1ad97d24d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.attrName.html
@@ -0,0 +1,66 @@
+
+
+
+ MutationEvent.attrName for DOMAttrModified Event
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent.attrName indicates the name of the changed Attr node
+ in a DOMAttrModified event.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.html
new file mode 100644
index 00000000000..c229abe96e3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.html
@@ -0,0 +1,66 @@
+
+
+
+ Mutation Event Type: DOMAttrModified
+
+
+
+ DOM Events
+
+ Test Description: DOMAttrModified event fires after an Attr.value has been
+ modified and after an Attr node has been added to or removed from an Element.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.newValue.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.newValue.html
new file mode 100644
index 00000000000..77b8a41e1a3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.newValue.html
@@ -0,0 +1,65 @@
+
+
+
+ MutationEvent.newValue for DOMAttrModified Event
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent.newValue indicates the new value of the Attr node in DOMAttrModified events.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.prevValue.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.prevValue.html
new file mode 100644
index 00000000000..31fbec77644
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.prevValue.html
@@ -0,0 +1,65 @@
+
+
+
+ MutationEvent.prevValue for DOMAttrModified Event
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent.prevValue indicates the previous value of the Attr node in DOMAttrModified events.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.relatedNode.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.relatedNode.html
new file mode 100644
index 00000000000..5c30dabe22f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMAttrModified.relatedNode.html
@@ -0,0 +1,66 @@
+
+
+
+ MutationEvent.relatedNode for DOMAttrModified Event
+
+
+
+ DOM Events
+
+ Test Description: In the case of the DOMAttrModified event, MutationEvent.relatedNode
+ indicates the Attr node which was modified, added, or removed.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMCharacterDataModified.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMCharacterDataModified.html
new file mode 100644
index 00000000000..31d4fbf08f3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMCharacterDataModified.html
@@ -0,0 +1,62 @@
+
+
+
+ MutationEvent: DOMCharacterDataModified Event Type
+
+
+
+ DOM Events
+
+ Test Description: DOMCharacterDataModified event fires after CharacterData.data has been modified.
+
+
+
+ Hello
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeInserted.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeInserted.html
new file mode 100644
index 00000000000..0e0d26d1aae
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeInserted.html
@@ -0,0 +1,64 @@
+
+
+
+ MutationEvent: DOMNodeInserted Event Type
+
+
+
+ DOM Events
+
+ Test Description: DOMNodeInserted event fires when a node has been added as a child of another node.
+
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeRemoved.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeRemoved.html
new file mode 100644
index 00000000000..34d7112027c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMNodeRemoved.html
@@ -0,0 +1,62 @@
+
+
+
+ MutationEvent: DOMNodeRemoved Event Type
+
+
+
+ DOM Events
+
+ Test Description: DOMNodeRemoved event fires when a node is being removed from its parent node.
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMSubtreeModified.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMSubtreeModified.html
new file mode 100644
index 00000000000..1819f563dac
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/DOMSubtreeModified.html
@@ -0,0 +1,72 @@
+
+
+
+ MutationEvent: DOMSubtreeModified Event Type
+
+
+
+ DOM Events
+
+ Test Description: DOMSubtreeModified event fires after any other events
+ caused by the mutation(s) have occurred.
+
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.defaultPrevented.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.defaultPrevented.html
new file mode 100644
index 00000000000..d1e0244c16b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.defaultPrevented.html
@@ -0,0 +1,68 @@
+
+
+
+ W3C DOM Level 3 Event Object Property: defaultPrevented
+
+
+
+
+ Test Description:
+ Event listeners can cancel default actions of cancelable event objects by invoking the Event.preventDefault()
+ method, and determine whether an event has been canceled through the Event.defaultPrevented attribute.
+
+
+ Click the hyperlink:
+ http://samples.msdn.microsoft.com/ietestcenter
+
+ Test passes if the word "PASS" appears below after clicking the hyperlink and the page does not navigate away.
+ Test result:
+ FAIL
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.eventPhase.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.eventPhase.html
new file mode 100644
index 00000000000..ab297e7c553
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.eventPhase.html
@@ -0,0 +1,77 @@
+
+
+
+ W3C DOM Level 2 Event Object Property: eventPhase
+
+
+
+
+ Test Description:
+ eventPhase is used to indicate which phase of event flow is currently being accomplished.
+
+
+
+ Double click here:
+
+
+ Test passes if the word "PASS" appears below after double clicking the above textbox.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.stopPropagation.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.stopPropagation.html
new file mode 100644
index 00000000000..9f796db6508
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/Event.stopPropagation.html
@@ -0,0 +1,85 @@
+
+
+
+ W3C DOM Level 3 Event Object method: stopPropagation
+
+
+
+
+ Test Description:
+ stopPropagation prevents other event listeners from being triggered.
+
+
+
+ Click the button:
+
+
+ Test passes if the word "PASS" appears below after clicking the above button using mouse.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.key.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.key.html
new file mode 100644
index 00000000000..4c1d254474a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.key.html
@@ -0,0 +1,56 @@
+
+
+
+ KeyboardEvent Object Property: key
+
+
+
+ Test Description: KeyboardEvent Object Property key holds the key value of the key pressed
+
+ Type 'a' here:
+
+ Test passes if the word "PASS" appears below after typing 'a' in the above textbox using keyboard.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.location.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.location.html
new file mode 100644
index 00000000000..63fe460f3d3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.location.html
@@ -0,0 +1,74 @@
+
+
+
+ KeyboardEvent.location
+
+
+
+ DOM Events
+
+ Test Description: KeyboardEvent.location attribute contains an indication of the
+ location of the key on the device.
+
+
+
+
+
+ Steps:
+ 1) Type 'a' in the above textbox using keyboard
+ 2) Press '{CTRL}' key on the left side of the keyboard
+ 3) Press '{SHIFT}' key on the right side of the keyboard
+ 4) Click here to test again if not following the steps exactly
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.modifiers.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.modifiers.html
new file mode 100644
index 00000000000..ee490b47ec6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/KeyboardEvent.modifiers.html
@@ -0,0 +1,66 @@
+
+
+
+ KeyboardEvent.getModifierState() and 'AltGraph' modifier key
+
+
+
+ DOM Events
+
+ Test Description: Some operating systems simulate the 'AltGraph' modifier key
+ with the combination of the 'Alt' and 'Control' modifier keys. Implementations
+ are encouraged to use the 'AltGraph' modifier key.
+
+
+
+
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Press and hold down '{CTRL}' key and then press '{ALT}' key on the keyboard
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.button.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.button.html
new file mode 100644
index 00000000000..213009f4c4d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.button.html
@@ -0,0 +1,65 @@
+
+
+
+ MouseEvent.button for mouseup Event
+
+
+
+
+ Test Description: MouseEvent.button value for mouseup event is based on current button pressed.
+
+
+
+
+
+ Steps:
+ 1) Move the mouse pointer to the above textbox
+ 2) Click the mouse button in this order: Left Button, Middle Button, Right Button
+ 3) Click here to test again if not following the steps exactly
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.image.map.area.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.image.map.area.html
new file mode 100644
index 00000000000..17b7dd5ccee
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.image.map.area.html
@@ -0,0 +1,70 @@
+
+
+
+ MouseEvent event on IMG element with MAP and AREA elements
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent event fires on the AREA element when click the MAP AREA on an image
+
+
+
+
+
+
+
+
+
+ Steps:
+
+ Click at the arrow pointer symbol on the bottom-right corner of the image.
+
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.preventDefault.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.preventDefault.html
new file mode 100644
index 00000000000..e6cb57806db
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MouseEvent.preventDefault.html
@@ -0,0 +1,94 @@
+
+
+
+ MouseEvent: mousedown - preventDefault() for text selection
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent - Text selection is disabled after cancelling mousedown event.
+
+
+ Use mouse to select the whole line here
+
+
+ Steps:
+
+ Make sure text in the above green box can be selected using mouse
+ Dismiss the selection, if any, by clicking at the green box with mouse
+ Now, click the button: Disable Selection
+ Drag mouse to select the whole line of the text inside the above green box
+ Click the button: VerifyResult
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.hasFeature.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.hasFeature.html
new file mode 100644
index 00000000000..f550a5366df
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.hasFeature.html
@@ -0,0 +1,67 @@
+
+
+
+ MutationEvent: feature detection with hasFeature()
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent - feature support detection using DOMImplementation.hasFeature() method
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.initMutationEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.initMutationEvent.html
new file mode 100644
index 00000000000..3b2bceabf45
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.initMutationEvent.html
@@ -0,0 +1,72 @@
+
+
+
+ MutationEvent.initMutationEvent() and Event.trusted
+
+
+
+ DOM Events
+
+ Test Description: initMutationEvent initializes attributes of a MutationEvent object.
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.relatedNode.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.relatedNode.html
new file mode 100644
index 00000000000..6b92079ef61
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/MutationEvent.relatedNode.html
@@ -0,0 +1,76 @@
+
+
+
+ MutationEvent.relatedNode for DOMNodeInserted and DOMNodeRemoved
+
+
+
+ DOM Events
+
+ Test Description: MutationEvent.relatedNode is the parent node of the node being removed for DOMNodeRemoved event;
+ and, it is the parent node of the node that has been inserted for DOMNodeInserted event
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html
new file mode 100644
index 00000000000..9b0843c115e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html
@@ -0,0 +1,18 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+ DOM Events
+
+ Test Description: DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified,
+ but the node itself has not been inserted or deleted. The proximal event target of this event shall be the
+ ProcessingInstruction node.
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 00000000000..0e3912ea7ef
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,63 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+
+
DOM Events
+
+ Test Description: DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified,
+ but the node itself has not been inserted or deleted. The proximal event target of this event shall be the
+ ProcessingInstruction node.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.hasFeature.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.hasFeature.html
new file mode 100644
index 00000000000..853cc7c4357
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.hasFeature.html
@@ -0,0 +1,60 @@
+
+
+
+ TextEvent: feature detection with hasFeature()
+
+
+
+ DOM Events
+
+ Test Description: TextEvent - feature support detection using DOMImplementation.hasFeature() method
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.initTextEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.initTextEvent.html
new file mode 100644
index 00000000000..52eae11aa9c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.initTextEvent.html
@@ -0,0 +1,66 @@
+
+
+
+ TextEvent.initTextEvent() and Event.trusted
+
+
+
+ DOM Events
+
+ Test Description: initTextEvent initializes attributes of a TextEvent object.
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.IME.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.IME.html
new file mode 100644
index 00000000000..af5c7362426
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.IME.html
@@ -0,0 +1,69 @@
+
+
+
+ TextEvent: inputMode with DOM_INPUT_METHOD_IME
+
+
+
+ DOM Events
+
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_IME (0x04)
+ when the text string was entered through an Input Method Editor.
+
+
+
+
+
+
+
+ Steps:
+
+ Open Japanese Microsoft IME and select Hiragana input method
+ Click at the above textbox and then type 'a' using keyboard
+ Press '{ENTER}' key to complete the IME composition
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.drop.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.drop.html
new file mode 100644
index 00000000000..14ffc19765b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.drop.html
@@ -0,0 +1,71 @@
+
+
+
+ TextEvent: inputMode with DOM_INPUT_METHOD_DROP
+
+
+
+ DOM Events
+
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_DROP (0x03)
+ when the text string was inserted as part of a drag-and-drop operation.
+
+
+
+ Hello World
+
+
+
+
+
+ Steps:
+
+ Select "Hello World" inside the green editbox
+ Drag-and-drop it ("Hello World") to the textbox below the green editbox
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html
new file mode 100644
index 00000000000..9d679d708e7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html
@@ -0,0 +1,67 @@
+
+
+
+ TextEvent: inputMode with DOM_INPUT_METHOD_KEYBOARD
+
+
+
+ DOM Events
+
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_KEYBOARD (0x01)
+ when the text string was input through a keyboard.
+
+
+
+
+
+
+ Steps:
+
+ Type 'a' in the above texbox using keyboard
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.paste.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.paste.html
new file mode 100644
index 00000000000..a93259cd608
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.paste.html
@@ -0,0 +1,71 @@
+
+
+
+ TextEvent: inputMode with DOM_INPUT_METHOD_PASTE
+
+
+
+ DOM Events
+
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_PASTE (0x02)
+ when the text string was pasted in from a clipboard.
+
+
+
+ Hello World
+
+
+
+
+
+ Steps:
+
+ Select and copy "Hello World" inside the green editbox
+ Paste it ("Hello World") to the textbox below the green editbox
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.script.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.script.html
new file mode 100644
index 00000000000..c1327ebae57
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/TextEvent.inputMode.script.html
@@ -0,0 +1,63 @@
+
+
+
+ TextEvent: inputMode with DOM_INPUT_METHOD_SCRIPT
+
+
+
+ DOM Events
+
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_SCRIPT (0x09)
+ when the text string was inserted via a script operation on the DOM.
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/UIEvent.load.stylesheet.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/UIEvent.load.stylesheet.html
new file mode 100644
index 00000000000..a948a2f71a4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/UIEvent.load.stylesheet.html
@@ -0,0 +1,59 @@
+
+
+
+ UIEvent: load event for style sheets
+
+
+
+ DOM Events
+
+ Test Description: UIEvent - load event fires when the DOM Implementation finishes loading
+ dependent resources, such as style sheets.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html
new file mode 100644
index 00000000000..4dfe246136a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html
@@ -0,0 +1,90 @@
+
+
+
+ WheelEvent: wheel Event capturing/bubbling
+
+
+
+ DOM Events
+
+ Test Description: WheelEvent - wheel event bubbles.
+
+
+
+ TOP TOP TOP TOP TOP TOP TOP Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here END END END END END END END
+
+
+ Steps:
+
+ Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ Move the mouse pointer over the above textarea
+ Scroll down the mouse wheel 1 or more units
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html
new file mode 100644
index 00000000000..52b17ced96c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html
@@ -0,0 +1,93 @@
+
+
+
+ WheelEvent: wheel - MouseEvent.ctrlKey and Zooming
+
+
+
+ DOM Events
+
+ Test Description: The typical default action of the wheel event type, in some cases, is to
+ zoom the document. If this event is canceled, the implementation must not zoom the document.
+
+
+
+
+
+ Steps:
+
+ Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ Make sure the page can be zoomed in/out by holding down '{CTRL}' key + scrolling the mouse wheel on the page
+ Now, click the button: Disable Zooming
+ Press and hold down '{CTRL}' key on the keyboard
+ Move the mouse pointer to the center of the page
+ Scroll down/up the mouse wheel some units
+ Click the button: VerifyResult
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.deltaMode.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.deltaMode.html
new file mode 100644
index 00000000000..11761f4083d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.deltaMode.html
@@ -0,0 +1,76 @@
+
+
+
+ WheelEvent: wheel - WheelEvent.deltaMode
+
+
+
+ DOM Events
+
+ Test Description: WheelEvent.deltaMode attribute contains an indication of the units of
+ measurement for the delta values. Its value may be different based on system configuration.
+
+
+
+
+ TOP TOP TOP TOP TOP TOP TOP
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ END END END END END END END
+
+
+
+ Steps:
+
+ Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ Move the mouse pointer over the above green box
+ Scroll down the mouse wheel 1 or more units
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.hasFeature.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.hasFeature.html
new file mode 100644
index 00000000000..8bd224fa98e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.hasFeature.html
@@ -0,0 +1,60 @@
+
+
+
+ WheelEvent: feature detection with hasFeature()
+
+
+
+ DOM Events
+
+ Test Description: WheelEvent - feature support detection using DOMImplementation.hasFeature() method
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.initWheelEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.initWheelEvent.html
new file mode 100644
index 00000000000..cd8c192e41b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.initWheelEvent.html
@@ -0,0 +1,76 @@
+
+
+
+ WheelEvent.initWheelEvent() and Event.trusted
+
+
+
+ DOM Events
+
+ Test Description: initWheelEvent initializes attributes of a WheelEvent object.
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html
new file mode 100644
index 00000000000..6cb55a071f3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html
@@ -0,0 +1,91 @@
+
+
+
+ WheelEvent: wheel - preventDefault() for Scrolling
+
+
+
+ DOM Events
+
+ Test Description: The typical default action of the wheel event type is to scroll the document/element
+ by the indicated amount. If this event is canceled, the implementation must not scroll document/element.
+
+
+
+ TOP TOP TOP TOP TOP TOP TOP Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here END END END END END END END
+
+
+ Steps:
+
+ Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ Make sure the above textarea can be scrolled by scrolling the mouse wheel over it
+ Now, click the button: Disable Scrolling
+ Move the mouse pointer over the above textarea
+ Scroll down the mouse wheel 1 or more units
+ Click the button: VerifyResult
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.img.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.img.html
new file mode 100644
index 00000000000..5e403013e29
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.img.html
@@ -0,0 +1,74 @@
+
+
+
+ W3C DOM Level 3 Event: abort
+
+
+
+
+ Test Description:
+ The abort event fires when the loading of a resource has been aborted.
+
+
+
+
+ Loading...
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.testresult.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.testresult.html
new file mode 100644
index 00000000000..b9c37576aa9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/abort.testresult.html
@@ -0,0 +1,30 @@
+
+
+
+
+ Test Description:
+ The abort event fires when the loading of a resource has been aborted.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/blur.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/blur.html
new file mode 100644
index 00000000000..0259fe6cb4b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/blur.html
@@ -0,0 +1,57 @@
+
+
+
+ W3C DOM Level 3 Event: blur
+
+
+
+ Test Description: blur event fires when an event target loses focus.
+
+
+ Click the textbox and then the button:
+ Button
+
+
+ Test passes if the word "PASS" appears below after clicking the above textbox and then the button.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.data.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.data.html
new file mode 100644
index 00000000000..177c37e8d76
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.data.html
@@ -0,0 +1,66 @@
+
+
+
+ CompositionEvent.data for compositionstart Event
+
+
+
+ DOM Events
+
+ Test Description: The value of the data attribute of the compositionstart event
+ shall be null for new IME input.
+
+
+
+
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.keydown.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.keydown.html
new file mode 100644
index 00000000000..7316d1a8a30
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.keydown.html
@@ -0,0 +1,76 @@
+
+
+
+ compositionstart Event and keydown Event
+
+
+
+ DOM Events
+
+ Test Description: When a keyboard is used to feed an input method editor,
+ compositionstart event type is generated after a keydown event.
+
+
+
+
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Type 'a' in the above textbox using keyboard
+ 3) Click here to test again if not following the steps exactly
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.preventDefault.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.preventDefault.html
new file mode 100644
index 00000000000..74fc52b5799
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/compositionstart.preventDefault.html
@@ -0,0 +1,73 @@
+
+
+
+ Cancelling compositionstart Event via Event.preventDefault()
+
+
+
+ DOM Events
+
+ Test Description: The default action of compositionstart event is to launch the appropriate text
+ composition system. If this event is canceled, the text composition system must not be launched.
+
+
+
+
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+
+
+ Test passes if the word "PASS" appears below and nothing is typed to the textbox after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/DOM.event.flow.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/DOM.event.flow.html
new file mode 100644
index 00000000000..35355f766b0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/DOM.event.flow.html
@@ -0,0 +1,64 @@
+
+
+
+ Event dispatch and DOM event flow
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html
new file mode 100644
index 00000000000..e0ab7e0d3e4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html
@@ -0,0 +1,77 @@
+
+
+
+ Dispatch additional events inside an event listener
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.eventHandler.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.eventHandler.html
new file mode 100644
index 00000000000..ed7e9aff280
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventListener.eventHandler.html
@@ -0,0 +1,61 @@
+
+
+
+ EventLister member: handleEvent()
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.after.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.after.dispatchEvent.html
new file mode 100644
index 00000000000..a2e44c9c8cf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.after.dispatchEvent.html
@@ -0,0 +1,45 @@
+
+
+
+ Event.defaultPrevented is reset after dipatchEvent()
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.multiple.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.multiple.dispatchEvent.html
new file mode 100644
index 00000000000..70b2fedbcf0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/EventObject.multiple.dispatchEvent.html
@@ -0,0 +1,56 @@
+
+
+
+ Multiple dispatchEvent() and stopPropagation()
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/ProcessingInstruction.DOMCharacterDataModified.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/ProcessingInstruction.DOMCharacterDataModified.html
new file mode 100644
index 00000000000..2d91abd496e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/ProcessingInstruction.DOMCharacterDataModified.html
@@ -0,0 +1,34 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/dispatchEvent.click.checkbox.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/dispatchEvent.click.checkbox.html
new file mode 100644
index 00000000000..8cb548f84c6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/dispatchEvent.click.checkbox.html
@@ -0,0 +1,80 @@
+
+
+
+ MouseEvent: Default action and synthetic click event
+
+
+
+
+
+
+
+
+ Click Here
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/domnodeinserted.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/domnodeinserted.html
new file mode 100644
index 00000000000..e5064d8d46c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/domnodeinserted.html
@@ -0,0 +1,26 @@
+
+MutationEvent: DOMNodeInserted Event Type
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopImmediatePropagation.effect.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopImmediatePropagation.effect.html
new file mode 100644
index 00000000000..f00c749f873
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopImmediatePropagation.effect.html
@@ -0,0 +1,72 @@
+
+
+
+ Event.stopImmediatePropagation() immediate effect
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.deferred.effect.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.deferred.effect.html
new file mode 100644
index 00000000000..8238fa7d962
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.deferred.effect.html
@@ -0,0 +1,71 @@
+
+
+
+ Event.stopPropagation() deferred effect
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.dispatchEvent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.dispatchEvent.html
new file mode 100644
index 00000000000..70ff9706290
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/stopPropagation.dispatchEvent.html
@@ -0,0 +1,66 @@
+
+
+
+ Calling stopPropagation() prior to dispatchEvent()
+
+
+
+
+
+
+
+
+
+ Shady Grove
+ Aeolian
+
+
+ Over the river, Charlie
+ Dorian
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 00000000000..7c0091a8f91
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,32 @@
+
+
+
+ ProcessingInstruction.data and DOMCharacterDataModified event
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/customevent.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/customevent.html
new file mode 100644
index 00000000000..a11ca15570e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/customevent.html
@@ -0,0 +1,61 @@
+
+
+
+ W3C DOM L3 Event: CustomEvent
+
+
+
+
+ Test Description:
+ Create and fire CustomEvent using methods: createEvent, initEvent, dispatchEvent.
+
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.UNSPECIFIED_EVENT_TYPE_ERR.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.UNSPECIFIED_EVENT_TYPE_ERR.html
new file mode 100644
index 00000000000..d239f06aa92
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.UNSPECIFIED_EVENT_TYPE_ERR.html
@@ -0,0 +1,48 @@
+
+
+
+ EventException.UNSPECIFIED_EVENT_TYPE_ERR and dispatchEvent()
+
+
+
+ DOM Events
+
+ Test Description: dispatchEvent - EventException UNSPECIFIED_EVENT_TYPE_ERR raises if the Event.type
+ was not specified by initializing the event before dispatchEvent was called.
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.click.checkbox.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.click.checkbox.html
new file mode 100644
index 00000000000..757bb126460
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/dispatchEvent.click.checkbox.html
@@ -0,0 +1,93 @@
+
+
+
+ MouseEvent: Default action and synthetic click event
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent: Default action is performed when a synthetic click event is dispatched on a checkbox element
+
+
+
+ Click Here
+
+
+ Steps:
+
+ Click the button "Click Here"
+
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/error.image.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/error.image.html
new file mode 100644
index 00000000000..3f55ac9bb90
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/error.image.html
@@ -0,0 +1,65 @@
+
+
+
+ W3C DOM Level 3 Event: error
+
+
+
+ Test Description: error event fires when an IMG resource failed to load.
+
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.html
new file mode 100644
index 00000000000..9c89bfafea6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.html
@@ -0,0 +1,61 @@
+
+
+
+ W3C DOM Level 3 Event: focusin
+
+
+
+
+ Test Description:
+ focusin event fires when an event target is about to receive focus.
+
+
+
+ Click here:
+
+
+ Test passes if the word "PASS" appears below after clicking the above textbox using mouse.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.relatedTarget.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.relatedTarget.html
new file mode 100644
index 00000000000..a36d254666d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusin.relatedTarget.html
@@ -0,0 +1,64 @@
+
+
+
+ FocusEvent.relatedTarget for focusin Event
+
+
+
+ DOM Events
+
+ Test Description: FocusEvent.relatedTarget for focusin event is the event target losing focus.
+
+
+
+ BUTTON
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Then click the above button using mouse
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusout.relatedTarget.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusout.relatedTarget.html
new file mode 100644
index 00000000000..bc02267ed7a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/focusout.relatedTarget.html
@@ -0,0 +1,64 @@
+
+
+
+ FocusEvent.relatedTarget for focusout Event
+
+
+
+ DOM Events
+
+ Test Description: FocusEvent.relatedTarget for focusout event is the event target receiving focus.
+
+
+
+ BUTTON
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Then click the above button using mouse
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.Events.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.Events.html
new file mode 100644
index 00000000000..e0c9ba18d82
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.Events.html
@@ -0,0 +1,52 @@
+
+
+
+ DOMImplementation.hasFeature() with Events, 3.0 and 2.0
+
+
+
+ DOM Events
+
+ Test Description: Since DOM Level 3 Events is built on top of DOM Level 2 Events, an
+ implementation that returns true for "Events" and "3.0" shall also return true for the
+ parameters "Events" and "2.0".
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.feature.string.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.feature.string.html
new file mode 100644
index 00000000000..e96c39c8556
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/hasFeature.feature.string.html
@@ -0,0 +1,80 @@
+
+
+
+ DOMImplementation.hasFeature() and Extended Feature String
+
+
+
+ DOM Events
+
+ Test Description: each interface defined in DOM Level 3 Events has a feature string,
+ which may act as a base feature string or as an extended feature string.
+
+
+ Test passes if the word "PASS" appears below.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/load.image.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/load.image.html
new file mode 100644
index 00000000000..1cff3183090
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/load.image.html
@@ -0,0 +1,82 @@
+
+
+
+ W3C DOM Level 3 Event: load
+
+
+
+
+ Test Description:
+ load event fires when the DOM implementation finishes loading the resource (such as the document)
+ and any dependent resources (such as images, style sheets, or scripts).
+
+
+
+
+
+
+ Test passes if the word "PASS" appears below after the above image is loaded.
+ Test result:
+ FAIL
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.ctrlKey.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.ctrlKey.html
new file mode 100644
index 00000000000..dac16046cf9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.ctrlKey.html
@@ -0,0 +1,64 @@
+
+
+
+ MouseEvent.ctrlKey for mouseenter Event
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent.ctrlKey returns true if 'Control' key is depressed, otherwise false.
+
+
+
+
+
+ Steps:
+ 1) Press and hold down the '{CTRL}' key
+ 2) Move the mouse pointer into the image
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.relatedTarget.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.relatedTarget.html
new file mode 100644
index 00000000000..f2d449dae85
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseenter.relatedTarget.html
@@ -0,0 +1,69 @@
+
+
+
+ MouseEvent.relatedTarget for mouseenter Event
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent.relatedTarget for mouseenter event indicates
+ the event target a pointing device is exiting, if any.
+
+
+
+
+
+ BUTTON
+
+
+
+ Steps:
+ 1) Move the mouse pointer into the above green rectangle
+ 2) Then move the mouse pointer onto the button
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseleave.relatedTarget.html b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseleave.relatedTarget.html
new file mode 100644
index 00000000000..37ca7197507
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/mouseleave.relatedTarget.html
@@ -0,0 +1,69 @@
+
+
+
+ MouseEvent.relatedTarget for mouseleave Event
+
+
+
+ DOM Events
+
+ Test Description: MouseEvent.relatedTarget for mouseleave event indicates
+ the event target a pointing device is entering, if any.
+
+
+
+
+
+ BUTTON
+
+
+
+ Steps:
+ 1) Move the mouse pointer onto the above button
+ 2) Then move the mouse pointer out of it
+
+
+ Test passes if the word "PASS" appears below after following the above steps.
+ Test result:
+ FAIL
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/16kb.js b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/16kb.js
new file mode 100644
index 00000000000..bf362ea39bd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/16kb.js
@@ -0,0 +1,140 @@
+var text =
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " ;
+ActualResult.push("SCRIPT:loaded");
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/InvalidBitMap.png b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/InvalidBitMap.png
new file mode 100644
index 00000000000..0a15a8e10d8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/InvalidBitMap.png
@@ -0,0 +1 @@
+Invalid BitMap
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/iepreview.png b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/iepreview.png
new file mode 100644
index 00000000000..63959a05626
Binary files /dev/null and b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/iepreview.png differ
diff --git a/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/style01.css b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/style01.css
new file mode 100644
index 00000000000..205e5bd7f59
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/tests/submissions/Microsoft/support/style01.css
@@ -0,0 +1,3 @@
+BODY {
+ PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #eef0eb; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px
+}
diff --git a/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-and-window-error-event.html b/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-and-window-error-event.html
new file mode 100644
index 00000000000..29841d9ac17
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-and-window-error-event.html
@@ -0,0 +1,33 @@
+
+
+Throwing in event listener generates an error event on the window object
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-when-all-have-not-run-yet.html b/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-when-all-have-not-run-yet.html
new file mode 100644
index 00000000000..52196329bec
--- /dev/null
+++ b/tests/wpt/web-platform-tests/DOMEvents/throwing-in-listener-when-all-have-not-run-yet.html
@@ -0,0 +1,31 @@
+
+
+Throwing in event listener
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test1.js b/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test1.js
new file mode 100644
index 00000000000..34983584999
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test1.js
@@ -0,0 +1 @@
+var test_result = 'test1_OK';
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test2.txt b/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test2.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test3.html b/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test3.html
new file mode 100644
index 00000000000..fa234cb9f99
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/BlobURL/support/file_test3.html
@@ -0,0 +1,25 @@
+
+
+
+
+ Test file
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/test1-manual.html b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test1-manual.html
new file mode 100644
index 00000000000..8da42cf647a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test1-manual.html
@@ -0,0 +1,122 @@
+
+
+
+
+ Blob and File reference URL Test(1)
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download the file .
+ Select the file in the file inputbox to run the test.
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/test2-manual.html b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test2-manual.html
new file mode 100644
index 00000000000..07fb27ef8af
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test2-manual.html
@@ -0,0 +1,62 @@
+
+
+
+
+ Blob and File reference URL Test(2)
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download the file .
+ Select the file in the file inputbox.
+ Delete the file.
+ Click the 'start' button.
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/BlobURL/test3-manual.html b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test3-manual.html
new file mode 100644
index 00000000000..ce020a7b74d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/BlobURL/test3-manual.html
@@ -0,0 +1,71 @@
+
+
+
+
+ Blob and File reference URL Test(3)
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download the file .
+ Select the file in the file inputbox and the test will start.
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/FileReader/Progress_event_bubbles_cancelable.html b/tests/wpt/web-platform-tests/FileAPI/FileReader/Progress_event_bubbles_cancelable.html
new file mode 100644
index 00000000000..6a03243f934
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/FileReader/Progress_event_bubbles_cancelable.html
@@ -0,0 +1,33 @@
+
+
+File API Test: Progress Event - bubbles, cancelable
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/FileReader/support/file_test1.txt b/tests/wpt/web-platform-tests/FileAPI/FileReader/support/file_test1.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/wpt/web-platform-tests/FileAPI/FileReader/test_errors-manual.html b/tests/wpt/web-platform-tests/FileAPI/FileReader/test_errors-manual.html
new file mode 100644
index 00000000000..e0a61200145
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/FileReader/test_errors-manual.html
@@ -0,0 +1,71 @@
+
+
+
+
+ FileReader Errors Test
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download the file .
+ Select the file in the file inputbox.
+ Delete the file.
+ Click the 'start' button.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/FileAPI/FileReaderSync.worker.js b/tests/wpt/web-platform-tests/FileAPI/FileReaderSync.worker.js
new file mode 100644
index 00000000000..77af6a7a6a2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/FileReaderSync.worker.js
@@ -0,0 +1,28 @@
+importScripts("/resources/testharness.js");
+
+var blob, readerSync;
+setup(function() {
+ readerSync = new FileReaderSync();
+ blob = new Blob(["test"]);
+});
+
+test(function() {
+ assert_true(readerSync instanceof FileReaderSync);
+}, "Interface");
+
+test(function() {
+ var text = readerSync.readAsText(blob);
+ assert_equals(text, "test");
+}, "readAsText");
+
+test(function() {
+ var data = readerSync.readAsDataURL(blob);
+ assert_equals(data.indexOf("data:"), 0);
+}, "readAsDataURL");
+
+test(function() {
+ var data = readerSync.readAsArrayBuffer(blob);
+ assert_true(data instanceof ArrayBuffer);
+}, "readAsArrayBuffer");
+
+done();
diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-XHR-revoke.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-XHR-revoke.html
new file mode 100644
index 00000000000..fea313eeee5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-XHR-revoke.html
@@ -0,0 +1,28 @@
+
+Revoking blob URL used with XMLHttpRequest
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-close.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-close.html
new file mode 100644
index 00000000000..8ec8bcca0b6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-close.html
@@ -0,0 +1,29 @@
+
+
+Blob.close
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html
new file mode 100644
index 00000000000..5a5104328f3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-constructor.html
@@ -0,0 +1,498 @@
+
+
+Blob constructor
+
+
+
+
+
+
+
+Discussion
+is ongoing that will affect a number of the following tests.
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/blob/Blob-slice.html b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-slice.html
new file mode 100644
index 00000000000..a66136b10f1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/blob/Blob-slice.html
@@ -0,0 +1,214 @@
+
+
+Blob slice
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html
new file mode 100644
index 00000000000..97c08b6546e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/file/File-constructor.html
@@ -0,0 +1,72 @@
+
+
+File constructor
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/fileReader.html b/tests/wpt/web-platform-tests/FileAPI/fileReader.html
new file mode 100644
index 00000000000..b767e22d4a6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/fileReader.html
@@ -0,0 +1,67 @@
+
+
+
+ FileReader States
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist.html b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist.html
new file mode 100644
index 00000000000..b97dcde19f6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist.html
@@ -0,0 +1,57 @@
+
+
+
+
+ FileAPI Test: filelist
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_multiple_selected_files-manual.html b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_multiple_selected_files-manual.html
new file mode 100644
index 00000000000..2efaa059fa4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_multiple_selected_files-manual.html
@@ -0,0 +1,64 @@
+
+
+
+
+ FileAPI Test: filelist_multiple_selected_files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download upload.txt , upload.zip to local.
+ Select the local two files (upload.txt, upload.zip) to run the test.
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_selected_file-manual.html b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_selected_file-manual.html
new file mode 100644
index 00000000000..966aadda615
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/filelist-section/filelist_selected_file-manual.html
@@ -0,0 +1,64 @@
+
+
+
+
+ FileAPI Test: filelist_selected_file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Test steps:
+
+ Download upload.txt to local.
+ Select the local upload.txt file to run the test.
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.txt b/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.txt
new file mode 100644
index 00000000000..f45965b711f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.txt
@@ -0,0 +1 @@
+Hello, this is test file for file upload.
diff --git a/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.zip b/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.zip
new file mode 100644
index 00000000000..a933d6a9494
Binary files /dev/null and b/tests/wpt/web-platform-tests/FileAPI/filelist-section/support/upload.zip differ
diff --git a/tests/wpt/web-platform-tests/FileAPI/historical.html b/tests/wpt/web-platform-tests/FileAPI/historical.html
new file mode 100644
index 00000000000..3ff56a30164
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/historical.html
@@ -0,0 +1,48 @@
+
+
+
+
+ Historical features
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/idlharness-manual.html b/tests/wpt/web-platform-tests/FileAPI/idlharness-manual.html
new file mode 100644
index 00000000000..8fb0dfb784a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/idlharness-manual.html
@@ -0,0 +1,167 @@
+
+
+
+
+ File API manual IDL tests
+
+
+
+
+
+
+
+
+ File API manual IDL tests
+
+
+
Test steps:
+
+ Download upload.txt to local.
+ Select the local upload.txt file to run the test.
+
+
+
+
+
+
+
+
+
+
+ interface ArrayBuffer {
+ };
+
+ interface ArrayBufferView {
+ };
+
+ interface URL {
+ };
+
+ interface EventTarget {
+ };
+
+ interface Event {
+ };
+
+ [TreatNonCallableAsNull]
+ callback EventHandlerNonNull = any (Event event);
+ typedef EventHandlerNonNull? EventHandler;
+
+
+
+[Constructor,
+ Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> blobParts, optional BlobPropertyBag options), Exposed=Window,Worker]
+interface Blob {
+
+ readonly attribute unsigned long long size;
+ readonly attribute DOMString type;
+ readonly attribute boolean isClosed;
+
+ //slice Blob into byte-ranged chunks
+
+ Blob slice([Clamp] optional long long start,
+ [Clamp] optional long long end,
+ optional DOMString contentType);
+ void close();
+
+};
+
+dictionary BlobPropertyBag {
+ DOMString type = "";
+};
+
+[Constructor(sequence<(Blob or DOMString or ArrayBufferView or ArrayBuffer)> fileBits,
+[EnsureUTF16] DOMString fileName, optional FilePropertyBag options), Exposed=Window,Worker]
+interface File : Blob {
+
+ readonly attribute DOMString name;
+ readonly attribute long long lastModified;
+
+};
+
+dictionary FilePropertyBag {
+
+ DOMString type = "";
+ long long lastModified;
+
+};
+
+[Exposed=Window,Worker] interface FileList {
+ getter File? item(unsigned long index);
+ readonly attribute unsigned long length;
+};
+
+[Constructor, Exposed=Window,Worker]
+interface FileReader: EventTarget {
+
+ // async read methods
+ void readAsArrayBuffer(Blob blob);
+ void readAsText(Blob blob, optional DOMString label);
+ void readAsDataURL(Blob blob);
+
+ void abort();
+
+ // states
+ const unsigned short EMPTY = 0;
+ const unsigned short LOADING = 1;
+ const unsigned short DONE = 2;
+
+ readonly attribute unsigned short readyState;
+
+ // File or Blob data
+ readonly attribute (DOMString or ArrayBuffer)? result;
+
+ readonly attribute DOMError? error;
+
+ // event handler attributes
+ attribute EventHandler onloadstart;
+ attribute EventHandler onprogress;
+ attribute EventHandler onload;
+ attribute EventHandler onabort;
+ attribute EventHandler onerror;
+ attribute EventHandler onloadend;
+
+};
+
+[Constructor, Exposed=Worker]
+interface FileReaderSync {
+
+ // Synchronously return strings
+
+ ArrayBuffer readAsArrayBuffer(Blob blob);
+ DOMString readAsText(Blob blob, optional DOMString label);
+ DOMString readAsDataURL(Blob blob);
+};
+
+partial interface URL {
+
+ static DOMString createObjectURL(Blob blob);
+ static DOMString createFor(Blob blob);
+ static void revokeObjectURL(DOMString url);
+
+};
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/idlharness.html b/tests/wpt/web-platform-tests/FileAPI/idlharness.html
new file mode 100644
index 00000000000..64a9c8508b3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/idlharness.html
@@ -0,0 +1,158 @@
+
+
+
+
+ File API automated IDL tests
+
+
+
+
+
+
+
+
+ File API automated IDL tests
+
+
+
+
+ interface ArrayBuffer {
+ };
+
+ interface ArrayBufferView {
+ };
+
+ interface URL {
+ };
+
+ interface EventTarget {
+ };
+
+ interface Event {
+ };
+
+ [TreatNonCallableAsNull]
+ callback EventHandlerNonNull = any (Event event);
+ typedef EventHandlerNonNull? EventHandler;
+
+
+
+[Constructor,
+ Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> blobParts, optional BlobPropertyBag options), Exposed=Window,Worker]
+interface Blob {
+
+ readonly attribute unsigned long long size;
+ readonly attribute DOMString type;
+ readonly attribute boolean isClosed;
+
+ //slice Blob into byte-ranged chunks
+
+ Blob slice([Clamp] optional long long start,
+ [Clamp] optional long long end,
+ optional DOMString contentType);
+ void close();
+
+};
+
+dictionary BlobPropertyBag {
+ DOMString type = "";
+};
+
+[Constructor(sequence<(Blob or DOMString or ArrayBufferView or ArrayBuffer)> fileBits,
+[EnsureUTF16] DOMString fileName, optional FilePropertyBag options), Exposed=Window,Worker]
+interface File : Blob {
+
+ readonly attribute DOMString name;
+ readonly attribute long long lastModified;
+
+};
+
+dictionary FilePropertyBag {
+
+ DOMString type = "";
+ long long lastModified;
+
+};
+
+[Exposed=Window,Worker] interface FileList {
+ getter File? item(unsigned long index);
+ readonly attribute unsigned long length;
+};
+
+[Constructor, Exposed=Window,Worker]
+interface FileReader: EventTarget {
+
+ // async read methods
+ void readAsArrayBuffer(Blob blob);
+ void readAsText(Blob blob, optional DOMString label);
+ void readAsDataURL(Blob blob);
+
+ void abort();
+
+ // states
+ const unsigned short EMPTY = 0;
+ const unsigned short LOADING = 1;
+ const unsigned short DONE = 2;
+
+ readonly attribute unsigned short readyState;
+
+ // File or Blob data
+ readonly attribute (DOMString or ArrayBuffer)? result;
+
+ readonly attribute DOMError? error;
+
+ // event handler attributes
+ attribute EventHandler onloadstart;
+ attribute EventHandler onprogress;
+ attribute EventHandler onload;
+ attribute EventHandler onabort;
+ attribute EventHandler onerror;
+ attribute EventHandler onloadend;
+
+};
+
+[Constructor, Exposed=Worker]
+interface FileReaderSync {
+
+ // Synchronously return strings
+
+ ArrayBuffer readAsArrayBuffer(Blob blob);
+ DOMString readAsText(Blob blob, optional DOMString label);
+ DOMString readAsDataURL(Blob blob);
+};
+
+partial interface URL {
+
+ static DOMString createObjectURL(Blob blob);
+ static DOMString createFor(Blob blob);
+ static void revokeObjectURL(DOMString url);
+
+};
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/progress.html b/tests/wpt/web-platform-tests/FileAPI/progress.html
new file mode 100644
index 00000000000..b2e03b3eb27
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/progress.html
@@ -0,0 +1,49 @@
+
+
+Process Events for FileReader
+
+
+
+
+Please choose one file through this input below.
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/Determining-Encoding.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/Determining-Encoding.html
new file mode 100644
index 00000000000..d65ae9db18a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/Determining-Encoding.html
@@ -0,0 +1,91 @@
+
+
+FileAPI Test: Blob Determining Encoding
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-event-handler-attributes.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-event-handler-attributes.html
new file mode 100644
index 00000000000..86657b5711a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-event-handler-attributes.html
@@ -0,0 +1,23 @@
+
+
+FileReader event handler attributes
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-multiple-reads.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-multiple-reads.html
new file mode 100644
index 00000000000..86a29d187b5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/FileReader-multiple-reads.html
@@ -0,0 +1,73 @@
+
+FileReader: starting new reads while one is in progress
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_abort.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_abort.html
new file mode 100644
index 00000000000..a96389c21d6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_abort.html
@@ -0,0 +1,46 @@
+
+
+
+
+ FileAPI Test: filereader_abort
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_error.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_error.html
new file mode 100644
index 00000000000..cf4524825b8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_error.html
@@ -0,0 +1,35 @@
+
+
+
+
+ FileAPI Test: filereader_error
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file-manual.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file-manual.html
new file mode 100644
index 00000000000..702ca9afd7b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file-manual.html
@@ -0,0 +1,69 @@
+
+
+
+
+ FileAPI Test: filereader_file
+
+
+
+
+
+
+
+
+
Test step:
+
+ Download blue-100x100.png to local.
+ Select the local file (blue-100x100.png) to run the test.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file_img-manual.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file_img-manual.html
new file mode 100644
index 00000000000..fca42c7fceb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_file_img-manual.html
@@ -0,0 +1,47 @@
+
+
+
+
+ FileAPI Test: filereader_file_img
+
+
+
+
+
+
+
+
+
Test step:
+
+ Download blue-100x100.png to local.
+ Select the local file (blue-100x100.png) to run the test.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html
new file mode 100644
index 00000000000..31001a51a07
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html
@@ -0,0 +1,38 @@
+
+
+
+
+ FileAPI Test: filereader_readAsArrayBuffer
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsDataURL.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsDataURL.html
new file mode 100644
index 00000000000..f0a3957e760
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsDataURL.html
@@ -0,0 +1,39 @@
+
+
+
+
+ FileAPI Test: filereader_readAsDataURL
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsText.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsText.html
new file mode 100644
index 00000000000..7d639d01114
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readAsText.html
@@ -0,0 +1,51 @@
+
+
+
+
+ FileAPI Test: filereader_readAsText
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readystate.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readystate.html
new file mode 100644
index 00000000000..1586b899505
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_readystate.html
@@ -0,0 +1,34 @@
+
+
+
+
+ FileAPI Test: filereader_readystate
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_result.html b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_result.html
new file mode 100644
index 00000000000..957d0337a75
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/filereader_result.html
@@ -0,0 +1,59 @@
+
+
+
+
+ FileAPI Test: filereader_result
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/reading-data-section/support/blue-100x100.png b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/support/blue-100x100.png
new file mode 100644
index 00000000000..5748719ff22
Binary files /dev/null and b/tests/wpt/web-platform-tests/FileAPI/reading-data-section/support/blue-100x100.png differ
diff --git a/tests/wpt/web-platform-tests/FileAPI/support/Blob.js b/tests/wpt/web-platform-tests/FileAPI/support/Blob.js
new file mode 100644
index 00000000000..1d66f23a604
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/support/Blob.js
@@ -0,0 +1,49 @@
+function test_blob(fn, expectations) {
+ var expected = expectations.expected,
+ type = expectations.type,
+ desc = expectations.desc;
+
+ var t = async_test(desc);
+ t.step(function() {
+ var blob = fn();
+ assert_true(blob instanceof Blob);
+ assert_false(blob instanceof File);
+ assert_equals(blob.type, type);
+ assert_equals(blob.size, expected.length);
+
+ var fr = new FileReader();
+ fr.onload = t.step_func_done(function(event) {
+ assert_equals(this.result, expected);
+ }, fr);
+ fr.onerror = t.step_func(function(e) {
+ assert_unreached("got error event on FileReader");
+ });
+ fr.readAsText(blob, "UTF-8");
+ });
+}
+
+function test_blob_binary(fn, expectations) {
+ var expected = expectations.expected,
+ type = expectations.type,
+ desc = expectations.desc;
+
+ var t = async_test(desc);
+ t.step(function() {
+ var blob = fn();
+ assert_true(blob instanceof Blob);
+ assert_false(blob instanceof File);
+ assert_equals(blob.type, type);
+ assert_equals(blob.size, expected.length);
+
+ var fr = new FileReader();
+ fr.onload = t.step_func_done(function(event) {
+ assert_true(this.result instanceof ArrayBuffer,
+ "Result should be an ArrayBuffer");
+ assert_array_equals(new Uint8Array(this.result), expected);
+ }, fr);
+ fr.onerror = t.step_func(function(e) {
+ assert_unreached("got error event on FileReader");
+ });
+ fr.readAsArrayBuffer(blob);
+ });
+}
diff --git a/tests/wpt/web-platform-tests/FileAPI/support/upload.txt b/tests/wpt/web-platform-tests/FileAPI/support/upload.txt
new file mode 100644
index 00000000000..5ab2f8a4323
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/support/upload.txt
@@ -0,0 +1 @@
+Hello
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_blob.html b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_blob.html
new file mode 100644
index 00000000000..db6b44180ec
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_blob.html
@@ -0,0 +1,26 @@
+
+
+FileAPI Test: Creating Blob URL with Blob
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file-manual.html b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file-manual.html
new file mode 100644
index 00000000000..5dcd1d49e7c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file-manual.html
@@ -0,0 +1,51 @@
+
+
+FileAPI Test: Creating Blob URL with File
+
+
+
+
+
+
+
+
Test steps:
+
+ Download blue96x96.png to local.
+ Select the local file (blue96x96.png) to run the test.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file_img-manual.html b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file_img-manual.html
new file mode 100644
index 00000000000..534c1de9968
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_createobjecturl_file_img-manual.html
@@ -0,0 +1,28 @@
+
+
+FileAPI Test: Creating Blob URL with File as image source
+
+
+
+
+
Test steps:
+
+ Download blue96x96.png to local.
+ Select the local file (blue96x96.png) to run the test.
+
+
Pass/fail criteria:
+
Test passes if there is a filled blue square.
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest.html b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest.html
new file mode 100644
index 00000000000..7a86cdd1e80
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest.html
@@ -0,0 +1,29 @@
+
+
+FileAPI Test: Creating Blob URL via XMLHttpRequest
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img-ref.html b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img-ref.html
new file mode 100644
index 00000000000..7d7390442d3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img-ref.html
@@ -0,0 +1,12 @@
+
+
+FileAPI Reference File
+
+
+
+Test passes if there is a filled blue square.
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html
new file mode 100644
index 00000000000..7f26633d81e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/FileAPI/url/url_xmlhttprequest_img.html
@@ -0,0 +1,28 @@
+
+
+
+FileAPI Test: Creating Blob URL via XMLHttpRequest as image source
+
+
+
+
+Test passes if there is a filled blue square.
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/README.md b/tests/wpt/web-platform-tests/IndexedDB/README.md
new file mode 100644
index 00000000000..6b636d5f1a4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/README.md
@@ -0,0 +1,8 @@
+This directory contains the Indexed Database API test suite.
+
+To run the tests in this test suite within a browser, go to: .
+
+The latest Editor's Draft of Indexed Database API is: .
+
+The latest W3C Technical Report of Indexed Database API is: .
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/abort-in-initial-upgradeneeded.html b/tests/wpt/web-platform-tests/IndexedDB/abort-in-initial-upgradeneeded.html
new file mode 100644
index 00000000000..6330ecb02e9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/abort-in-initial-upgradeneeded.html
@@ -0,0 +1,35 @@
+
+
+Test that an abort in the initial upgradeneeded sets version back to 0
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/close-in-upgradeneeded.html b/tests/wpt/web-platform-tests/IndexedDB/close-in-upgradeneeded.html
new file mode 100644
index 00000000000..eda823a21f1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/close-in-upgradeneeded.html
@@ -0,0 +1,39 @@
+
+
+When db.close is called in upgradeneeded, the db is cleaned up on refresh
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/cursor-overloads.htm b/tests/wpt/web-platform-tests/IndexedDB/cursor-overloads.htm
new file mode 100644
index 00000000000..343e5a4cc1f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/cursor-overloads.htm
@@ -0,0 +1,88 @@
+
+
+
+
+
+Validate the overloads of IDBObjectStore.openCursor(), IDBIndex.openCursor() and IDBIndex.openKeyCursor()
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idb_webworkers.htm b/tests/wpt/web-platform-tests/IndexedDB/idb_webworkers.htm
new file mode 100644
index 00000000000..dba3a93f120
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idb_webworkers.htm
@@ -0,0 +1,33 @@
+
+IndexedDB inside of a WebWorker
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-continue-async.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-continue-async.htm
new file mode 100644
index 00000000000..d1b6af3e189
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-continue-async.htm
@@ -0,0 +1,186 @@
+
+IDBCursor asyncness
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-invalid.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-invalid.htm
new file mode 100644
index 00000000000..dda216b7531
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance-invalid.htm
@@ -0,0 +1,188 @@
+
+IDBCursor.advance() - invalid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance.htm
new file mode 100644
index 00000000000..f4ecbc0e5aa
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-advance.htm
@@ -0,0 +1,243 @@
+
+IDBCursor.advance()
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-continue.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-continue.htm
new file mode 100644
index 00000000000..968cd9cbd09
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-continue.htm
@@ -0,0 +1,240 @@
+
+IDBCursor.continue()
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index-keyrange.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index-keyrange.htm
new file mode 100644
index 00000000000..c3f9340370d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index-keyrange.htm
@@ -0,0 +1,82 @@
+
+IDBCursor direction - index with keyrange
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index.htm
new file mode 100644
index 00000000000..39afcb24d86
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-index.htm
@@ -0,0 +1,81 @@
+
+IDBCursor direction - index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm
new file mode 100644
index 00000000000..2b2bf04bfd6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore-keyrange.htm
@@ -0,0 +1,77 @@
+
+IDBCursor direction - object store with keyrange
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore.htm
new file mode 100644
index 00000000000..c02355395a2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction-objectstore.htm
@@ -0,0 +1,80 @@
+
+IDBCursor direction - object store
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction.htm
new file mode 100644
index 00000000000..b50eded7908
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-direction.htm
@@ -0,0 +1,73 @@
+
+IDBCursor.direction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-key.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-key.htm
new file mode 100644
index 00000000000..7b10b99e225
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-key.htm
@@ -0,0 +1,57 @@
+
+IDBCursor.key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-primarykey.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-primarykey.htm
new file mode 100644
index 00000000000..04b4a14a07b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-primarykey.htm
@@ -0,0 +1,61 @@
+
+IDBCursor.primaryKey
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-reused.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-reused.htm
new file mode 100644
index 00000000000..603041e7cdf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-reused.htm
@@ -0,0 +1,69 @@
+
+IDBCursor is reused
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor-source.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-source.htm
new file mode 100644
index 00000000000..7e3746ae7e6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor-source.htm
@@ -0,0 +1,68 @@
+
+IDBCursor.source
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index.htm
new file mode 100644
index 00000000000..8f2d0c65182
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index.htm
@@ -0,0 +1,57 @@
+
+IDBCursor.advance() - index - iterate cursor number of times specified by count
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index2.htm
new file mode 100644
index 00000000000..539c824e61e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index2.htm
@@ -0,0 +1,47 @@
+
+IDBCursor.advance() - attempt to pass a count parameter that is not a number
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index3.htm
new file mode 100644
index 00000000000..5adf3f077fd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index3.htm
@@ -0,0 +1,47 @@
+
+IDBCursor.advance() - index - attempt to advance backwards
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index5.htm
new file mode 100644
index 00000000000..452c0f142f6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index5.htm
@@ -0,0 +1,55 @@
+
+IDBCursor.advance() - index - iterate to the next record
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index6.htm
new file mode 100644
index 00000000000..826cb1e1a0e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index6.htm
@@ -0,0 +1,37 @@
+
+
+IDBCursor.advance() - index - throw TypeError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index7.htm
new file mode 100644
index 00000000000..8da5b618d45
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index7.htm
@@ -0,0 +1,39 @@
+
+
+IDBCursor.advance() - index - throw TransactionInactiveError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index8.htm
new file mode 100644
index 00000000000..b5e64d4cdce
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index8.htm
@@ -0,0 +1,38 @@
+
+
+IDBCursor.advance() - index - throw InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index9.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index9.htm
new file mode 100644
index 00000000000..517a573c49e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_index9.htm
@@ -0,0 +1,37 @@
+
+
+IDBCursor.advance() - index - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore.htm
new file mode 100644
index 00000000000..bf7cb70fb60
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore.htm
@@ -0,0 +1,54 @@
+
+ IDBCursor.advance() - object store - iterate cursor number of times specified by count
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore2.htm
new file mode 100644
index 00000000000..32478c141ea
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore2.htm
@@ -0,0 +1,40 @@
+
+
+IDBCursor.advance() - object store - throw TypeError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore3.htm
new file mode 100644
index 00000000000..1accd6631a0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore3.htm
@@ -0,0 +1,42 @@
+
+
+IDBCursor.advance() - object store - throw TransactionInactiveError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore4.htm
new file mode 100644
index 00000000000..387973169d0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore4.htm
@@ -0,0 +1,41 @@
+
+
+IDBCursor.advance() - object store - throw InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore5.htm
new file mode 100644
index 00000000000..cb0859c636e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_advance_objectstore5.htm
@@ -0,0 +1,36 @@
+
+
+IDBCursor.advance() - object store - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index.htm
new file mode 100644
index 00000000000..8b0d079a939
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index.htm
@@ -0,0 +1,52 @@
+
+IDBCursor.continue() - index - iterate to the next record
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index2.htm
new file mode 100644
index 00000000000..d0eaef3d074
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index2.htm
@@ -0,0 +1,49 @@
+
+IDBCursor.continue() - index - attempt to pass a key parameter that is not a valid key
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index3.htm
new file mode 100644
index 00000000000..357dc157f35
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index3.htm
@@ -0,0 +1,54 @@
+
+IDBCursor.continue() - index - attempt to iterate to the previous record when the direction is set for the next record
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index4.htm
new file mode 100644
index 00000000000..c5cfd85ebdb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index4.htm
@@ -0,0 +1,65 @@
+
+IDBCursor.continue() - index - attempt to iterate to the next record when the direction is set for the previous record
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index5.htm
new file mode 100644
index 00000000000..abe0e658b01
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index5.htm
@@ -0,0 +1,64 @@
+
+IDBCursor.continue() - index - iterate using 'prevunique'
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index6.htm
new file mode 100644
index 00000000000..cf5bd4066e8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index6.htm
@@ -0,0 +1,64 @@
+
+IDBCursor.continue() - index - iterate using nextunique
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index7.htm
new file mode 100644
index 00000000000..fed235685c7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index7.htm
@@ -0,0 +1,38 @@
+
+
+IDBCursor.continue() - index - throw TransactionInactiveError
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index8.htm
new file mode 100644
index 00000000000..4a574ec90f4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_index8.htm
@@ -0,0 +1,38 @@
+
+
+IDBCursor.continue() - index - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_invalid.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_invalid.htm
new file mode 100644
index 00000000000..dea07bc9112
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_invalid.htm
@@ -0,0 +1,54 @@
+
+IDBCursor.continue() - attempt to call continue two times
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore.htm
new file mode 100644
index 00000000000..76750c969a4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore.htm
@@ -0,0 +1,46 @@
+
+IDBCursor.continue() - object store - iterate to the next record
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore2.htm
new file mode 100644
index 00000000000..14502330b80
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore2.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.continue() - object store - attempt to pass a key parameter is not a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore3.htm
new file mode 100644
index 00000000000..a059b62e53a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore3.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.continue() - object store - attempt to iterate to the previous record when the direction is set for the next record
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore4.htm
new file mode 100644
index 00000000000..b4819c73300
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore4.htm
@@ -0,0 +1,57 @@
+
+IDBCursor.continue() - object store - attempt to iterate to the next record when the direction is set for the previous record
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore5.htm
new file mode 100644
index 00000000000..3c1943336c3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore5.htm
@@ -0,0 +1,42 @@
+
+
+IDBCursor.continue() - object store - throw TransactionInactiveError
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore6.htm
new file mode 100644
index 00000000000..f9d656ebf89
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_continue_objectstore6.htm
@@ -0,0 +1,37 @@
+
+
+IDBCursor.continue() - object store - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index.htm
new file mode 100644
index 00000000000..8cddcea994f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index.htm
@@ -0,0 +1,69 @@
+
+IDBCursor.delete() - index - remove a record from the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index2.htm
new file mode 100644
index 00000000000..a5147f75450
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index2.htm
@@ -0,0 +1,42 @@
+
+IDBCursor.delete() - index - attempt to remove a record in a read-only transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index3.htm
new file mode 100644
index 00000000000..bb5722ee351
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index3.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.delete() - index - attempt to remove a record in an inactive transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index4.htm
new file mode 100644
index 00000000000..9b57bd681a9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index4.htm
@@ -0,0 +1,38 @@
+
+
+IDBCursor.delete() - index - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index5.htm
new file mode 100644
index 00000000000..66eacdebe66
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_index5.htm
@@ -0,0 +1,39 @@
+
+
+IDBCursor.delete() - index - throw InvalidStateError when the cursor is being iterated
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore.htm
new file mode 100644
index 00000000000..044a4e57183
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore.htm
@@ -0,0 +1,65 @@
+
+IDBCursor.delete() - object store - remove a record from the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore2.htm
new file mode 100644
index 00000000000..69521e66b79
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore2.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.delete() - object store - attempt to remove a record in a read-only transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore3.htm
new file mode 100644
index 00000000000..bdb8d93c34f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore3.htm
@@ -0,0 +1,39 @@
+
+IDBCursor.delete() - index - attempt to remove a record in an inactive transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore4.htm
new file mode 100644
index 00000000000..47bcd8b0057
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore4.htm
@@ -0,0 +1,37 @@
+
+
+IDBCursor.delete() - object store - throw InvalidStateError caused by object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore5.htm
new file mode 100644
index 00000000000..b37e26126a9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_delete_objectstore5.htm
@@ -0,0 +1,41 @@
+
+
+IDBCursor.delete() - object store - throw InvalidStateError when the cursor is being iterated
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating.htm
new file mode 100644
index 00000000000..fd3cd0a690d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating.htm
@@ -0,0 +1,110 @@
+
+IDBCursor.continue() - objectstore - delete next element, and iterate to it
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index.htm
new file mode 100644
index 00000000000..559cce6db54
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index.htm
@@ -0,0 +1,53 @@
+
+IDBCursor.continue() - index - delete next element, and iterate to it
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index2.htm
new file mode 100644
index 00000000000..91a8383500c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_index2.htm
@@ -0,0 +1,53 @@
+
+IDBCursor.continue() - index - add next element, and iterate to it
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore.htm
new file mode 100644
index 00000000000..db66c4db33b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore.htm
@@ -0,0 +1,51 @@
+
+IDBCursor.continue() - objectstore - delete next element, and iterate to it
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore2.htm
new file mode 100644
index 00000000000..2374a854e44
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_iterating_objectstore2.htm
@@ -0,0 +1,51 @@
+
+IDBCursor.continue() - objectstore - add next element, and iterate to it
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index.htm
new file mode 100644
index 00000000000..5fa1f940a99
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index.htm
@@ -0,0 +1,64 @@
+
+IDBCursor.update() - index - modify a record in the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index2.htm
new file mode 100644
index 00000000000..03f9c2712cb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index2.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.update() - index - attempt to modify a record in a read-only transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index3.htm
new file mode 100644
index 00000000000..0f7b2a1dbe5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index3.htm
@@ -0,0 +1,41 @@
+
+IDBCursor.update() - index - attempt to modify a record in an inactive transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index4.htm
new file mode 100644
index 00000000000..ee60da0d214
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index4.htm
@@ -0,0 +1,39 @@
+
+
+IDBCursor.update() - index - attempt to modify a record when object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index5.htm
new file mode 100644
index 00000000000..a31528d1658
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index5.htm
@@ -0,0 +1,45 @@
+
+IDBCursor.update() - index - throw DataCloneError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index6.htm
new file mode 100644
index 00000000000..1e51b1354cf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index6.htm
@@ -0,0 +1,41 @@
+
+IDBCursor.update() - index - no argument
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index7.htm
new file mode 100644
index 00000000000..1d464fbcdee
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_index7.htm
@@ -0,0 +1,41 @@
+
+IDBCursor.update() - index - throw DataError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore.htm
new file mode 100644
index 00000000000..8aa6a13721d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore.htm
@@ -0,0 +1,60 @@
+
+IDBCursor.update() - objectstore - modify a record in the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore2.htm
new file mode 100644
index 00000000000..65c87bd9536
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore2.htm
@@ -0,0 +1,38 @@
+
+IDBCursor.update() - object store - attempt to modify a record in a read-only transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore3.htm
new file mode 100644
index 00000000000..0ce59de29c9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore3.htm
@@ -0,0 +1,40 @@
+
+IDBCursor.update() - object store - attempt to modify a record in an inactive transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore4.htm
new file mode 100644
index 00000000000..cbd0b1f92a6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore4.htm
@@ -0,0 +1,39 @@
+
+IDBCursor.update() - index - modify a record in the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore5.htm
new file mode 100644
index 00000000000..5dfb82ca19d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore5.htm
@@ -0,0 +1,41 @@
+
+
+IDBCursor.update() - object store - attempt to modify a record when object store been deleted
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore6.htm
new file mode 100644
index 00000000000..16aa00dfae0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore6.htm
@@ -0,0 +1,43 @@
+
+IDBCursor.update() - object store - throw DataCloneError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore7.htm
new file mode 100644
index 00000000000..b1b736cf0ce
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore7.htm
@@ -0,0 +1,39 @@
+
+IDBCursor.update() - object store - no argument
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore8.htm
new file mode 100644
index 00000000000..f0b8900d4b0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbcursor_update_objectstore8.htm
@@ -0,0 +1,39 @@
+
+IDBCursor.update() - object store - throw DataError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close.htm
new file mode 100644
index 00000000000..46485a4303c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close.htm
@@ -0,0 +1,43 @@
+
+IDBDatabase.close() - unblock the version change transaction created by an open database request
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close2.htm
new file mode 100644
index 00000000000..68bafb94638
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_close2.htm
@@ -0,0 +1,39 @@
+
+IDBDatabase.close() - unblock the delete database request
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore-createIndex-emptyname.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore-createIndex-emptyname.htm
new file mode 100644
index 00000000000..97f860a7a8f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore-createIndex-emptyname.htm
@@ -0,0 +1,45 @@
+
+
+IDBDatabase.createObjectStore() and IDBObjectStore.createIndex() - both with empty name
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore.htm
new file mode 100644
index 00000000000..36fe9325001
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore.htm
@@ -0,0 +1,29 @@
+
+IDBDatabase.createObjectStore() - returns an instance of IDBObjectStore
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-1000ends.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-1000ends.htm
new file mode 100644
index 00000000000..d6e4a48ed1c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-1000ends.htm
@@ -0,0 +1,37 @@
+
+IDBDatabase.createObjectStore() - create 1000 object stores, add one item and delete
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-emptyname.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-emptyname.htm
new file mode 100644
index 00000000000..cee4754a8eb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore10-emptyname.htm
@@ -0,0 +1,38 @@
+
+
+IDBDatabase.createObjectStore() - empty name
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore11.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore11.htm
new file mode 100644
index 00000000000..8d98953e065
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore11.htm
@@ -0,0 +1,25 @@
+
+
+IDBDatabase.createObjectStore() - Attampt Create Exsists Object Store With Difference keyPath throw ConstraintError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore2.htm
new file mode 100644
index 00000000000..78f06ff9b90
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore2.htm
@@ -0,0 +1,33 @@
+
+IDBDatabase.createObjectStore() - object store 'name' and 'keyPath' properties are correctly set
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore3.htm
new file mode 100644
index 00000000000..ccf4a2b5fde
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore3.htm
@@ -0,0 +1,24 @@
+
+IDBDatabase.createObjectStore() - attempt to create an object store outside of a version change transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore4.htm
new file mode 100644
index 00000000000..07d787bd9a1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore4.htm
@@ -0,0 +1,27 @@
+
+IDBDatabase.createObjectStore() - attempt to create an object store that already exists
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore5.htm
new file mode 100644
index 00000000000..7e205096e4c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore5.htm
@@ -0,0 +1,33 @@
+
+IDBDatabase.createObjectStore() - object store's name appears in database's list
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore6.htm
new file mode 100644
index 00000000000..c1200c5f93a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore6.htm
@@ -0,0 +1,30 @@
+
+IDBDatabase.createObjectStore() - attempt to create an object store with an invalid key path
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore7.htm
new file mode 100644
index 00000000000..358baeeecab
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore7.htm
@@ -0,0 +1,25 @@
+
+IDBDatabase.createObjectStore() - create an object store with an unknown optional parameter
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore8-parameters.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore8-parameters.htm
new file mode 100644
index 00000000000..48a9993858c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore8-parameters.htm
@@ -0,0 +1,38 @@
+
+
+IDBObjectStoreParameters
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm
new file mode 100644
index 00000000000..0a6dc03a67a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm
@@ -0,0 +1,29 @@
+
+
+createObjectStore: Invalid optionalParameters
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore.htm
new file mode 100644
index 00000000000..b69570cc063
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore.htm
@@ -0,0 +1,25 @@
+
+IDBDatabase.deleteObjectStore() - object store's name is removed from database's list
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore2.htm
new file mode 100644
index 00000000000..3c1abe63232
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore2.htm
@@ -0,0 +1,31 @@
+
+IDBDatabase.deleteObjectStore() - attempt to remove an object store outside of a version change transaction
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore3.htm
new file mode 100644
index 00000000000..cae00f9d220
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore3.htm
@@ -0,0 +1,23 @@
+
+IDBDatabase.deleteObjectStore() - attempt to remove an object store that does not exist
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore4-not_reused.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore4-not_reused.htm
new file mode 100644
index 00000000000..f724d092ba2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_deleteObjectStore4-not_reused.htm
@@ -0,0 +1,42 @@
+
+
+IDBDatabase.deleteObjectStore() - the object store is not reused
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction.htm
new file mode 100644
index 00000000000..94de8b43342
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction.htm
@@ -0,0 +1,24 @@
+
+IDBDatabase.transaction() - attempt to open a transaction with invalid scope
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction2.htm
new file mode 100644
index 00000000000..310014bc510
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction2.htm
@@ -0,0 +1,27 @@
+
+IDBDatabase.transaction() - opening a transaction defaults to a read-only mode
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction3.htm
new file mode 100644
index 00000000000..9b353c7108f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction3.htm
@@ -0,0 +1,28 @@
+
+IDBDatabase.transaction() - attempt to open a transaction from closed database connection
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction4.htm
new file mode 100644
index 00000000000..515c499b0c8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction4.htm
@@ -0,0 +1,26 @@
+
+IDBDatabase.transaction() - attempt to open a transaction with invalid mode
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction5.htm
new file mode 100644
index 00000000000..b6b45ab9f28
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbdatabase_transaction5.htm
@@ -0,0 +1,22 @@
+
+
+IDBDatabase.transaction() - If storeNames is an empty list, the implementation must throw a DOMException of type InvalidAccessError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp.htm
new file mode 100644
index 00000000000..7b301ece46d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp.htm
@@ -0,0 +1,21 @@
+
+
+IDBFactory.cmp() - compared keys return correct value
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp2.htm
new file mode 100644
index 00000000000..446bb465ce6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_cmp2.htm
@@ -0,0 +1,41 @@
+
+
+IDBFactory.cmp() - invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase.htm
new file mode 100644
index 00000000000..fd7a908d3d8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase.htm
@@ -0,0 +1,25 @@
+
+IDBFactory.deleteDatabase() - request has no source
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase2.htm
new file mode 100644
index 00000000000..0c7c73a28fc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase2.htm
@@ -0,0 +1,27 @@
+
+IDBFactory.deleteDatabase() - result of the request is set to undefined
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase3.htm
new file mode 100644
index 00000000000..e1cab41a5c1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase3.htm
@@ -0,0 +1,33 @@
+
+IDBFactory.deleteDatabase() - success event
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase4.htm
new file mode 100644
index 00000000000..3a4e9944da5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_deleteDatabase4.htm
@@ -0,0 +1,58 @@
+
+Test events opening a second database when one connection is open already
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open.htm
new file mode 100644
index 00000000000..bca2cfdc801
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open.htm
@@ -0,0 +1,18 @@
+
+IDBFactory.open() - request has no source
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open10.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open10.htm
new file mode 100644
index 00000000000..598046ff98f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open10.htm
@@ -0,0 +1,91 @@
+
+IDBFactory.open() - error in upgradeneeded resets db
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open11.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open11.htm
new file mode 100644
index 00000000000..66ea9d52559
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open11.htm
@@ -0,0 +1,60 @@
+
+IDBFactory.open() - second open's transaction is available to get objectStores
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open12.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open12.htm
new file mode 100644
index 00000000000..763c4805155
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open12.htm
@@ -0,0 +1,50 @@
+
+IDBFactory.open() - upgradeneeded gets VersionChangeEvent
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open2.htm
new file mode 100644
index 00000000000..e4d54ee0a13
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open2.htm
@@ -0,0 +1,20 @@
+
+IDBFactory.open() - database 'name' and 'version' are correctly set
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open3.htm
new file mode 100644
index 00000000000..9ec6db5ab86
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open3.htm
@@ -0,0 +1,27 @@
+
+IDBFactory.open() - no version opens current database
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open4.htm
new file mode 100644
index 00000000000..15ca666b816
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open4.htm
@@ -0,0 +1,20 @@
+
+IDBFactory.open() - new database has default version
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open5.htm
new file mode 100644
index 00000000000..d9460bb7eda
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open5.htm
@@ -0,0 +1,18 @@
+
+IDBFactory.open() - new database is empty
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open6.htm
new file mode 100644
index 00000000000..bbb8ac02d37
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open6.htm
@@ -0,0 +1,34 @@
+
+IDBFactory.open() - open database with a lower version than current
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open7.htm
new file mode 100644
index 00000000000..bd168f7557e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open7.htm
@@ -0,0 +1,38 @@
+
+IDBFactory.open() - open database with a higher version than current
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open8.htm
new file mode 100644
index 00000000000..7e2ac93ec06
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open8.htm
@@ -0,0 +1,27 @@
+
+IDBFactory.open() - error in version change transaction aborts open
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open9.htm b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open9.htm
new file mode 100644
index 00000000000..d9f392cfdc3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbfactory_open9.htm
@@ -0,0 +1,60 @@
+
+IDBFactory.open() - errors in version argument
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-arraykeypath.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-arraykeypath.htm
new file mode 100644
index 00000000000..3e584a6c4e2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-arraykeypath.htm
@@ -0,0 +1,23 @@
+
+
+IDBIndex.multiEntry: array keyPath with multiEntry
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-big.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-big.htm
new file mode 100644
index 00000000000..4f9df36e204
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry-big.htm
@@ -0,0 +1,58 @@
+
+
+IDBIndex.multiEntry - a 1000 entry multiEntry array
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry.htm
new file mode 100644
index 00000000000..4f44453e0a5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex-multientry.htm
@@ -0,0 +1,53 @@
+
+
+IDBIndex.multiEntry - adding keys
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_count.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count.htm
new file mode 100644
index 00000000000..1b84ef9b79e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count.htm
@@ -0,0 +1,37 @@
+
+
+IDBIndex.count() - returns the number of records in the index
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_count2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count2.htm
new file mode 100644
index 00000000000..1494fe116fd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count2.htm
@@ -0,0 +1,37 @@
+
+
+IDBIndex.count() - returns the number of records that have keys within the range
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_count3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count3.htm
new file mode 100644
index 00000000000..7fb34347cdb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count3.htm
@@ -0,0 +1,28 @@
+
+
+IDBIndex.count() - returns the number of records that have keys with the key
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_count4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count4.htm
new file mode 100644
index 00000000000..addd99260d4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_count4.htm
@@ -0,0 +1,37 @@
+
+
+IDBIndex.count() - throw DataError when using invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get.htm
new file mode 100644
index 00000000000..835cbefd2c3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get.htm
@@ -0,0 +1,36 @@
+
+
+IDBIndex.get() - returns the record
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get2.htm
new file mode 100644
index 00000000000..52b1d371ebf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get2.htm
@@ -0,0 +1,39 @@
+
+
+IDBIndex.get() - returns the record where the index contains duplicate values
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get3.htm
new file mode 100644
index 00000000000..d0f90078905
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get3.htm
@@ -0,0 +1,27 @@
+
+
+IDBIndex.get() - attempt to retrieve a record that doesn't exist
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get4.htm
new file mode 100644
index 00000000000..bd0cc5ec85e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get4.htm
@@ -0,0 +1,39 @@
+
+
+IDBIndex.get() - returns the record with the first key in the range
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get5.htm
new file mode 100644
index 00000000000..65e2623cdd9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get5.htm
@@ -0,0 +1,26 @@
+
+
+IDBIndex.get() - throw DataError when using invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get6.htm
new file mode 100644
index 00000000000..c7f6b92febe
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get6.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.get() - throw InvalidStateError when the index is deleted
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_get7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get7.htm
new file mode 100644
index 00000000000..a49b0efc6ff
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_get7.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.get() - throw TransactionInactiveError on aborted transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey.htm
new file mode 100644
index 00000000000..536f2fd39f6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey.htm
@@ -0,0 +1,38 @@
+
+
+IDBIndex.getKey() - returns the record's primary key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey2.htm
new file mode 100644
index 00000000000..9e867324268
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey2.htm
@@ -0,0 +1,39 @@
+
+
+IDBIndex.getKey() - returns the record's primary key where the index contains duplicate values
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey3.htm
new file mode 100644
index 00000000000..238107ccc6a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey3.htm
@@ -0,0 +1,28 @@
+
+
+IDBIndex.getKey() - attempt to retrieve the primary key of a record that doesn't exist
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey4.htm
new file mode 100644
index 00000000000..2002a5fe194
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey4.htm
@@ -0,0 +1,38 @@
+
+
+IDBIndex.getKey() - returns the key of the first record within the range
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey5.htm
new file mode 100644
index 00000000000..96af868beaf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey5.htm
@@ -0,0 +1,26 @@
+
+
+IDBIndex.getKey() - throw DataError when using invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey6.htm
new file mode 100644
index 00000000000..6e9680da9ed
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey6.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.getKey() - throw InvalidStateError when the index is deleted
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey7.htm
new file mode 100644
index 00000000000..5a35ebb5c91
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_getKey7.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.getKey() - throw TransactionInactiveError on aborted transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_indexNames.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_indexNames.htm
new file mode 100644
index 00000000000..3099b45e91f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_indexNames.htm
@@ -0,0 +1,34 @@
+
+
+IDBIndex.getKey() - returns the record's primary key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor.htm
new file mode 100644
index 00000000000..0efff9325f7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.openCursor() - throw InvalidStateError when the index is deleted
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor2.htm
new file mode 100644
index 00000000000..d39254055f1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openCursor2.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.openCursor() - throw TransactionInactiveError on aborted transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor.htm
new file mode 100644
index 00000000000..e158802911e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor.htm
@@ -0,0 +1,28 @@
+
+
+IDBIndex.openKeyCursor() - throw DataError when using a invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor2.htm
new file mode 100644
index 00000000000..d8354c2fdaa
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor2.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.openKeyCursor() - throw InvalidStateError when the index is deleted
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor3.htm
new file mode 100644
index 00000000000..b4af3172417
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbindex_openKeyCursor3.htm
@@ -0,0 +1,29 @@
+
+
+IDBIndex.openKeyCursor() - throw TransactionInactiveError on aborted transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange.htm b/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange.htm
new file mode 100644
index 00000000000..dd6e5f7e50e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange.htm
@@ -0,0 +1,67 @@
+
+
+IDBKeyRange Tests
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange_incorrect.htm b/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange_incorrect.htm
new file mode 100644
index 00000000000..0449ca80732
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbkeyrange_incorrect.htm
@@ -0,0 +1,92 @@
+
+
+
+
+
+ IDBKeyRange Tests - Incorrect
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add.htm
new file mode 100644
index 00000000000..f091d1faf12
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.add() - add with an inline key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add10.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add10.htm
new file mode 100644
index 00000000000..f2bf447500d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add10.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.add() - Attempt to call 'add' without an key parameter when the object store uses out-of-line keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add11.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add11.htm
new file mode 100644
index 00000000000..99ff14c31b3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add11.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.add() - Attempt to add a record where the record's key does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add12.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add12.htm
new file mode 100644
index 00000000000..d679af08b41
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add12.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.add() - Attempt to add a record where the record's in-line key is not defined
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add13.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add13.htm
new file mode 100644
index 00000000000..943a6cf9baf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add13.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.add() - Attempt to add a record where the out of line key provided does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add14.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add14.htm
new file mode 100644
index 00000000000..5bac57cb765
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add14.htm
@@ -0,0 +1,32 @@
+
+
+IDBObjectStore.add() - Add a record where a value being indexed does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add15.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add15.htm
new file mode 100644
index 00000000000..268ed72e935
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add15.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.add() - If the transaction this IDBObjectStore belongs to has its mode set to readonly, throw ReadOnlyError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add16.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add16.htm
new file mode 100644
index 00000000000..a0ea3abbf07
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add16.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.add() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add2.htm
new file mode 100644
index 00000000000..70c05544588
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add2.htm
@@ -0,0 +1,36 @@
+
+
+IDBObjectStore.add() - add with an out-of-line key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add3.htm
new file mode 100644
index 00000000000..ac397372d48
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add3.htm
@@ -0,0 +1,39 @@
+
+
+IDBObjectStore.add() - record with same key already exists
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add4.htm
new file mode 100644
index 00000000000..c4b875cd41f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add4.htm
@@ -0,0 +1,40 @@
+
+
+IDBObjectStore.add() - add where an index has unique:true specified
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add5.htm
new file mode 100644
index 00000000000..1c1cd1fb284
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add5.htm
@@ -0,0 +1,34 @@
+
+
+IDBObjectStore.add() - object store's key path is an object attribute
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add6.htm
new file mode 100644
index 00000000000..c6f1910a3ee
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add6.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.add() - autoIncrement and inline keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add7.htm
new file mode 100644
index 00000000000..1b2a6dac3fa
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add7.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.add() - autoIncrement and out-of-line keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add8.htm
new file mode 100644
index 00000000000..b3266fdc0f6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add8.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.add() - object store has autoIncrement:true and the key path is an object attribute
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add9.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add9.htm
new file mode 100644
index 00000000000..6e027a11dc4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_add9.htm
@@ -0,0 +1,27 @@
+
+
+IDBObjectStore.add() - Attempt to add a record that does not meet the constraints of an object store's inline key requirements
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear.htm
new file mode 100644
index 00000000000..d9c3fb2a189
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear.htm
@@ -0,0 +1,41 @@
+
+
+IDBObjectStore.clear() - Verify clear removes all records
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear2.htm
new file mode 100644
index 00000000000..ac1fdff4cac
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear2.htm
@@ -0,0 +1,43 @@
+
+
+IDBObjectStore.clear() - clear removes all records from an index
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear3.htm
new file mode 100644
index 00000000000..fc0fa4d8dff
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear3.htm
@@ -0,0 +1,36 @@
+
+
+IDBObjectStore.clear() - If the transaction this IDBObjectStore belongs to has its mode set to readonly, throw ReadOnlyError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear4.htm
new file mode 100644
index 00000000000..298857a5972
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_clear4.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.clear() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count.htm
new file mode 100644
index 00000000000..a54d16e435d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.count() - returns the number of records in the object store
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count2.htm
new file mode 100644
index 00000000000..b92715a2d99
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count2.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.count() - returns the number of records that have keys within the range
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count3.htm
new file mode 100644
index 00000000000..970b87a3d84
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count3.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.count() - returns the number of records that have keys with the key
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count4.htm
new file mode 100644
index 00000000000..6d7b34f5009
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_count4.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.count() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex.htm
new file mode 100644
index 00000000000..8f0327c1a78
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex.htm
@@ -0,0 +1,30 @@
+
+
+IDBObjectStore.createIndex() - returns an IDBIndex and the properties are set correctly
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex10.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex10.htm
new file mode 100644
index 00000000000..757296253d4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex10.htm
@@ -0,0 +1,24 @@
+
+
+IDBDatabase.createIndex() - If an index with the name name already exists in this object store, the implementation must throw a DOMException of type ConstraintError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex11.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex11.htm
new file mode 100644
index 00000000000..7da1169e4c2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex11.htm
@@ -0,0 +1,23 @@
+
+
+IDBDatabase.createIndex() - If keyPath is not a valid key path, the implementation must throw a DOMException of type SyntaxError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex12.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex12.htm
new file mode 100644
index 00000000000..18296b4adbe
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex12.htm
@@ -0,0 +1,31 @@
+
+
+IDBDatabase.createIndex() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex13.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex13.htm
new file mode 100644
index 00000000000..fb70cc72b8d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex13.htm
@@ -0,0 +1,31 @@
+
+
+IDBDatabase.createIndex() - Operate out versionchange throw InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex2.htm
new file mode 100644
index 00000000000..9dc1686b186
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex2.htm
@@ -0,0 +1,41 @@
+
+
+IDBObjectStore.createIndex() - attempt to create an index that requires unique values on an object store already contains duplicates
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex3-usable-right-away.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex3-usable-right-away.htm
new file mode 100644
index 00000000000..f4b9b984f05
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex3-usable-right-away.htm
@@ -0,0 +1,38 @@
+
+
+IDBObjectStore.createIndex() - the index is usable right after being made
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex4-deleteIndex-event_order.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex4-deleteIndex-event_order.htm
new file mode 100644
index 00000000000..2dccc865e72
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex4-deleteIndex-event_order.htm
@@ -0,0 +1,66 @@
+
+
+IDBObjectStore.createIndex() - Event ordering for a later deleted index
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex5-emptykeypath.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex5-emptykeypath.htm
new file mode 100644
index 00000000000..29fadc00e3f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex5-emptykeypath.htm
@@ -0,0 +1,38 @@
+
+
+IDBObjectStore.createIndex() - empty keyPath
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex6-event_order.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex6-event_order.htm
new file mode 100644
index 00000000000..20b4890382d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex6-event_order.htm
@@ -0,0 +1,72 @@
+
+
+IDBObjectStore.createIndex() - event order when unique constraint is triggered
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex7-event_order.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex7-event_order.htm
new file mode 100644
index 00000000000..23e3dbb8752
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex7-event_order.htm
@@ -0,0 +1,77 @@
+
+
+IDBObjectStore.createIndex() - Event ordering for ConstraintError on request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex8-valid_keys.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex8-valid_keys.htm
new file mode 100644
index 00000000000..8dbe03f59ef
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex8-valid_keys.htm
@@ -0,0 +1,54 @@
+
+
+IDBObjectStore.createIndex() - index can be valid keys
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex9-emptyname.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex9-emptyname.htm
new file mode 100644
index 00000000000..3d04357c972
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_createIndex9-emptyname.htm
@@ -0,0 +1,41 @@
+
+
+IDBObjectStore.createIndex() - empty name
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete.htm
new file mode 100644
index 00000000000..33728929623
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete.htm
@@ -0,0 +1,46 @@
+
+
+IDBObjectStore.delete() - delete removes record (inline keys)
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete2.htm
new file mode 100644
index 00000000000..f7e46846025
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete2.htm
@@ -0,0 +1,27 @@
+
+
+IDBObjectStore.delete() - key doesn't match any records
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete3.htm
new file mode 100644
index 00000000000..b72b1072d78
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete3.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.delete() - object store's key path is an object attribute
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete4.htm
new file mode 100644
index 00000000000..3d36b7962ee
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete4.htm
@@ -0,0 +1,48 @@
+
+
+IDBObjectStore.delete() - delete removes record (out-of-line keys)
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete5.htm
new file mode 100644
index 00000000000..9e8ac80a123
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete5.htm
@@ -0,0 +1,32 @@
+
+IDBObjectStore.delete() - removes all of the records in the range
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete6.htm
new file mode 100644
index 00000000000..01d54dee93b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete6.htm
@@ -0,0 +1,36 @@
+
+
+IDBObjectStore.delete() - If the transaction this IDBObjectStore belongs to has its mode set to readonly, throw ReadOnlyError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete7.htm
new file mode 100644
index 00000000000..d070a6d4b16
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_delete7.htm
@@ -0,0 +1,33 @@
+
+
+IDBObjectStore.delete() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleteIndex.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleteIndex.htm
new file mode 100644
index 00000000000..1e0fb2976c8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleteIndex.htm
@@ -0,0 +1,43 @@
+
+
+IDBObjectStore.deleteIndex() - removes the index
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleted.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleted.htm
new file mode 100644
index 00000000000..1d9421ce03a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_deleted.htm
@@ -0,0 +1,49 @@
+
+
+Attempting to use deleted IDBObjectStore
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get.htm
new file mode 100644
index 00000000000..99aff78d564
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.get() - key is a number
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get2.htm
new file mode 100644
index 00000000000..dfbfea17c22
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get2.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.get() - key is a string
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get3.htm
new file mode 100644
index 00000000000..b093e535796
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get3.htm
@@ -0,0 +1,34 @@
+
+
+IDBObjectStore.get() - key is a Date
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get4.htm
new file mode 100644
index 00000000000..7853697a19f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get4.htm
@@ -0,0 +1,27 @@
+
+
+IDBObjectStore.get() - attempt to retrieve a record that doesn't exist
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get5.htm
new file mode 100644
index 00000000000..59b0ede641f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get5.htm
@@ -0,0 +1,31 @@
+
+IDBObjectStore.get() - returns the record with the first key in the range
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get6.htm
new file mode 100644
index 00000000000..33381a684b6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get6.htm
@@ -0,0 +1,30 @@
+
+
+IDBObjectStore.get() - throw TransactionInactiveError on aborted transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get7.htm
new file mode 100644
index 00000000000..570441b6634
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_get7.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.get() - throw DataError when using invalid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_index.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_index.htm
new file mode 100644
index 00000000000..5da58ecc311
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_index.htm
@@ -0,0 +1,34 @@
+
+
+IDBObjectStore.index() - returns an index
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor.htm
new file mode 100644
index 00000000000..914aa57211f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor.htm
@@ -0,0 +1,39 @@
+
+IDBObjectStore.openCursor() - iterate through 100 objects
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor_invalid.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor_invalid.htm
new file mode 100644
index 00000000000..698e7998b23
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_openCursor_invalid.htm
@@ -0,0 +1,50 @@
+
+IDBObjectStore.openCursor() - invalid
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put.htm
new file mode 100644
index 00000000000..6a0fed4b7fe
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put.htm
@@ -0,0 +1,35 @@
+
+
+IDBObjectStore.put() - put with an inline key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put10.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put10.htm
new file mode 100644
index 00000000000..d0de11c3e30
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put10.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.put() - Attempt to call 'put' without an key parameter when the object store uses out-of-line keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put11.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put11.htm
new file mode 100644
index 00000000000..9a13757ef20
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put11.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.put() - Attempt to put a record where the record's key does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put12.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put12.htm
new file mode 100644
index 00000000000..24970dff080
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put12.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.put() - Attempt to put a record where the record's in-line key is not defined
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put13.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put13.htm
new file mode 100644
index 00000000000..870c8e4a718
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put13.htm
@@ -0,0 +1,29 @@
+
+
+IDBObjectStore.put() - Attempt to put a record where the out of line key provided does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put14.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put14.htm
new file mode 100644
index 00000000000..c6896964592
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put14.htm
@@ -0,0 +1,32 @@
+
+
+IDBObjectStore.put() - Put a record where a value being indexed does not meet the constraints of a valid key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put15.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put15.htm
new file mode 100644
index 00000000000..cf2c35435cf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put15.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.put() - If the transaction this IDBObjectStore belongs to has its mode set to readonly, throw ReadOnlyError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put16.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put16.htm
new file mode 100644
index 00000000000..09d9e2acde2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put16.htm
@@ -0,0 +1,31 @@
+
+
+IDBObjectStore.put() - If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put2.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put2.htm
new file mode 100644
index 00000000000..3b9fc30a811
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put2.htm
@@ -0,0 +1,36 @@
+
+
+IDBObjectStore.put() - put with an out-of-line key
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put3.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put3.htm
new file mode 100644
index 00000000000..79097a283e5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put3.htm
@@ -0,0 +1,48 @@
+
+
+IDBObjectStore.put() - record with same key already exists
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put4.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put4.htm
new file mode 100644
index 00000000000..c1335b27d00
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put4.htm
@@ -0,0 +1,40 @@
+
+
+IDBObjectStore.put() - put where an index has unique:true specified
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put5.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put5.htm
new file mode 100644
index 00000000000..a4d9abefff6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put5.htm
@@ -0,0 +1,34 @@
+
+
+IDBObjectStore.put() - object store's key path is an object attribute
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put6.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put6.htm
new file mode 100644
index 00000000000..bcf7e7d1934
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put6.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.put() - autoIncrement and inline keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put7.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put7.htm
new file mode 100644
index 00000000000..6765b0a84ae
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put7.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.put() - autoIncrement and out-of-line keys
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put8.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put8.htm
new file mode 100644
index 00000000000..3bf284eacab
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put8.htm
@@ -0,0 +1,47 @@
+
+
+IDBObjectStore.put() - object store has autoIncrement:true and the key path is an object attribute
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put9.htm b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put9.htm
new file mode 100644
index 00000000000..6e50a0b296d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbobjectstore_put9.htm
@@ -0,0 +1,27 @@
+
+
+IDBObjectStore.put() - Attempt to put a record that does not meet the constraints of an object store's inline key requirements
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbtransaction-oncomplete.htm b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction-oncomplete.htm
new file mode 100644
index 00000000000..7c295c7c150
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction-oncomplete.htm
@@ -0,0 +1,53 @@
+
+IDBTransaction - complete event
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbtransaction.htm b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction.htm
new file mode 100644
index 00000000000..8a3484511e5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction.htm
@@ -0,0 +1,46 @@
+
+IDBTransaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbtransaction_abort.htm b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction_abort.htm
new file mode 100644
index 00000000000..c93a2da290f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbtransaction_abort.htm
@@ -0,0 +1,42 @@
+
+
+IDBTransaction - abort
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbversionchangeevent.htm b/tests/wpt/web-platform-tests/IndexedDB/idbversionchangeevent.htm
new file mode 100644
index 00000000000..5e688353364
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbversionchangeevent.htm
@@ -0,0 +1,66 @@
+
+IDBVersionChangeEvent fired in upgradeneeded, versionchange and deleteDatabase
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/idbworker.js b/tests/wpt/web-platform-tests/IndexedDB/idbworker.js
new file mode 100644
index 00000000000..359f6fb6911
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/idbworker.js
@@ -0,0 +1,34 @@
+var db
+
+self.addEventListener('message', MessageHandler, false)
+
+function MessageHandler(e)
+{
+ var open_rq, idb = self.indexedDB || self.msIndexedDB || self.webkitIndexedDB || self.mozIndexedDB
+
+ if (!idb)
+ {
+ self.postMessage(false)
+ return
+ }
+ else
+ self.postMessage(true)
+
+ open_rq = idb.open("webworker101", 1)
+
+ open_rq.onupgradeneeded = function(e) {
+ db = e.target.result
+ db.createObjectStore("store")
+ .add("test", 1)
+ }
+ open_rq.onsuccess = function(e) {
+ db = e.target.result
+ db.onerror = function() { self.postMessage("db.error") }
+ db.transaction("store").objectStore("store").get(1).onsuccess = function(e) {
+ self.postMessage(e.target.result)
+ db.close()
+ }
+ }
+ open_rq.onerror = function() { self.postMessage("open.error") }
+ open_rq.onblocked = function() { self.postMessage("open.blocked") }
+}
diff --git a/tests/wpt/web-platform-tests/IndexedDB/index_sort_order.htm b/tests/wpt/web-platform-tests/IndexedDB/index_sort_order.htm
new file mode 100644
index 00000000000..6249c420489
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/index_sort_order.htm
@@ -0,0 +1,51 @@
+
+
+Verify key sort order in an index is 'number < Date < DOMString'
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/interfaces.htm b/tests/wpt/web-platform-tests/IndexedDB/interfaces.htm
new file mode 100644
index 00000000000..644f4d178f4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/interfaces.htm
@@ -0,0 +1,64 @@
+
+
+
+
+
+Test IndexedDB's interfaces
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/interfaces.html b/tests/wpt/web-platform-tests/IndexedDB/interfaces.html
new file mode 100644
index 00000000000..cc4e7f20392
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/interfaces.html
@@ -0,0 +1,50 @@
+
+
+IndexedDB IDL tests
+
+
+
+
+
+IndexedDB IDL tests
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/interfaces.idl b/tests/wpt/web-platform-tests/IndexedDB/interfaces.idl
new file mode 100644
index 00000000000..055e62f46b3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/interfaces.idl
@@ -0,0 +1,145 @@
+enum IDBTransactionMode {
+ "readonly",
+ "readwrite",
+ "versionchange"
+};
+
+enum IDBRequestReadyState {
+ "pending",
+ "done"
+};
+
+interface IDBKeyRange {
+ readonly attribute any lower;
+ readonly attribute any upper;
+ readonly attribute boolean lowerOpen;
+ readonly attribute boolean upperOpen;
+ static IDBKeyRange only (any value);
+ static IDBKeyRange lowerBound (any lower, optional boolean open = false);
+ static IDBKeyRange upperBound (any upper, optional boolean open = false);
+ static IDBKeyRange bound (any lower, any upper, optional boolean lowerOpen = false, optional boolean upperOpen = false);
+};
+
+enum IDBCursorDirection {
+ "next",
+ "nextunique",
+ "prev",
+ "prevunique"
+};
+
+dictionary IDBObjectStoreParameters {
+ (DOMString or sequence)? keyPath = null;
+ boolean autoIncrement = false;
+};
+
+dictionary IDBIndexParameters {
+ boolean unique = false;
+ boolean multiEntry = false;
+};
+
+dictionary IDBVersionChangeEventInit : EventInit {
+ unsigned long long oldVersion = 0;
+ unsigned long long? newVersion = null;
+};
+
+interface IDBRequest : EventTarget {
+ readonly attribute any result;
+ readonly attribute DOMError error;
+ readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
+ readonly attribute IDBTransaction transaction;
+ readonly attribute IDBRequestReadyState readyState;
+ attribute EventHandler onsuccess;
+ attribute EventHandler onerror;
+};
+
+interface IDBOpenDBRequest : IDBRequest {
+ attribute EventHandler onblocked;
+ attribute EventHandler onupgradeneeded;
+};
+
+[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
+interface IDBVersionChangeEvent : Event {
+ readonly attribute unsigned long long oldVersion;
+ readonly attribute unsigned long long? newVersion;
+};
+
+[NoInterfaceObject]
+interface IDBEnvironment {
+ readonly attribute IDBFactory indexedDB;
+};
+
+interface IDBFactory {
+ IDBOpenDBRequest open (DOMString name, [EnforceRange] optional unsigned long long version);
+ IDBOpenDBRequest deleteDatabase (DOMString name);
+ short cmp (any first, any second);
+};
+
+interface IDBDatabase : EventTarget {
+ readonly attribute DOMString name;
+ readonly attribute unsigned long long version;
+ readonly attribute DOMStringList objectStoreNames;
+ IDBObjectStore createObjectStore (DOMString name, optional IDBObjectStoreParameters optionalParameters);
+ void deleteObjectStore (DOMString name);
+ IDBTransaction transaction ((DOMString or sequence) storeNames, optional IDBTransactionMode mode = "readonly");
+ void close ();
+ attribute EventHandler onabort;
+ attribute EventHandler onerror;
+ attribute EventHandler onversionchange;
+};
+
+interface IDBObjectStore {
+ readonly attribute DOMString name;
+ readonly attribute any keyPath;
+ readonly attribute DOMStringList indexNames;
+ readonly attribute IDBTransaction transaction;
+ readonly attribute boolean autoIncrement;
+ IDBRequest put (any value, optional any key);
+ IDBRequest add (any value, optional any key);
+ IDBRequest delete (any key);
+ IDBRequest get (any key);
+ IDBRequest clear ();
+ IDBRequest openCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBIndex createIndex (DOMString name, (DOMString or sequence) keyPath, optional IDBIndexParameters optionalParameters);
+ IDBIndex index (DOMString name);
+ void deleteIndex (DOMString indexName);
+ IDBRequest count (optional any key);
+};
+
+interface IDBIndex {
+ readonly attribute DOMString name;
+ readonly attribute IDBObjectStore objectStore;
+ readonly attribute any keyPath;
+ readonly attribute boolean multiEntry;
+ readonly attribute boolean unique;
+ IDBRequest openCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest get (any key);
+ IDBRequest getKey (any key);
+ IDBRequest count (optional any key);
+};
+
+interface IDBCursor {
+ readonly attribute (IDBObjectStore or IDBIndex) source;
+ readonly attribute IDBCursorDirection direction;
+ readonly attribute any key;
+ readonly attribute any primaryKey;
+ IDBRequest update (any value);
+ void advance ([EnforceRange] unsigned long count);
+ void continue (optional any key);
+ IDBRequest delete ();
+};
+
+interface IDBCursorWithValue : IDBCursor {
+ readonly attribute any value;
+};
+
+interface IDBTransaction : EventTarget {
+ readonly attribute IDBTransactionMode mode;
+ readonly attribute IDBDatabase db;
+ readonly attribute DOMError error;
+ IDBObjectStore objectStore (DOMString name);
+ void abort ();
+ attribute EventHandler onabort;
+ attribute EventHandler oncomplete;
+ attribute EventHandler onerror;
+};
diff --git a/tests/wpt/web-platform-tests/IndexedDB/interfaces.worker.js b/tests/wpt/web-platform-tests/IndexedDB/interfaces.worker.js
new file mode 100644
index 00000000000..5da0590bb29
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/interfaces.worker.js
@@ -0,0 +1,39 @@
+"use strict";
+
+importScripts("/resources/testharness.js");
+importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
+
+var request = new XMLHttpRequest();
+request.open("GET", "interfaces.idl");
+request.send();
+request.onload = function() {
+ var idlArray = new IdlArray();
+ var idls = request.responseText;
+
+ idlArray.add_untested_idls("interface WorkerGlobalScope {};");
+ idlArray.add_untested_idls("interface WorkerUtils {};");
+ idlArray.add_untested_idls("WorkerGlobalScope implements WorkerUtils;");
+ idlArray.add_untested_idls("interface Event { };");
+ idlArray.add_untested_idls("interface EventTarget { };");
+
+ // From Indexed DB:
+ idlArray.add_idls("WorkerUtils implements IDBEnvironment;");
+ idlArray.add_idls(idls);
+
+ idlArray.add_objects({
+ IDBCursor: [],
+ IDBCursorWithValue: [],
+ IDBDatabase: [],
+ IDBEnvironment: [],
+ IDBFactory: ["self.indexedDB"],
+ IDBIndex: [],
+ IDBKeyRange: ["IDBKeyRange.only(0)"],
+ IDBObjectStore: [],
+ IDBOpenDBRequest: [],
+ IDBRequest: [],
+ IDBTransaction: [],
+ IDBVersionChangeEvent: ["new IDBVersionChangeEvent('foo')"],
+ });
+ idlArray.test();
+ done();
+};
diff --git a/tests/wpt/web-platform-tests/IndexedDB/key_invalid.htm b/tests/wpt/web-platform-tests/IndexedDB/key_invalid.htm
new file mode 100644
index 00000000000..30759d5ef3e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/key_invalid.htm
@@ -0,0 +1,129 @@
+
+
+
+Invalid key
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/key_valid.html b/tests/wpt/web-platform-tests/IndexedDB/key_valid.html
new file mode 100644
index 00000000000..e695d14c4cd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/key_valid.html
@@ -0,0 +1,73 @@
+
+
+
+Valid key
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keygenerator-constrainterror.htm b/tests/wpt/web-platform-tests/IndexedDB/keygenerator-constrainterror.htm
new file mode 100644
index 00000000000..794b271ba39
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keygenerator-constrainterror.htm
@@ -0,0 +1,76 @@
+
+
+Keygenerator ConstraintError when using same id as already generated
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keygenerator-overflow.htm b/tests/wpt/web-platform-tests/IndexedDB/keygenerator-overflow.htm
new file mode 100644
index 00000000000..797a184be63
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keygenerator-overflow.htm
@@ -0,0 +1,70 @@
+
+
+Keygenerator overflow
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keygenerator.htm b/tests/wpt/web-platform-tests/IndexedDB/keygenerator.htm
new file mode 100644
index 00000000000..8430364fc9d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keygenerator.htm
@@ -0,0 +1,67 @@
+
+
+Keygenerator
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keyorder.htm b/tests/wpt/web-platform-tests/IndexedDB/keyorder.htm
new file mode 100644
index 00000000000..f65a4de4f0d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keyorder.htm
@@ -0,0 +1,180 @@
+
+
+
+Key sort order
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keypath.htm b/tests/wpt/web-platform-tests/IndexedDB/keypath.htm
new file mode 100644
index 00000000000..539af8e500b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keypath.htm
@@ -0,0 +1,148 @@
+
+
+
+Keypath
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keypath_invalid.htm b/tests/wpt/web-platform-tests/IndexedDB/keypath_invalid.htm
new file mode 100644
index 00000000000..9c5bd6c2f6c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keypath_invalid.htm
@@ -0,0 +1,65 @@
+
+
+
+Invalid keypath
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/keypath_maxsize.htm b/tests/wpt/web-platform-tests/IndexedDB/keypath_maxsize.htm
new file mode 100644
index 00000000000..5e0415dbc1d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/keypath_maxsize.htm
@@ -0,0 +1,66 @@
+
+
+Keypath
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/list_ordering.htm b/tests/wpt/web-platform-tests/IndexedDB/list_ordering.htm
new file mode 100644
index 00000000000..8349dbae79f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/list_ordering.htm
@@ -0,0 +1,61 @@
+
+
+
objectStoreNames and indexNames order
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/objectstore_keyorder.htm b/tests/wpt/web-platform-tests/IndexedDB/objectstore_keyorder.htm
new file mode 100644
index 00000000000..69c281fd02a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/objectstore_keyorder.htm
@@ -0,0 +1,49 @@
+
+
+
Verify key sort order in an object store is 'number < Date < DOMString'
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/request_bubble-and-capture.htm b/tests/wpt/web-platform-tests/IndexedDB/request_bubble-and-capture.htm
new file mode 100644
index 00000000000..930e20ee0db
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/request_bubble-and-capture.htm
@@ -0,0 +1,69 @@
+
+
+
Bubbling and capturing of request events
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/string-list-ordering.htm b/tests/wpt/web-platform-tests/IndexedDB/string-list-ordering.htm
new file mode 100644
index 00000000000..cc905e56ecf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/string-list-ordering.htm
@@ -0,0 +1,85 @@
+
+
+
+
+
+
Test string list ordering in IndexedDB
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/support.js b/tests/wpt/web-platform-tests/IndexedDB/support.js
new file mode 100644
index 00000000000..858fe5d7701
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/support.js
@@ -0,0 +1,122 @@
+var databaseName = "database";
+var databaseVersion = 1;
+
+if (!window.indexedDB)
+{
+ if (window.msIndexedDB)
+ {
+ window.indexedDB = window.msIndexedDB;
+ }
+ else if (window.mozIndexedDB)
+ {
+ window.indexedDB = window.mozIndexedDB;
+ }
+ else if (window.webkitIndexedDB)
+ {
+ window.indexedDB = webkitIndexedDB;
+ IDBCursor = webkitIDBCursor;
+ IDBDatabaseException = webkitIDBDatabaseException;
+ IDBIndex = webkitIDBIndex;
+ IDBObjectStore = webkitIDBObjectStore;
+ IDBRequest = webkitIDBRequest;
+ IDBKeyRange = webkitIDBKeyRange;
+ IDBTransaction = webkitIDBTransaction;
+ }
+}
+
+/* Delete created databases
+ *
+ * Go through each finished test, see if it has an associated database. Close
+ * that and delete the database. */
+add_completion_callback(function(tests)
+{
+ for (var i in tests)
+ {
+ if(tests[i].db)
+ {
+ tests[i].db.close();
+ window.indexedDB.deleteDatabase(tests[i].db.name);
+ }
+ }
+});
+
+function fail(test, desc) {
+ return test.step_func(function(e) {
+ if (e && e.message && e.target.error)
+ assert_unreached(desc + " (" + e.target.error.name + ": " + e.message + ")");
+ else if (e && e.message)
+ assert_unreached(desc + " (" + e.message + ")");
+ else if (e && e.target.readyState === 'done' && e.target.error)
+ assert_unreached(desc + " (" + e.target.error.name + ")");
+ else
+ assert_unreached(desc);
+ });
+}
+
+function createdb(test, dbname, version)
+{
+ var rq_open = createdb_for_multiple_tests(dbname, version);
+ return rq_open.setTest(test);
+}
+
+function createdb_for_multiple_tests(dbname, version) {
+ var rq_open,
+ fake_open = {},
+ test = null,
+ dbname = (dbname ? dbname : "testdb-" + new Date().getTime() + Math.random() );
+
+ if (version)
+ rq_open = window.indexedDB.open(dbname, version);
+ else
+ rq_open = window.indexedDB.open(dbname);
+
+ function auto_fail(evt, current_test) {
+ /* Fail handlers, if we haven't set on/whatever/, don't
+ * expect to get event whatever. */
+ rq_open.manually_handled = {}
+
+ rq_open.addEventListener(evt, function(e) {
+ if (current_test !== test) {
+ return;
+ }
+
+ test.step(function() {
+ if (!rq_open.manually_handled[evt]) {
+ assert_unreached("unexpected open." + evt + " event");
+ }
+
+ if (e.target.result + "" == "[object IDBDatabase]" && !this.db) {
+ this.db = e.target.result;
+
+ this.db.onerror = fail(test, "unexpected db.error");
+ this.db.onabort = fail(test, "unexpected db.abort");
+ this.db.onversionchange = fail(test, "unexpected db.versionchange");
+ }
+ })
+ })
+ rq_open.__defineSetter__("on" + evt, function(h) {
+ rq_open.manually_handled[evt] = true;
+ if (!h)
+ rq_open.addEventListener(evt, function() {});
+ else
+ rq_open.addEventListener(evt, test.step_func(h));
+ })
+ }
+
+ // add a .setTest method to the DB object
+ Object.defineProperty(rq_open, 'setTest', {
+ enumerable: false,
+ value: function(t) {
+ test = t;
+
+ auto_fail("upgradeneeded", test);
+ auto_fail("success", test);
+ auto_fail("blocked", test);
+ auto_fail("error", test);
+
+ return this;
+ }
+ });
+
+ return rq_open;
+}
diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-create_in_versionchange.htm b/tests/wpt/web-platform-tests/IndexedDB/transaction-create_in_versionchange.htm
new file mode 100644
index 00000000000..be2cd224500
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-create_in_versionchange.htm
@@ -0,0 +1,82 @@
+
+
+
Attempt to create new transactions inside a versionchange transaction
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime-blocked.htm b/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime-blocked.htm
new file mode 100644
index 00000000000..3288506c505
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime-blocked.htm
@@ -0,0 +1,108 @@
+
+
Blocked event
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime.htm b/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime.htm
new file mode 100644
index 00000000000..2412424fd4e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-lifetime.htm
@@ -0,0 +1,101 @@
+
+
Test events opening a second database when one connection is open already
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-requestqueue.htm b/tests/wpt/web-platform-tests/IndexedDB/transaction-requestqueue.htm
new file mode 100644
index 00000000000..b34c37e98c2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-requestqueue.htm
@@ -0,0 +1,91 @@
+
+
+
Transactions have a request queue
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction_bubble-and-capture.htm b/tests/wpt/web-platform-tests/IndexedDB/transaction_bubble-and-capture.htm
new file mode 100644
index 00000000000..9da61f4fcde
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/transaction_bubble-and-capture.htm
@@ -0,0 +1,75 @@
+
+
+
Capture and bubble
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/value.htm b/tests/wpt/web-platform-tests/IndexedDB/value.htm
new file mode 100644
index 00000000000..36e83395248
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/value.htm
@@ -0,0 +1,40 @@
+
+
+
Values
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/value_recursive.htm b/tests/wpt/web-platform-tests/IndexedDB/value_recursive.htm
new file mode 100644
index 00000000000..f49a1ccbc59
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/value_recursive.htm
@@ -0,0 +1,66 @@
+
+
+
Recursive value
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/IndexedDB/writer-starvation.htm b/tests/wpt/web-platform-tests/IndexedDB/writer-starvation.htm
new file mode 100644
index 00000000000..ae6c90150e2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/IndexedDB/writer-starvation.htm
@@ -0,0 +1,105 @@
+
+
+
Writer starvation
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/LICENSE b/tests/wpt/web-platform-tests/LICENSE
new file mode 100644
index 00000000000..28fcc080cb4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/LICENSE
@@ -0,0 +1,29 @@
+W3C 3-clause BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of works must retain the original copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the original copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of the W3C nor the names of its contributors may be
+ used to endorse or promote products derived from this work without
+ specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/wpt/web-platform-tests/README.md b/tests/wpt/web-platform-tests/README.md
new file mode 100644
index 00000000000..0c1c7165ca5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/README.md
@@ -0,0 +1,218 @@
+The Web Platform Tests Project [](http://irc.w3.org/?channels=testing)
+==============================
+
+These are test suites for 60+ Web-platform specifications, along
+with test-infrastructure code for running the tests.
+
+Running the Tests
+=================
+
+The tests are designed to be run from your local computer. The test
+environment requires Python 2.7+ (but not Python 3.x). You will also
+need a copy of OpenSSL. For users on Windows this is available from
+[the openssl website](https://www.openssl.org/related/binaries.html).
+
+To get the tests running, you need to set up the test domains in your
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system). The
+following entries are required:
+
+```
+127.0.0.1 web-platform.test
+127.0.0.1 www.web-platform.test
+127.0.0.1 www1.web-platform.test
+127.0.0.1 www2.web-platform.test
+127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
+127.0.0.1 xn--lve-6lad.web-platform.test
+```
+
+Because web-platform-tests uses git submodules, you must ensure that
+these are up to date. In the root of your checkout, run:
+
+```
+git submodule update --init --recursive
+```
+
+The test environment can then be started using
+
+```
+./serve
+```
+
+This will start HTTP servers on two ports and a websockets server on
+one port. By default one web server starts on port 8000 and the other
+ports are randomly-chosen free ports. Tests must be loaded from the
+*first* HTTP server in the output. To change the ports, edit the
+`config.json` file, for example, replacing the part that reads:
+
+```
+"http": [8000, "auto"]
+```
+
+to some port of your choice e.g.
+
+```
+"http":[1234, "auto"]
+```
+
+If you installed OpenSSL in such a way that running `openssl` at a
+command line doesn't work, you also need to adjust the path to the
+OpenSSL binary. This can be done by adding a section to `config.json`
+like:
+
+```
+"ssl": {"openssl": {"binary": "/path/to/openssl"}}
+```
+
+Test Runner
+===========
+
+There is a test runner that is designed to provide a
+convenient way to run the web-platform tests in-browser. It will run
+testharness.js tests automatically but requires manual work for
+reftests and manual tests.
+
+The runner can be found at `/tools/runner/index.html` on the local
+server i.e.
+
+```
+http://web-platform.test:8000/tools/runner/index.html
+```
+
+in the default configuration. The first time you use this it has to
+generate a manifest of all tests. This may take some time, so please
+be patient.
+
+Publication
+===========
+
+The master branch is automatically synced to http://w3c-test.org/.
+
+Pull requests that have been checked are automatically mirrored to
+http://w3c-test.org/submissions/.
+
+Finding Things
+==============
+
+Each top-level directory represents a W3C specification: the name
+matches the shortname used after the canonical address of the said
+specification under http://www.w3.org/TR/ .
+
+For some of the specifications, the tree under the top-level directory
+represents the sections of the respective documents, using the section
+IDs for directory names, with a maximum of three levels deep.
+
+So if you're looking for tests in HTML for "The History interface",
+they will be under `html/browsers/history/the-history-interface/`.
+
+Various resources that tests depend on are in `common`, `images`, and
+`fonts`.
+
+
+If you're looking at a section of the specification and can't figure
+out where the directory is for it in the tree, just run:
+
+```
+node tools/scripts/id2path.js your-id
+```
+
+Branches
+========
+
+In the vast majority of cases the **only** upstream branch that you
+should need to care about is `master`. If you see other branches in
+the repository, you can generally safely ignore them.
+
+Contributing
+============
+
+Save the Web, Write Some Tests!
+
+Absolutely everyone is welcome (and even encouraged) to contribute to
+test development, so long as you fulfill the contribution requirements
+detailed in the [Contributing Guidelines][contributing]. No test is
+too small or too simple, especially if it corresponds to something for
+which you've noted an interoperability bug in a browser.
+
+The way to contribute is just as usual:
+
+* Fork this repository (and make sure you're still relatively in sync
+ with it if you forked a while ago).
+* Create a branch for your changes:
+ `git checkout -b your-name/topic`.
+* Make your changes.
+* Run the lint script described below.
+* Commit locally and push that to your repo.
+* Send in a pull request based on the above.
+
+A lint is available to test for common mistakes in testcases. It can
+be run with:
+
+```
+./lint
+```
+
+in the root of the checkout. It is also run for every submitted pull
+request, and branches with lint errors will not get merged. In the
+unusual case that the lint is reporting an error for something that is
+essential to your test, there is a whitelist at
+`tools/lint/lint.whitelist` that may be updated.
+
+Adding command-line scripts ("tools" subdirs)
+---------------------------------------------
+
+Sometimes you may want to add a script to the repository that's meant
+to be used from the command line, not from a browser (e.g., a script
+for generating test files). If you want to ensure (e.g., for security
+reasons) that such scripts won't be handled by the HTTP server, but
+will instead only be usable from the command line, then place them in
+either:
+
+* the `tools` subdir at the root of the repository, or
+
+* the `tools` subdir at the root of any top-level directory in the
+ repository which contains the tests the script is meant to be used
+ with
+
+Any files in those `tools` directories won't be handled by the HTTP
+server; instead the server will return a 404 if a user navigates to
+the URL for a file within them.
+
+If you want to add a script for use with a particular set of tests but
+there isn't yet any `tools` subdir at the root of a top-level
+directory in the repository containing those tests, you can create a
+`tools` subdir at the root of that top-level directory and place your
+scripts there.
+
+For example, if you wanted to add a script for use with tests in the
+`notifications` directory, create the `notifications/tools` subdir and
+put your script there.
+
+Test Review
+===========
+
+We can sometimes take a little while to go through pull requests
+because we have to go through all the tests and ensure that they match
+the specification correctly. But we look at all of them, and take
+everything that we can.
+
+Getting Involved
+================
+
+If you wish to contribute actively, you're very welcome to join the
+public-test-infra@w3.org mailing list (low traffic) by
+[signing up to our mailing list](mailto:public-test-infra-request@w3.org?subject=subscribe).
+The mailing list is [archived][mailarchive].
+
+Join us on irc #testing ([irc.w3.org][ircw3org], port 6665). The channel
+is [archived][ircarchive].
+
+[contributing]: https://github.com/w3c/web-platform-tests/blob/master/CONTRIBUTING.md
+[ircw3org]: https://www.w3.org/wiki/IRC
+[ircarchive]: http://krijnhoetmer.nl/irc-logs/testing/
+[mailarchive]: http://lists.w3.org/Archives/Public/public-test-infra/
+
+Documentation
+=============
+
+* [How to write and review tests](http://testthewebforward.org/docs/)
+* [Documentation for the wptserve server](http://wptserve.readthedocs.org/en/latest/)
diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/README.md b/tests/wpt/web-platform-tests/WebCryptoAPI/README.md
new file mode 100644
index 00000000000..5546cf2b6f2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebCryptoAPI/README.md
@@ -0,0 +1 @@
+Directory for Crypto API tests
diff --git a/tests/wpt/web-platform-tests/WebCryptoAPI/test_getRandomValues.html b/tests/wpt/web-platform-tests/WebCryptoAPI/test_getRandomValues.html
new file mode 100644
index 00000000000..62b00e9f12c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebCryptoAPI/test_getRandomValues.html
@@ -0,0 +1,47 @@
+
+
+
WebCryptoAPI: getRandomValues()
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constants.html b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constants.html
new file mode 100644
index 00000000000..450b4b334e6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constants.html
@@ -0,0 +1,59 @@
+
+
+
DOMException constants
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constructor.html b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constructor.html
new file mode 100644
index 00000000000..9dc6d9918a3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/DOMException-constructor.html
@@ -0,0 +1,73 @@
+
+
+
DOMException constructor
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.html b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.html
new file mode 100644
index 00000000000..ddb40f4ddea
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.html
@@ -0,0 +1,11 @@
+
+
+
DOMException constructor and prototype object
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.js b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.js
new file mode 100644
index 00000000000..e539d85dbbb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.js
@@ -0,0 +1,111 @@
+function run_test() {
+ test(function() {
+ // "There MUST exist a property on the ECMAScript global object whose
+ // name is “DOMException†and value is an object called the
+ // DOMException constructor object, which provides access to legacy
+ // DOMException code constants. The property has the attributes
+ // { [[Writable]]: true, [[Enumerable]]: false,
+ // [[Configurable]]: true }."
+ assert_own_property(self, "DOMException",
+ "self does not have own property \"DOMException\"");
+ var desc = Object.getOwnPropertyDescriptor(self, "DOMException");
+ assert_false("get" in desc, "self's property \"DOMException\" has getter");
+ assert_false("set" in desc, "self's property \"DOMException\" has setter");
+ assert_true(desc.writable, "self's property \"DOMException\" is not writable");
+ assert_false(desc.enumerable, "self's property \"DOMException\" is enumerable");
+ assert_true(desc.configurable, "self's property \"DOMException\" is not configurable");
+
+ // "The DOMException constructor object MUST be a function object but
+ // with a [[Prototype]] value of %Error% ([ECMA-262], section 6.1.7.4)."
+ assert_equals(Object.getPrototypeOf(self.DOMException), Error,
+ "prototype of self's property \"DOMException\" is not Error");
+
+ // "Its [[Get]] internal property is set as described in ECMA-262
+ // section 9.1.8."
+ // Not much to test for this.
+ // "Its [[Construct]] internal property is set as described in ECMA-262
+ // section 19.2.2.3."
+ // "Its @@hasInstance property is set as described in ECMA-262 section
+ // 19.2.3.8, unless otherwise specified."
+
+ // String() returns something implementation-dependent, because it
+ // calls Function#toString.
+ assert_class_string(self.DOMException, "Function",
+ "class string of DOMException");
+
+ // "For every legacy code listed in the error names table, there MUST
+ // be a property on the DOMException constructor object whose name and
+ // value are as indicated in the table. The property has attributes
+ // { [[Writable]]: false, [[Enumerable]]: true,
+ // [[Configurable]]: false }."
+ // See DOMException-constants.html.
+ }, "existence and properties of DOMException");
+
+ test(function() {
+ assert_own_property(self, "DOMException",
+ "self does not have own property \"DOMException\"");
+
+ // "The DOMException constructor object MUST also have a property named
+ // “prototype†with attributes { [[Writable]]: false,
+ // [[Enumerable]]: false, [[Configurable]]: false } whose value is an
+ // object called the DOMException prototype object. This object also
+ // provides access to the legacy code values."
+ assert_own_property(self.DOMException, "prototype",
+ 'exception "DOMException" does not have own property "prototype"');
+ var desc = Object.getOwnPropertyDescriptor(self.DOMException, "prototype");
+ assert_false("get" in desc, "DOMException.prototype has getter");
+ assert_false("set" in desc, "DOMException.prototype has setter");
+ assert_false(desc.writable, "DOMException.prototype is writable");
+ assert_false(desc.enumerable, "DOMException.prototype is enumerable");
+ assert_false(desc.configurable, "DOMException.prototype is configurable");
+
+ // "The DOMException prototype object MUST have an internal
+ // [[Prototype]] property whose value is %ErrorPrototype% ([ECMA-262],
+ // section 6.1.7.4)."
+ assert_own_property(self, "Error",
+ 'should inherit from Error, but self has no such property');
+ assert_own_property(self.Error, "prototype",
+ 'should inherit from Error, but that object has no "prototype" property');
+ assert_equals(Object.getPrototypeOf(self.DOMException.prototype),
+ self.Error.prototype,
+ 'prototype of DOMException.prototype is not Error.prototype');
+
+ // "The class string of the DOMException prototype object is
+ // “DOMExceptionPrototypeâ€."
+ assert_class_string(self.DOMException.prototype, "DOMExceptionPrototype",
+ "class string of DOMException.prototype");
+ }, "existence and properties of DOMException.prototype");
+
+ test(function() {
+ assert_false(self.DOMException.prototype.hasOwnProperty("name"),
+ "DOMException.prototype should not have an own \"name\" " +
+ "property.");
+ assert_false(self.DOMException.prototype.hasOwnProperty("code"),
+ "DOMException.prototype should not have an own \"name\" " +
+ "property.");
+ }, "existence of name and code properties on DOMException.prototype");
+
+ test(function() {
+ assert_own_property(self, "DOMException",
+ "self does not have own property \"DOMException\"");
+ assert_own_property(self.DOMException, "prototype",
+ 'interface "DOMException" does not have own property "prototype"');
+
+ // "There MUST be a property named “constructor†on the DOMException
+ // prototype object with attributes { [[Writable]]: true,
+ // [[Enumerable]]: false, [[Configurable]]: true } and whose value is
+ // the DOMException constructor object."
+ assert_own_property(self.DOMException.prototype, "constructor",
+ "DOMException" + '.prototype does not have own property "constructor"');
+ var desc = Object.getOwnPropertyDescriptor(self.DOMException.prototype, "constructor");
+ assert_false("get" in desc, "DOMException.prototype.constructor has getter");
+ assert_false("set" in desc, "DOMException.prototype.constructor has setter");
+ assert_true(desc.writable, "DOMException.prototype.constructor is not writable");
+ assert_false(desc.enumerable, "DOMException.prototype.constructor is enumerable");
+ assert_true(desc.configurable, "DOMException.prototype.constructor in not configurable");
+ assert_equals(self.DOMException.prototype.constructor, self.DOMException,
+ "DOMException.prototype.constructor is not the same object as DOMException");
+ }, "existence and properties of exception interface prototype object's \"constructor\" property");
+
+ done();
+}
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.worker.js b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.worker.js
new file mode 100644
index 00000000000..75149244f59
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/constructor-object.worker.js
@@ -0,0 +1,3 @@
+importScripts("/resources/testharness.js")
+importScripts("constructor-object.js")
+run_test();
diff --git a/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/exceptions.html b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/exceptions.html
new file mode 100644
index 00000000000..bc1d7fe6395
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/ecmascript-binding/es-exceptions/exceptions.html
@@ -0,0 +1,136 @@
+
+
DOMException-throwing tests
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/enum.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/enum.widl
new file mode 100644
index 00000000000..c355c3251c0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/enum.widl
@@ -0,0 +1 @@
+enum foo { 1, 2, 3};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/module.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/module.widl
new file mode 100644
index 00000000000..a4c79fdf155
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/module.widl
@@ -0,0 +1,25 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+module gfx {
+
+ module geom {
+ interface Shape { /* ... */ };
+ interface Rectangle : Shape { /* ... */ };
+ interface Path : Shape { /* ... */ };
+ };
+
+ interface GraphicsContext {
+ void fillShape(geom::Shape s);
+ void strokeShape(geom::Shape s);
+ };
+};
+
+module gui {
+
+ interface Widget { /* ... */ };
+
+ interface Window : Widget {
+ gfx::GraphicsContext getGraphicsContext();
+ };
+
+ interface Button : Widget { /* ... */ };
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableany.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableany.widl
new file mode 100644
index 00000000000..38957655523
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableany.widl
@@ -0,0 +1,3 @@
+interface NonNullable {
+ attribute any? foo;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableobjects.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableobjects.widl
new file mode 100644
index 00000000000..1deac5aeec9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/nonnullableobjects.widl
@@ -0,0 +1,5 @@
+interface Foo {};
+
+interface NonNullable {
+ attribute Foo?? foo;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/raises.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/raises.widl
new file mode 100644
index 00000000000..ff65522f2b3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/raises.widl
@@ -0,0 +1,18 @@
+// getraises and setraises are not longer valid Web IDL
+interface Person {
+
+ // An attribute that can raise an exception if it is set to an invalid value.
+ attribute DOMString name setraises (InvalidName);
+
+ // An attribute whose value cannot be assigned to, and which can raise an
+ // exception some circumstances.
+ readonly attribute DOMString petName getraises (NoSuchPet);
+};
+
+exception SomeException {
+};
+
+interface ExceptionThrower {
+ // This attribute always throws a SomeException and never returns a value.
+ attribute long valueOf getraises(SomeException);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/scopedname.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/scopedname.widl
new file mode 100644
index 00000000000..cfcb1ccc939
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/scopedname.widl
@@ -0,0 +1,2 @@
+// scoped names are no longer valid in WebIDL
+ typedef gfx::geom::geom2d::Point Point;
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/sequenceAsAttribute.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/sequenceAsAttribute.widl
new file mode 100644
index 00000000000..c23da82ac22
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/sequenceAsAttribute.widl
@@ -0,0 +1,3 @@
+interface sequenceAsAttribute {
+ attribute sequence
invalid;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/special-omittable.widl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/special-omittable.widl
new file mode 100644
index 00000000000..bdfbfa70973
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/special-omittable.widl
@@ -0,0 +1,8 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+// omittable is no longer a recognized keywoard as of 20110905
+interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ omittable getter float getProperty(DOMString propertyName);
+ omittable setter void setProperty(DOMString propertyName, float propertyValue);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/invalid/idl/stringconstants.idl b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/stringconstants.idl
new file mode 100644
index 00000000000..44fd3ff136e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/invalid/idl/stringconstants.idl
@@ -0,0 +1,3 @@
+interface Util {
+ const DOMString hello = "world";
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/readme.txt b/tests/wpt/web-platform-tests/WebIDL/readme.txt
new file mode 100644
index 00000000000..12ded6acdf5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/readme.txt
@@ -0,0 +1,3 @@
+These are syntax tests for WebIDL parser. A correct parser should fail on the tests in the "invalid" directory, and should be able to collect the data necessary to generate the XML serialization for valid fragments collected in the "valid" directory.
+
+(the said XML serialization is the one produced by widlproc https://github.com/dontcallmedom/widlproc from which these tests have been imported)
diff --git a/tests/wpt/web-platform-tests/WebIDL/testable_assertions.txt b/tests/wpt/web-platform-tests/WebIDL/testable_assertions.txt
new file mode 100644
index 00000000000..c1706f8c39d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/testable_assertions.txt
@@ -0,0 +1,29 @@
+{
+ "travil_test_1": {
+ "title": "The Title of this spec",
+ "specRef": "html > body:nth-child(2) > div:nth-child(1) > h1:nth-child(2)",
+ "notes": "This assertion is linked to the H1 in the beginning of the spec.",
+ "author": "Microsoft",
+ "date": "2012-07-11T23:39:23.634Z",
+ "testURL": "",
+ "testApproved": false
+ },
+ "travil_test_2": {
+ "title": "The Initial publication of WebIDL (at the bottom of the spec)",
+ "specRef": "#changes > dl:nth-child(4) > dt:nth-child(19)",
+ "notes": "17 October 2007 was the FPWD.\nTime to start testing.",
+ "author": "Microsoft",
+ "date": "2012-07-11T23:40:41.624Z",
+ "testURL": "",
+ "testApproved": false
+ },
+ "travil_test_3": {
+ "title": "This assertion should not be found (by design)",
+ "specRef": "#does_not_exist > div",
+ "notes": "This is for testing purposes only (testing the framework)",
+ "author": "Microsoft",
+ "date": "2012-07-11T23:40:41.624Z",
+ "testURL": "",
+ "testApproved": false
+ }
+}
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/allowany.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/allowany.widl
new file mode 100644
index 00000000000..2343bb96374
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/allowany.widl
@@ -0,0 +1,6 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface B {
+ void g();
+ void g(B b);
+ void g([AllowAny] DOMString s);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/array.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/array.widl
new file mode 100644
index 00000000000..22e21fb6564
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/array.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[Constructor]
+interface LotteryResults {
+ readonly attribute unsigned short[][] numbers;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/attributes.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/attributes.widl
new file mode 100644
index 00000000000..7e1d691cbe2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/attributes.widl
@@ -0,0 +1,14 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+exception InvalidName {
+ DOMString reason;
+};
+
+exception NoSuchPet { };
+
+interface Person {
+
+ // A simple attribute that can be set to any value the range an unsigned
+ // short can take.
+ attribute unsigned short age;
+
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/callback.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/callback.widl
new file mode 100644
index 00000000000..d92f6a18c0a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/callback.widl
@@ -0,0 +1,5 @@
+callback AsyncOperationCallback = void (DOMString status);
+
+callback interface EventHandler {
+ void eventOccurred(DOMString details);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/caller.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/caller.widl
new file mode 100644
index 00000000000..92acb1c0176
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/caller.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface NumberQuadrupler {
+ // This operation simply returns four times the given number x.
+ legacycaller float compute(float x);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/constants.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/constants.widl
new file mode 100644
index 00000000000..5e28ae9c116
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/constants.widl
@@ -0,0 +1,18 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Util {
+ const boolean DEBUG = false;
+ const short negative = -1;
+ const octet LF = 10;
+ const unsigned long BIT_MASK = 0x0000fc00;
+ const float AVOGADRO = 6.022e23;
+ const unrestricted float sobig = Infinity;
+ const unrestricted double minusonedividedbyzero = -Infinity;
+ const short notanumber = NaN;
+};
+
+exception Error {
+ const short ERR_UNKNOWN = 0;
+ const short ERR_OUT_OF_MEMORY = 1;
+
+ short errorCode;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/constructor.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/constructor.widl
new file mode 100644
index 00000000000..f93ec08a6e6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/constructor.widl
@@ -0,0 +1,9 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[Constructor,
+ Constructor(float radius)]
+interface Circle {
+ attribute float r;
+ attribute float cx;
+ attribute float cy;
+ readonly attribute float circumference;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary-inherits.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary-inherits.widl
new file mode 100644
index 00000000000..48f8a0fdceb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary-inherits.widl
@@ -0,0 +1,9 @@
+dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ Point position;
+};
+
+dictionary WetPaintOptions : PaintOptions {
+ float hydrometry;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary.widl
new file mode 100644
index 00000000000..f46b7ba7806
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/dictionary.widl
@@ -0,0 +1,11 @@
+// Extracted from Web IDL editors draft May 31 2011
+dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ Point position;
+};
+
+partial dictionary A {
+ long h;
+ long d;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation-dos.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation-dos.widl
new file mode 100644
index 00000000000..fb801101f14
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation-dos.widl
@@ -0,0 +1,33 @@
+/**
+* \brief Testing documentation features
+*
+* This is a
+* single paragraph
+*
+* This is valid.
+* This is valid .
+* This is valid .
+* This is valid .
+*
+* This
+* is
+* valid
+*
+*
+* This
+* valid
+*
+*
+*
+* this
+* is
+*
+*
+* valid
+*
+*
+* This is valid.
+* This is valid.
+* This is valid.
+*/
+interface Documentation {};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation.widl
new file mode 100644
index 00000000000..003e9226f67
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/documentation.widl
@@ -0,0 +1,34 @@
+/**
+* \brief Testing documentation features
+*
+* This is a
+* single paragraph
+*
+* This is valid.
+* This is valid .
+* This is valid .
+* This is valid .
+*
+* This
+* is
+* valid
+*
+*
+* This
+* valid
+*
+*
+*
+* this
+* is
+*
+*
+* valid
+*
+*
+* This is valid.
+* This is valid.
+* This is valid.
+*
+*/
+interface Documentation {};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/enum.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/enum.widl
new file mode 100644
index 00000000000..851fca2e6f6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/enum.widl
@@ -0,0 +1,8 @@
+enum MealType { "rice", "noodles", "other" };
+
+interface Meal {
+ attribute MealType type;
+ attribute float size; // in grams
+
+ void initialize(MealType type, float size);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/equivalent-decl.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/equivalent-decl.widl
new file mode 100644
index 00000000000..6b3e0eda284
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/equivalent-decl.widl
@@ -0,0 +1,18 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float getProperty(DOMString propertyName);
+ setter void setProperty(DOMString propertyName, float propertyValue);
+};
+
+
+interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ float getProperty(DOMString propertyName);
+ void setProperty(DOMString propertyName, float propertyValue);
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception-inheritance.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception-inheritance.widl
new file mode 100644
index 00000000000..258fdeba6f4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception-inheritance.widl
@@ -0,0 +1,7 @@
+// from http://lists.w3.org/Archives/Public/public-script-coord/2010OctDec/0112.html
+ exception DOMException {
+ unsigned short code;
+ };
+
+ exception HierarchyRequestError : DOMException { };
+ exception NoModificationAllowedError : DOMException { };
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception.widl
new file mode 100644
index 00000000000..f4b6ae29e10
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/exception.widl
@@ -0,0 +1,8 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Dahut {
+ attribute DOMString type;
+};
+
+exception SomeException {
+};
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/getter-setter.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/getter-setter.widl
new file mode 100644
index 00000000000..bdf87e1c7c7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/getter-setter.widl
@@ -0,0 +1,7 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/identifier-qualified-names.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/identifier-qualified-names.widl
new file mode 100644
index 00000000000..33893d4c644
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/identifier-qualified-names.widl
@@ -0,0 +1,44 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+ // Typedef identifier: "number"
+ // Qualified name: "::framework::number"
+ typedef float number;
+
+ // Exception identifier: "FrameworkException"
+ // Qualified name: "::framework::FrameworkException"
+ exception FrameworkException {
+
+ // Constant identifier: "ERR_NOT_FOUND"
+ // Qualified name: "::framework::FrameworkException::ERR_NOT_FOUND"
+ const long ERR_NOT_FOUND = 1;
+
+ // Exception field identifier: "code"
+ long code;
+ };
+
+ // Interface identifier: "System"
+ // Qualified name: "::framework::System"
+ interface System {
+
+ // Operation identifier: "createObject"
+ // Operation argument identifier: "interface"
+ object createObject(DOMString _interface);
+
+ // Operation has no identifier; it declares a getter.
+ getter DOMString (DOMString keyName);
+ };
+
+
+ // Interface identifier: "TextField"
+ // Qualified name: "::framework::gui::TextField"
+ interface TextField {
+
+ // Attribute identifier: "const"
+ attribute boolean _const;
+
+ // Attribute identifier: "value"
+ attribute DOMString? _value;
+ };
+
+interface Foo {
+ void op(object interface);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/implements.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/implements.widl
new file mode 100644
index 00000000000..7a310926f1c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/implements.widl
@@ -0,0 +1,14 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+ interface Node {
+ readonly attribute unsigned short nodeType;
+ // ...
+ };
+
+ interface EventTarget {
+ void addEventListener(DOMString type,
+ EventListener listener,
+ boolean useCapture);
+ // ...
+ };
+
+ Node implements EventTarget;
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/indexed-properties.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/indexed-properties.widl
new file mode 100644
index 00000000000..acf0ed3bf84
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/indexed-properties.widl
@@ -0,0 +1,12 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface OrderedMap {
+ readonly attribute unsigned long size;
+
+ getter any getByIndex(unsigned long index);
+ setter void setByIndex(unsigned long index, any value);
+ deleter void removeByIndex(unsigned long index);
+
+ getter any get(DOMString name);
+ setter creator void set(DOMString name, any value);
+ deleter void remove(DOMString name);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/inherits-getter.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/inherits-getter.widl
new file mode 100644
index 00000000000..558e8116494
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/inherits-getter.widl
@@ -0,0 +1,16 @@
+interface Animal {
+
+ // A simple attribute that can be set to any string value.
+ readonly attribute DOMString name;
+};
+
+interface Person : Animal {
+
+ // An attribute whose value cannot be assigned to.
+ readonly attribute unsigned short age;
+
+ // An attribute that can raise an exception if it is set to an invalid value.
+ // Its getter behavior is inherited from Animal, and need not be specified
+ // the description of Person.
+ inherit attribute DOMString name;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/interface-inherits.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/interface-inherits.widl
new file mode 100644
index 00000000000..7921def7727
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/interface-inherits.widl
@@ -0,0 +1,12 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Animal {
+ attribute DOMString name;
+};
+
+interface Human : Animal {
+ attribute Dog pet;
+};
+
+interface Dog : Animal {
+ attribute Human owner;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/iterator.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/iterator.widl
new file mode 100644
index 00000000000..3bf1b36dec6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/iterator.widl
@@ -0,0 +1,35 @@
+interface SessionManager {
+ Session getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ Session iterator;
+};
+
+interface Session {
+ readonly attribute DOMString username;
+ // ...
+};
+
+interface SessionManager2 {
+ Session2 getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ Session2 iterator = SessionIterator;
+};
+
+interface Session2 {
+ readonly attribute DOMString username;
+ // ...
+};
+
+interface SessionIterator {
+ readonly attribute unsigned long remainingSessions;
+};
+
+ interface NodeList {
+ Node iterator = NodeIterator;
+ };
+
+ interface NodeIterator {
+ Node iterator object;
+ };
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/namedconstructor.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/namedconstructor.widl
new file mode 100644
index 00000000000..c468b78f8e1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/namedconstructor.widl
@@ -0,0 +1,6 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[NamedConstructor=Audio,
+ NamedConstructor=Audio(DOMString src)]
+interface HTMLAudioElement : HTMLMediaElement {
+ // ...
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/nointerfaceobject.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nointerfaceobject.widl
new file mode 100644
index 00000000000..c17d75ff8fd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nointerfaceobject.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[NoInterfaceObject]
+interface Query {
+ any lookupEntry(unsigned long key);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullable.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullable.widl
new file mode 100644
index 00000000000..ccbf625ff8a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullable.widl
@@ -0,0 +1,9 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface MyConstants {
+ const boolean? ARE_WE_THERE_YET = false;
+};
+
+interface Node {
+ readonly attribute DOMString? namespaceURI;
+ // ...
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullableobjects.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullableobjects.widl
new file mode 100644
index 00000000000..83d1d40b2ac
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/nullableobjects.widl
@@ -0,0 +1,13 @@
+// Extracted from WebIDL spec 2011-05-23
+
+interface A {
+ // ...
+};
+interface B {
+ // ...
+};
+interface C {
+ void f(A? x);
+ void f(B? x);
+
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/operation-optional-arg.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/operation-optional-arg.widl
new file mode 100644
index 00000000000..379053b45f1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/operation-optional-arg.widl
@@ -0,0 +1,4 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface ColorCreator {
+ object createColor(float v1, float v2, float v3, optional float alpha = 3.5);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/overloading.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/overloading.widl
new file mode 100644
index 00000000000..ef1288a8877
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/overloading.widl
@@ -0,0 +1,20 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface A {
+ // ...
+};
+
+interface B {
+ // ...
+};
+
+interface C {
+ void f(A x);
+ void f(B x);
+};
+
+interface A {
+ /* f1 */ void f(DOMString a);
+ /* f2 */ void f([AllowAny] DOMString a, DOMString b, float... c);
+ /* f3 */ void f();
+ /* f4 */ void f(long a, DOMString b, optional DOMString c, float... d);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/overridebuiltins.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/overridebuiltins.widl
new file mode 100644
index 00000000000..79211c29e84
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/overridebuiltins.widl
@@ -0,0 +1,6 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[OverrideBuiltins]
+interface StringMap2 {
+ readonly attribute unsigned long length;
+ getter DOMString lookup(DOMString key);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/partial-interface.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/partial-interface.widl
new file mode 100644
index 00000000000..90e7e0ea421
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/partial-interface.widl
@@ -0,0 +1,7 @@
+interface Foo {
+ attribute DOMString bar;
+};
+
+partial interface Foo {
+ attribute DOMString quux;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/primitives.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/primitives.widl
new file mode 100644
index 00000000000..92939601a1a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/primitives.widl
@@ -0,0 +1,19 @@
+interface Primitives {
+ attribute boolean truth;
+ attribute byte character;
+ attribute octet value;
+ attribute short number;
+ attribute unsigned short positive;
+ attribute long big;
+ attribute unsigned long bigpositive;
+ attribute long long bigbig;
+ attribute unsigned long long bigbigpositive;
+ attribute float real;
+ attribute double bigreal;
+ attribute unrestricted float realwithinfinity;
+ attribute unrestricted double bigrealwithinfinity;
+ attribute DOMString string;
+ attribute ByteString bytes;
+ attribute Date date;
+ attribute RegExp regexp;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/prototyperoot.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/prototyperoot.widl
new file mode 100644
index 00000000000..30dd5cbca13
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/prototyperoot.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[PrototypeRoot]
+interface Node {
+ readonly attribute unsigned short nodeType;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/putforwards.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/putforwards.widl
new file mode 100644
index 00000000000..1e50a4ee394
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/putforwards.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Person {
+ [PutForwards=full] readonly attribute Name name;
+ attribute unsigned short age;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/reg-operations.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/reg-operations.widl
new file mode 100644
index 00000000000..13997cb1d12
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/reg-operations.widl
@@ -0,0 +1,17 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Dimensions {
+ attribute unsigned long width;
+ attribute unsigned long height;
+};
+
+exception NoPointerDevice { };
+
+interface Button {
+
+ // An operation that takes no arguments, returns a boolean
+ boolean isMouseOver();
+
+ // Overloaded operations.
+ void setDimensions(Dimensions size);
+ void setDimensions(unsigned long width, unsigned long height);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/replaceable.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/replaceable.widl
new file mode 100644
index 00000000000..c14d0c37689
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/replaceable.widl
@@ -0,0 +1,5 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Counter {
+ [Replaceable] readonly attribute unsigned long value;
+ void increment();
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/sequence.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/sequence.widl
new file mode 100644
index 00000000000..a1aa931f5f0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/sequence.widl
@@ -0,0 +1,7 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+// edited to remove sequence as attributes, now invalid
+interface Canvas {
+ void drawPolygon(sequence coordinates);
+ sequence getInflectionPoints();
+ // ...
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/serializer.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/serializer.widl
new file mode 100644
index 00000000000..6f6ccd0e8d5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/serializer.widl
@@ -0,0 +1,64 @@
+interface Transaction {
+ readonly attribute Account from;
+ readonly attribute Account to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer;
+};
+
+interface Account {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer DOMString serialize();
+};
+
+interface Transaction2 {
+ readonly attribute Account2 from;
+ readonly attribute Account2 to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer = { from, to, amount, description };
+};
+
+interface Account2 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = number;
+};
+
+interface Account3 {
+ attribute DOMString name;
+ attribute unsigned long number;
+
+ serializer = { attribute };
+};
+
+interface Account4 {
+ getter object getItem(unsigned long index);
+ serializer = { getter };
+};
+
+interface Account5 : Account {
+ attribute DOMString secondname;
+ serializer = { inherit, secondname };
+};
+
+interface Account6 : Account {
+ attribute DOMString secondname;
+ serializer = { inherit, attribute };
+};
+
+interface Account7 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = [ name, number ];
+};
+
+interface Account8 {
+ getter object getItem(unsigned long index);
+ serializer = [ getter ];
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/static.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/static.widl
new file mode 100644
index 00000000000..5b2cd36590f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/static.widl
@@ -0,0 +1,11 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Point { /* ... */ };
+
+interface Circle {
+ attribute float cx;
+ attribute float cy;
+ attribute float radius;
+
+ static readonly attribute long triangulationCount;
+ static Point triangulate(Circle c1, Circle c2, Circle c3);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-attribute.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-attribute.widl
new file mode 100644
index 00000000000..c964ecb93e6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-attribute.widl
@@ -0,0 +1,6 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[Constructor]
+interface Student {
+ attribute unsigned long id;
+ stringifier attribute DOMString name;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-custom.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-custom.widl
new file mode 100644
index 00000000000..b5d7c87e7f4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier-custom.widl
@@ -0,0 +1,9 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+[Constructor]
+interface Student {
+ attribute unsigned long id;
+ attribute DOMString? familyName;
+ attribute DOMString givenName;
+
+ stringifier DOMString ();
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier.widl
new file mode 100644
index 00000000000..4eb483d9b53
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/stringifier.widl
@@ -0,0 +1,8 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface A {
+ stringifier DOMString ();
+};
+
+interface A {
+ stringifier;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasnull.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasnull.widl
new file mode 100644
index 00000000000..d3c55b008c0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasnull.widl
@@ -0,0 +1,7 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Dog {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatNullAs=EmptyString] DOMString breedName);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasundefined.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasundefined.widl
new file mode 100644
index 00000000000..e30050f8413
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/treatasundefined.widl
@@ -0,0 +1,7 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface Cat {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatUndefinedAs=EmptyString] DOMString breedName);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/typedef.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/typedef.widl
new file mode 100644
index 00000000000..b4c17d8d36a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/typedef.widl
@@ -0,0 +1,22 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+ interface Point {
+ attribute float x;
+ attribute float y;
+ };
+
+ typedef sequence PointSequence;
+
+ interface Rect {
+ attribute Point topleft;
+ attribute Point bottomright;
+ };
+
+ interface Widget {
+
+ readonly attribute Rect bounds;
+
+ boolean pointWithinBounds(Point p);
+ boolean allPointsWithinBounds(PointSequence ps);
+ };
+
+ typedef [Clamp] octet value;
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/typesuffixes.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/typesuffixes.widl
new file mode 100644
index 00000000000..95e31c16902
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/typesuffixes.widl
@@ -0,0 +1,3 @@
+interface Suffixes {
+ void test(sequence? foo);
+};
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/uniontype.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/uniontype.widl
new file mode 100644
index 00000000000..4d99f019630
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/uniontype.widl
@@ -0,0 +1,3 @@
+interface Union {
+ attribute (float or (Date or Event) or (Node or DOMString)?) test;
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/idl/variadic-operations.widl b/tests/wpt/web-platform-tests/WebIDL/valid/idl/variadic-operations.widl
new file mode 100644
index 00000000000..51fae4cc1ea
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/idl/variadic-operations.widl
@@ -0,0 +1,7 @@
+// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
+interface IntegerSet {
+ readonly attribute unsigned long cardinality;
+
+ void union(long... ints);
+ void intersection(long... ints);
+};
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/allowany.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/allowany.widlprocxml
new file mode 100644
index 00000000000..7da508bcb5c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/allowany.widlprocxml
@@ -0,0 +1,44 @@
+
+
+
+ interface B {
+ void g();
+ void g([B] b);
+ void g([AllowAny] DOMString s);
+};
+
+ interface B {
+ void g();
+ void g([B] b);
+ void g([AllowAny] DOMString s);
+};
+
+ void g();
+
+
+
+
+ void g([B] b);
+
+
+
+
+
+
+
+
+ void g([AllowAny] DOMString s);
+
+
+
+
+
+ AllowAny
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/array.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/array.widlprocxml
new file mode 100644
index 00000000000..3df72ff1608
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/array.widlprocxml
@@ -0,0 +1,27 @@
+
+
+
+ [Constructor]
+interface LotteryResults {
+ readonly attribute unsigned short[][] numbers;
+};
+
+ [Constructor]
+interface LotteryResults {
+ readonly attribute unsigned short[][] numbers;
+};
+
+
+ Constructor
+
+
+
+ readonly attribute unsigned short[][] numbers;
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/attributes.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/attributes.widlprocxml
new file mode 100644
index 00000000000..89bd8ac9b01
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/attributes.widlprocxml
@@ -0,0 +1,38 @@
+
+
+
+ exception InvalidName {
+ DOMString reason;
+};
+
+exception NoSuchPet { };
+
+interface Person {
+
+ attribute unsigned short age;
+
+};
+
+ exception InvalidName {
+ DOMString reason;
+};
+
+ DOMString reason;
+
+
+
+
+ exception NoSuchPet { };
+
+
+ interface Person {
+
+ attribute unsigned short age;
+
+};
+
+ attribute unsigned short age;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/callback.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/callback.widlprocxml
new file mode 100644
index 00000000000..9eac06ce279
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/callback.widlprocxml
@@ -0,0 +1,32 @@
+
+
+
+ callback AsyncOperationCallback = void (DOMString status);
+
+callback interface EventHandler {
+ void eventOccurred(DOMString details);
+};
+
+ callback AsyncOperationCallback = void (DOMString status);
+
+
+
+
+
+
+
+
+ callback interface EventHandler {
+ void eventOccurred(DOMString details);
+};
+
+ void eventOccurred(DOMString details);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/caller.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/caller.widlprocxml
new file mode 100644
index 00000000000..9754d4e0268
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/caller.widlprocxml
@@ -0,0 +1,21 @@
+
+
+
+ interface NumberQuadrupler {
+ legacycaller float compute(float x);
+};
+
+ interface NumberQuadrupler {
+ legacycaller float compute(float x);
+};
+
+ legacycaller float compute(float x);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/constants.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/constants.widlprocxml
new file mode 100644
index 00000000000..51cb4331f75
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/constants.widlprocxml
@@ -0,0 +1,85 @@
+
+
+
+ interface Util {
+ const boolean DEBUG = false;
+ const short negative = -1;
+ const octet LF = 10;
+ const unsigned long BIT_MASK = 0x0000fc00;
+ const float AVOGADRO = 6.022e23;
+ const unrestricted float sobig = Infinity;
+ const unrestricted double minusonedividedbyzero = -Infinity;
+ const short notanumber = NaN;
+};
+
+exception Error {
+ const short ERR_UNKNOWN = 0;
+ const short ERR_OUT_OF_MEMORY = 1;
+
+ short errorCode;
+};
+
+ interface Util {
+ const boolean DEBUG = false;
+ const short negative = -1;
+ const octet LF = 10;
+ const unsigned long BIT_MASK = 0x0000fc00;
+ const float AVOGADRO = 6.022e23;
+ const unrestricted float sobig = Infinity;
+ const unrestricted double minusonedividedbyzero = -Infinity;
+ const short notanumber = NaN;
+};
+
+ const boolean DEBUG = false;
+
+
+
+ const short negative = -1;
+
+
+
+ const octet LF = 10;
+
+
+
+ const unsigned long BIT_MASK = 0x0000fc00;
+
+
+
+ const float AVOGADRO = 6.022e23;
+
+
+
+ const unrestricted float sobig = Infinity;
+
+
+
+ const unrestricted double minusonedividedbyzero = -Infinity;
+
+
+
+ const short notanumber = NaN;
+
+
+
+
+ exception Error {
+ const short ERR_UNKNOWN = 0;
+ const short ERR_OUT_OF_MEMORY = 1;
+
+ short errorCode;
+};
+
+ const short ERR_UNKNOWN = 0;
+
+
+
+ const short ERR_OUT_OF_MEMORY = 1;
+
+
+
+ short errorCode;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/constructor.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/constructor.widlprocxml
new file mode 100644
index 00000000000..8e78fbab365
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/constructor.widlprocxml
@@ -0,0 +1,51 @@
+
+
+
+ [Constructor,
+ Constructor(float radius)]
+interface Circle {
+ attribute float r;
+ attribute float cx;
+ attribute float cy;
+ readonly attribute float circumference;
+};
+
+ [Constructor,
+ Constructor(float radius)]
+interface Circle {
+ attribute float r;
+ attribute float cx;
+ attribute float cy;
+ readonly attribute float circumference;
+};
+
+
+ Constructor
+
+
+ Constructor(float radius)
+
+
+
+
+
+
+
+
+ attribute float r;
+
+
+
+ attribute float cx;
+
+
+
+ attribute float cy;
+
+
+
+ readonly attribute float circumference;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary-inherits.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary-inherits.widlprocxml
new file mode 100644
index 00000000000..269a83cd849
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary-inherits.widlprocxml
@@ -0,0 +1,44 @@
+
+
+
+ dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ [Point] position;
+};
+
+dictionary WetPaintOptions : [PaintOptions] {
+ float hydrometry;
+};
+
+ dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ [Point] position;
+};
+
+ DOMString? fillPattern = "black";
+
+
+
+ DOMString? strokePattern = null;
+
+
+
+ [Point] position;
+
+
+
+
+ dictionary WetPaintOptions : [PaintOptions] {
+ float hydrometry;
+};
+
+
+
+
+ float hydrometry;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary.widlprocxml
new file mode 100644
index 00000000000..978ccb4e271
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/dictionary.widlprocxml
@@ -0,0 +1,47 @@
+
+
+
+ dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ [Point] position;
+};
+
+partial dictionary A {
+ long h;
+ long d;
+};
+
+ dictionary PaintOptions {
+ DOMString? fillPattern = "black";
+ DOMString? strokePattern = null;
+ [Point] position;
+};
+
+ DOMString? fillPattern = "black";
+
+
+
+ DOMString? strokePattern = null;
+
+
+
+ [Point] position;
+
+
+
+
+ partial dictionary A {
+ long h;
+ long d;
+};
+
+ long h;
+
+
+
+ long d;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation-dos.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation-dos.widlprocxml
new file mode 100644
index 00000000000..1611f0e576a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation-dos.widlprocxml
@@ -0,0 +1,59 @@
+
+
+
+ interface Documentation {};
+
+ interface Documentation {};
+
+
+ Testing documentation features
+
+
+
+This is a
+single paragraph
+
+
+This is valid.
+
+This is valid .
+
+This is valid .
+
+This is valid .
+
+
+
+This
+
+valid
+
+
+
+
+this
+
+is
+
+
+
+valid
+
+
+
+This is valid.
+
+This is valid.
+
+This is valid.
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation.widlprocxml
new file mode 100644
index 00000000000..afe4527c221
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/documentation.widlprocxml
@@ -0,0 +1,61 @@
+
+
+
+ interface Documentation {};
+
+ interface Documentation {};
+
+
+ Testing documentation features
+
+
+
+This is a
+single paragraph
+
+
+This is valid.
+
+This is valid .
+
+This is valid .
+
+This is valid .
+
+
+
+This
+
+valid
+
+
+
+
+this
+
+is
+
+
+
+valid
+
+
+
+This is valid.
+
+This is valid.
+
+This is valid.
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/enum.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/enum.widlprocxml
new file mode 100644
index 00000000000..e1e8258fbd0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/enum.widlprocxml
@@ -0,0 +1,52 @@
+
+
+
+ enum MealType { "rice", "noodles", "other" };
+
+interface Meal {
+ attribute [MealType] type;
+ attribute float size;
+
+ void initialize([MealType] type, float size);
+};
+
+ enum MealType { "rice", "noodles", "other" };
+
+ "rice
+
+
+ "noodles
+
+
+ "other
+
+
+
+ interface Meal {
+ attribute [MealType] type;
+ attribute float size;
+
+ void initialize([MealType] type, float size);
+};
+
+ attribute [MealType] type;
+
+
+
+ attribute float size;
+
+
+
+ void initialize([MealType] type, float size);
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/equivalent-decl.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/equivalent-decl.widlprocxml
new file mode 100644
index 00000000000..c322d0a5e22
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/equivalent-decl.widlprocxml
@@ -0,0 +1,111 @@
+
+
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float getProperty(DOMString propertyName);
+ setter void setProperty(DOMString propertyName, float propertyValue);
+};
+
+
+interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ float getProperty(DOMString propertyName);
+ void setProperty(DOMString propertyName, float propertyValue);
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float getProperty(DOMString propertyName);
+ setter void setProperty(DOMString propertyName, float propertyValue);
+};
+
+ readonly attribute unsigned long propertyCount;
+
+
+
+ getter float getProperty(DOMString propertyName);
+
+
+
+
+
+
+
+
+ setter void setProperty(DOMString propertyName, float propertyValue);
+
+
+
+
+
+
+
+
+
+
+
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ float getProperty(DOMString propertyName);
+ void setProperty(DOMString propertyName, float propertyValue);
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
+
+ readonly attribute unsigned long propertyCount;
+
+
+
+ float getProperty(DOMString propertyName);
+
+
+
+
+
+
+
+
+ void setProperty(DOMString propertyName, float propertyValue);
+
+
+
+
+
+
+
+
+
+
+
+ getter float (DOMString propertyName);
+
+
+
+
+
+
+
+
+ setter void (DOMString propertyName, float propertyValue);
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception-inheritance.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception-inheritance.widlprocxml
new file mode 100644
index 00000000000..3a1f868a4b4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception-inheritance.widlprocxml
@@ -0,0 +1,31 @@
+
+
+
+ exception DOMException {
+ unsigned short code;
+ };
+
+ exception HierarchyRequestError : [DOMException] { };
+ exception NoModificationAllowedError : [DOMException] { };
+
+ exception DOMException {
+ unsigned short code;
+ };
+
+ unsigned short code;
+
+
+
+
+ exception HierarchyRequestError : [DOMException] { };
+
+
+
+
+
+ exception NoModificationAllowedError : [DOMException] { };
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception.widlprocxml
new file mode 100644
index 00000000000..ac93320fe16
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/exception.widlprocxml
@@ -0,0 +1,23 @@
+
+
+
+ interface Dahut {
+ attribute DOMString type;
+};
+
+exception SomeException {
+};
+
+ interface Dahut {
+ attribute DOMString type;
+};
+
+ attribute DOMString type;
+
+
+
+
+ exception SomeException {
+};
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/getter-setter.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/getter-setter.widlprocxml
new file mode 100644
index 00000000000..76afc058c68
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/getter-setter.widlprocxml
@@ -0,0 +1,43 @@
+
+
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ getter float (DOMString propertyName);
+ setter void (DOMString propertyName, float propertyValue);
+};
+
+ readonly attribute unsigned long propertyCount;
+
+
+
+ getter float (DOMString propertyName);
+
+
+
+
+
+
+
+
+ setter void (DOMString propertyName, float propertyValue);
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/identifier-qualified-names.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/identifier-qualified-names.widlprocxml
new file mode 100644
index 00000000000..b6024e5ff68
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/identifier-qualified-names.widlprocxml
@@ -0,0 +1,107 @@
+
+
+
+ typedef float number;
+
+ exception FrameworkException {
+
+ const long ERR_NOT_FOUND = 1;
+
+ long code;
+ };
+
+ interface System {
+
+ object createObject(DOMString _interface);
+
+ getter DOMString (DOMString keyName);
+ };
+
+
+ interface TextField {
+
+ attribute boolean _const;
+
+ attribute DOMString? _value;
+ };
+
+interface Foo {
+ void op(object interface);
+};
+
+ typedef float number;
+
+
+
+ exception FrameworkException {
+
+ const long ERR_NOT_FOUND = 1;
+
+ long code;
+ };
+
+ const long ERR_NOT_FOUND = 1;
+
+
+
+ long code;
+
+
+
+
+ interface System {
+
+ object createObject(DOMString _interface);
+
+ getter DOMString (DOMString keyName);
+ };
+
+ object createObject(DOMString _interface);
+
+
+
+
+
+
+
+
+ getter DOMString (DOMString keyName);
+
+
+
+
+
+
+
+
+
+ interface TextField {
+
+ attribute boolean _const;
+
+ attribute DOMString? _value;
+ };
+
+ attribute boolean _const;
+
+
+
+ attribute DOMString? _value;
+
+
+
+
+ interface Foo {
+ void op(object interface);
+};
+
+ void op(object interface);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/implements.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/implements.widlprocxml
new file mode 100644
index 00000000000..3d1c1ab8478
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/implements.widlprocxml
@@ -0,0 +1,51 @@
+
+
+
+ interface Node {
+ readonly attribute unsigned short nodeType;
+ };
+
+ interface EventTarget {
+ void addEventListener(DOMString type,
+ [EventListener] listener,
+ boolean useCapture);
+ };
+
+ [Node] implements [EventTarget];
+
+ interface Node {
+ readonly attribute unsigned short nodeType;
+ };
+
+ readonly attribute unsigned short nodeType;
+
+
+
+
+ interface EventTarget {
+ void addEventListener(DOMString type,
+ [EventListener] listener,
+ boolean useCapture);
+ };
+
+ void addEventListener(DOMString type,
+ [EventListener] listener,
+ boolean useCapture);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [Node] implements [EventTarget];
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/indexed-properties.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/indexed-properties.widlprocxml
new file mode 100644
index 00000000000..fb83621b60d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/indexed-properties.widlprocxml
@@ -0,0 +1,92 @@
+
+
+
+ interface OrderedMap {
+ readonly attribute unsigned long size;
+
+ getter any getByIndex(unsigned long index);
+ setter void setByIndex(unsigned long index, any value);
+ deleter void removeByIndex(unsigned long index);
+
+ getter any get(DOMString name);
+ setter creator void set(DOMString name, any value);
+ deleter void remove(DOMString name);
+};
+
+ interface OrderedMap {
+ readonly attribute unsigned long size;
+
+ getter any getByIndex(unsigned long index);
+ setter void setByIndex(unsigned long index, any value);
+ deleter void removeByIndex(unsigned long index);
+
+ getter any get(DOMString name);
+ setter creator void set(DOMString name, any value);
+ deleter void remove(DOMString name);
+};
+
+ readonly attribute unsigned long size;
+
+
+
+ getter any getByIndex(unsigned long index);
+
+
+
+
+
+
+
+
+ setter void setByIndex(unsigned long index, any value);
+
+
+
+
+
+
+
+
+
+
+
+ deleter void removeByIndex(unsigned long index);
+
+
+
+
+
+
+
+
+ getter any get(DOMString name);
+
+
+
+
+
+
+
+
+ setter creator void set(DOMString name, any value);
+
+
+
+
+
+
+
+
+
+
+
+ deleter void remove(DOMString name);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/inherits-getter.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/inherits-getter.widlprocxml
new file mode 100644
index 00000000000..55e7a317fd9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/inherits-getter.widlprocxml
@@ -0,0 +1,44 @@
+
+
+
+ interface Animal {
+
+ readonly attribute DOMString name;
+};
+
+interface Person : [Animal] {
+
+ readonly attribute unsigned short age;
+
+ inherit attribute DOMString name;
+};
+
+ interface Animal {
+
+ readonly attribute DOMString name;
+};
+
+ readonly attribute DOMString name;
+
+
+
+
+ interface Person : [Animal] {
+
+ readonly attribute unsigned short age;
+
+ inherit attribute DOMString name;
+};
+
+
+
+
+ readonly attribute unsigned short age;
+
+
+
+ inherit attribute DOMString name;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/interface-inherits.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/interface-inherits.widlprocxml
new file mode 100644
index 00000000000..94f0e29df05
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/interface-inherits.widlprocxml
@@ -0,0 +1,48 @@
+
+
+
+ interface Animal {
+ attribute DOMString name;
+};
+
+interface Human : [Animal] {
+ attribute [Dog] pet;
+};
+
+interface Dog : [Animal] {
+ attribute [Human] owner;
+};
+
+ interface Animal {
+ attribute DOMString name;
+};
+
+ attribute DOMString name;
+
+
+
+
+ interface Human : [Animal] {
+ attribute [Dog] pet;
+};
+
+
+
+
+ attribute [Dog] pet;
+
+
+
+
+ interface Dog : [Animal] {
+ attribute [Human] owner;
+};
+
+
+
+
+ attribute [Human] owner;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/iterator.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/iterator.widlprocxml
new file mode 100644
index 00000000000..8ca95fbbd17
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/iterator.widlprocxml
@@ -0,0 +1,132 @@
+
+
+
+ interface SessionManager {
+ [Session] getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ [Session] iterator;
+};
+
+interface Session {
+ readonly attribute DOMString username;
+};
+
+interface SessionManager2 {
+ [Session2] getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ [Session2] iterator = SessionIterator;
+};
+
+interface Session2 {
+ readonly attribute DOMString username;
+};
+
+interface SessionIterator {
+ readonly attribute unsigned long remainingSessions;
+};
+
+ interface NodeList {
+ [Node] iterator = NodeIterator;
+ };
+
+ interface NodeIterator {
+ [Node] iterator object;
+ };
+
+ interface SessionManager {
+ [Session] getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ [Session] iterator;
+};
+
+ [Session] getSessionForUser(DOMString username);
+
+
+
+
+
+
+
+
+ readonly attribute unsigned long sessionCount;
+
+
+
+ [Session] iterator;
+
+
+
+
+ interface Session {
+ readonly attribute DOMString username;
+};
+
+ readonly attribute DOMString username;
+
+
+
+
+ interface SessionManager2 {
+ [Session2] getSessionForUser(DOMString username);
+ readonly attribute unsigned long sessionCount;
+
+ [Session2] iterator = SessionIterator;
+};
+
+ [Session2] getSessionForUser(DOMString username);
+
+
+
+
+
+
+
+
+ readonly attribute unsigned long sessionCount;
+
+
+
+ [Session2] iterator = SessionIterator;
+
+
+
+
+ interface Session2 {
+ readonly attribute DOMString username;
+};
+
+ readonly attribute DOMString username;
+
+
+
+
+ interface SessionIterator {
+ readonly attribute unsigned long remainingSessions;
+};
+
+ readonly attribute unsigned long remainingSessions;
+
+
+
+
+ interface NodeList {
+ [Node] iterator = NodeIterator;
+ };
+
+ [Node] iterator = NodeIterator;
+
+
+
+
+ interface NodeIterator {
+ [Node] iterator object;
+ };
+
+ [Node] iterator object;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/module.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/module.widlprocxml
new file mode 100644
index 00000000000..b575b8705af
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/module.widlprocxml
@@ -0,0 +1,99 @@
+
+
+
+
+ module gfx {
+
+ module geom {
+ interface Shape { };
+ interface Rectangle : [Shape] { };
+ interface Path : [Shape] { };
+ };
+
+ interface GraphicsContext {
+ void fillShape([geom::Shape] s);
+ void strokeShape([geom::Shape] s);
+ };
+};
+
+ module geom {
+ interface Shape { };
+ interface Rectangle : [Shape] { };
+ interface Path : [Shape] { };
+ };
+
+ interface Shape { };
+
+
+ interface Rectangle : [Shape] { };
+
+
+
+
+
+ interface Path : [Shape] { };
+
+
+
+
+
+
+ interface GraphicsContext {
+ void fillShape([geom::Shape] s);
+ void strokeShape([geom::Shape] s);
+ };
+
+ void fillShape([geom::Shape] s);
+
+
+
+
+
+
+
+
+ void strokeShape([geom::Shape] s);
+
+
+
+
+
+
+
+
+
+
+ module gui {
+
+ interface Widget { };
+
+ interface Window : [Widget] {
+ [gfx::GraphicsContext] getGraphicsContext();
+ };
+
+ interface Button : [Widget] { };
+};
+
+ interface Widget { };
+
+
+ interface Window : [Widget] {
+ [gfx::GraphicsContext] getGraphicsContext();
+ };
+
+
+
+
+ [gfx::GraphicsContext] getGraphicsContext();
+
+
+
+
+
+ interface Button : [Widget] { };
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/namedconstructor.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/namedconstructor.widlprocxml
new file mode 100644
index 00000000000..9f661612879
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/namedconstructor.widlprocxml
@@ -0,0 +1,30 @@
+
+
+
+ [NamedConstructor=Audio,
+ NamedConstructor=Audio(DOMString src)]
+interface HTMLAudioElement : [HTMLMediaElement] {
+};
+
+ [NamedConstructor=Audio,
+ NamedConstructor=Audio(DOMString src)]
+interface HTMLAudioElement : [HTMLMediaElement] {
+};
+
+
+ NamedConstructor
+
+
+ NamedConstructor=Audio(DOMString src)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/namespaceobject.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/namespaceobject.widlprocxml
new file mode 100644
index 00000000000..af0cde93719
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/namespaceobject.widlprocxml
@@ -0,0 +1,60 @@
+
+
+
+
+ [NamespaceObject]
+module acme {
+
+ exception DeviceException { };
+
+ module pim {
+
+ [Constructor]
+ interface Contact { };
+
+ [Constructor,
+ NamedConstructor=RecurringEvent(long freq)]
+ interface CalendarEvent { };
+ };
+};
+
+
+
+
+ exception DeviceException { };
+
+
+ module pim {
+
+ [Constructor]
+ interface Contact { };
+
+ [Constructor,
+ NamedConstructor=RecurringEvent(long freq)]
+ interface CalendarEvent { };
+ };
+
+ [Constructor]
+ interface Contact { };
+
+
+
+
+
+ [Constructor,
+ NamedConstructor=RecurringEvent(long freq)]
+ interface CalendarEvent { };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/nointerfaceobject.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nointerfaceobject.widlprocxml
new file mode 100644
index 00000000000..f64f116b60f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nointerfaceobject.widlprocxml
@@ -0,0 +1,28 @@
+
+
+
+ [NoInterfaceObject]
+interface Query {
+ any lookupEntry(unsigned long key);
+};
+
+ [NoInterfaceObject]
+interface Query {
+ any lookupEntry(unsigned long key);
+};
+
+
+ NoInterfaceObject
+
+
+
+ any lookupEntry(unsigned long key);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullable.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullable.widlprocxml
new file mode 100644
index 00000000000..8739e443262
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullable.widlprocxml
@@ -0,0 +1,29 @@
+
+
+
+ interface MyConstants {
+ const boolean? ARE_WE_THERE_YET = false;
+};
+
+interface Node {
+ readonly attribute DOMString? namespaceURI;
+};
+
+ interface MyConstants {
+ const boolean? ARE_WE_THERE_YET = false;
+};
+
+ const boolean? ARE_WE_THERE_YET = false;
+
+
+
+
+ interface Node {
+ readonly attribute DOMString? namespaceURI;
+};
+
+ readonly attribute DOMString? namespaceURI;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullableobjects.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullableobjects.widlprocxml
new file mode 100644
index 00000000000..22d9fdd25d6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/nullableobjects.widlprocxml
@@ -0,0 +1,46 @@
+
+
+
+ interface A {
+};
+interface B {
+};
+interface C {
+ void f([A]? x);
+ void f([B]? x);
+
+};
+
+ interface A {
+};
+
+
+ interface B {
+};
+
+
+ interface C {
+ void f([A]? x);
+ void f([B]? x);
+
+};
+
+ void f([A]? x);
+
+
+
+
+
+
+
+
+ void f([B]? x);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/operation-optional-arg.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/operation-optional-arg.widlprocxml
new file mode 100644
index 00000000000..54aef1f87e3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/operation-optional-arg.widlprocxml
@@ -0,0 +1,30 @@
+
+
+
+ interface ColorCreator {
+ object createColor(float v1, float v2, float v3, optional float alpha = 3.5);
+};
+
+ interface ColorCreator {
+ object createColor(float v1, float v2, float v3, optional float alpha = 3.5);
+};
+
+ object createColor(float v1, float v2, float v3, optional float alpha = 3.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/overloading.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/overloading.widlprocxml
new file mode 100644
index 00000000000..db6da7a68c7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/overloading.widlprocxml
@@ -0,0 +1,113 @@
+
+
+
+ interface A {
+};
+
+interface B {
+};
+
+interface C {
+ void f([A] x);
+ void f([B] x);
+};
+
+interface A {
+void f(DOMString a);
+void f([AllowAny] DOMString a, DOMString b, float... c);
+void f();
+void f(long a, DOMString b, optional DOMString c, float... d);
+};
+
+ interface A {
+};
+
+
+ interface B {
+};
+
+
+ interface C {
+ void f([A] x);
+ void f([B] x);
+};
+
+ void f([A] x);
+
+
+
+
+
+
+
+
+ void f([B] x);
+
+
+
+
+
+
+
+
+
+ interface A {
+void f(DOMString a);
+void f([AllowAny] DOMString a, DOMString b, float... c);
+void f();
+void f(long a, DOMString b, optional DOMString c, float... d);
+};
+
+ void f(DOMString a);
+
+
+
+
+
+
+
+
+ void f([AllowAny] DOMString a, DOMString b, float... c);
+
+
+
+
+
+ AllowAny
+
+
+
+
+
+
+
+
+
+
+
+
+
+ void f();
+
+
+
+
+ void f(long a, DOMString b, optional DOMString c, float... d);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/overridebuiltins.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/overridebuiltins.widlprocxml
new file mode 100644
index 00000000000..56c92517beb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/overridebuiltins.widlprocxml
@@ -0,0 +1,34 @@
+
+
+
+ [OverrideBuiltins]
+interface StringMap2 {
+ readonly attribute unsigned long length;
+ getter DOMString lookup(DOMString key);
+};
+
+ [OverrideBuiltins]
+interface StringMap2 {
+ readonly attribute unsigned long length;
+ getter DOMString lookup(DOMString key);
+};
+
+
+ OverrideBuiltins
+
+
+
+ readonly attribute unsigned long length;
+
+
+
+ getter DOMString lookup(DOMString key);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/partial-interface.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/partial-interface.widlprocxml
new file mode 100644
index 00000000000..8d7dcb4e4f7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/partial-interface.widlprocxml
@@ -0,0 +1,29 @@
+
+
+
+ interface Foo {
+ attribute DOMString bar;
+};
+
+partial interface Foo {
+ attribute DOMString quux;
+};
+
+ interface Foo {
+ attribute DOMString bar;
+};
+
+ attribute DOMString bar;
+
+
+
+
+ partial interface Foo {
+ attribute DOMString quux;
+};
+
+ attribute DOMString quux;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/primitives.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/primitives.widlprocxml
new file mode 100644
index 00000000000..46977a2d74e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/primitives.widlprocxml
@@ -0,0 +1,112 @@
+
+
+
+ interface Primitives {
+ attribute boolean truth;
+ attribute byte character;
+ attribute octet value;
+ attribute short number;
+ attribute unsigned short positive;
+ attribute long big;
+ attribute unsigned long bigpositive;
+ attribute long long bigbig;
+ attribute unsigned long long bigbigpositive;
+ attribute float real;
+ attribute double bigreal;
+ attribute unrestricted float realwithinfinity;
+ attribute unrestricted double bigrealwithinfinity;
+ attribute DOMString string;
+ attribute ByteString bytes;
+ attribute Date date;
+ attribute RegExp regexp;
+};
+
+ interface Primitives {
+ attribute boolean truth;
+ attribute byte character;
+ attribute octet value;
+ attribute short number;
+ attribute unsigned short positive;
+ attribute long big;
+ attribute unsigned long bigpositive;
+ attribute long long bigbig;
+ attribute unsigned long long bigbigpositive;
+ attribute float real;
+ attribute double bigreal;
+ attribute unrestricted float realwithinfinity;
+ attribute unrestricted double bigrealwithinfinity;
+ attribute DOMString string;
+ attribute ByteString bytes;
+ attribute Date date;
+ attribute RegExp regexp;
+};
+
+ attribute boolean truth;
+
+
+
+ attribute byte character;
+
+
+
+ attribute octet value;
+
+
+
+ attribute short number;
+
+
+
+ attribute unsigned short positive;
+
+
+
+ attribute long big;
+
+
+
+ attribute unsigned long bigpositive;
+
+
+
+ attribute long long bigbig;
+
+
+
+ attribute unsigned long long bigbigpositive;
+
+
+
+ attribute float real;
+
+
+
+ attribute double bigreal;
+
+
+
+ attribute unrestricted float realwithinfinity;
+
+
+
+ attribute unrestricted double bigrealwithinfinity;
+
+
+
+ attribute DOMString string;
+
+
+
+ attribute ByteString bytes;
+
+
+
+ attribute Date date;
+
+
+
+ attribute RegExp regexp;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/prototyperoot.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/prototyperoot.widlprocxml
new file mode 100644
index 00000000000..2e56cd75ec3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/prototyperoot.widlprocxml
@@ -0,0 +1,23 @@
+
+
+
+ [PrototypeRoot]
+interface Node {
+ readonly attribute unsigned short nodeType;
+};
+
+ [PrototypeRoot]
+interface Node {
+ readonly attribute unsigned short nodeType;
+};
+
+
+ PrototypeRoot
+
+
+
+ readonly attribute unsigned short nodeType;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/putforwards.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/putforwards.widlprocxml
new file mode 100644
index 00000000000..634fad55a56
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/putforwards.widlprocxml
@@ -0,0 +1,27 @@
+
+
+
+ interface Person {
+ [PutForwards=full] readonly attribute [Name] name;
+ attribute unsigned short age;
+};
+
+ interface Person {
+ [PutForwards=full] readonly attribute [Name] name;
+ attribute unsigned short age;
+};
+
+ [PutForwards=full] readonly attribute [Name] name;
+
+
+ PutForwards
+
+
+
+
+
+ attribute unsigned short age;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/reg-operations.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/reg-operations.widlprocxml
new file mode 100644
index 00000000000..3b756ed68d8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/reg-operations.widlprocxml
@@ -0,0 +1,70 @@
+
+
+
+ interface Dimensions {
+ attribute unsigned long width;
+ attribute unsigned long height;
+};
+
+exception NoPointerDevice { };
+
+interface Button {
+
+ boolean isMouseOver();
+
+ void setDimensions([Dimensions] size);
+ void setDimensions(unsigned long width, unsigned long height);
+};
+
+ interface Dimensions {
+ attribute unsigned long width;
+ attribute unsigned long height;
+};
+
+ attribute unsigned long width;
+
+
+
+ attribute unsigned long height;
+
+
+
+
+ exception NoPointerDevice { };
+
+
+ interface Button {
+
+ boolean isMouseOver();
+
+ void setDimensions([Dimensions] size);
+ void setDimensions(unsigned long width, unsigned long height);
+};
+
+ boolean isMouseOver();
+
+
+
+
+ void setDimensions([Dimensions] size);
+
+
+
+
+
+
+
+
+ void setDimensions(unsigned long width, unsigned long height);
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/replaceable.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/replaceable.widlprocxml
new file mode 100644
index 00000000000..f9762166825
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/replaceable.widlprocxml
@@ -0,0 +1,28 @@
+
+
+
+ interface Counter {
+ [Replaceable] readonly attribute unsigned long value;
+ void increment();
+};
+
+ interface Counter {
+ [Replaceable] readonly attribute unsigned long value;
+ void increment();
+};
+
+ [Replaceable] readonly attribute unsigned long value;
+
+
+ Replaceable
+
+
+
+
+
+ void increment();
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/sequence.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/sequence.widlprocxml
new file mode 100644
index 00000000000..d5f4564175b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/sequence.widlprocxml
@@ -0,0 +1,32 @@
+
+
+
+ interface Canvas {
+ void drawPolygon(sequence<float> coordinates);
+ sequence<float> getInflectionPoints();
+};
+
+ interface Canvas {
+ void drawPolygon(sequence<float> coordinates);
+ sequence<float> getInflectionPoints();
+};
+
+ void drawPolygon(sequence<float> coordinates);
+
+
+
+
+
+
+
+
+
+
+ sequence<float> getInflectionPoints();
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/serializer.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/serializer.widlprocxml
new file mode 100644
index 00000000000..eb4219f8a5e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/serializer.widlprocxml
@@ -0,0 +1,296 @@
+
+
+
+ interface Transaction {
+ readonly attribute [Account] from;
+ readonly attribute [Account] to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer;
+};
+
+interface Account {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer DOMString serialize();
+};
+
+interface Transaction2 {
+ readonly attribute [Account2] from;
+ readonly attribute [Account2] to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer = { from, to, amount, description };
+};
+
+interface Account2 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = number;
+};
+
+interface Account3 {
+ attribute DOMString name;
+ attribute unsigned long number;
+
+ serializer = { attribute };
+};
+
+interface Account4 {
+ getter object getItem(unsigned long index);
+ serializer = { getter };
+};
+
+interface Account5 : [Account] {
+ attribute DOMString secondname;
+ serializer = { inherit, secondname };
+};
+
+interface Account6 : [Account] {
+ attribute DOMString secondname;
+ serializer = { inherit, attribute };
+};
+
+interface Account7 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = [ name, number ];
+};
+
+interface Account8 {
+ getter object getItem(unsigned long index);
+ serializer = [ getter ];
+};
+
+ interface Transaction {
+ readonly attribute [Account] from;
+ readonly attribute [Account] to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer;
+};
+
+ readonly attribute [Account] from;
+
+
+
+ readonly attribute [Account] to;
+
+
+
+ readonly attribute float amount;
+
+
+
+ readonly attribute DOMString description;
+
+
+
+ readonly attribute unsigned long number;
+
+
+
+ serializer;
+
+
+
+ interface Account {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer DOMString serialize();
+};
+
+ attribute DOMString name;
+
+
+
+ attribute unsigned long number;
+
+
+
+ serializer DOMString serialize();
+
+
+
+
+
+ interface Transaction2 {
+ readonly attribute [Account2] from;
+ readonly attribute [Account2] to;
+ readonly attribute float amount;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long number;
+
+ serializer = { from, to, amount, description };
+};
+
+ readonly attribute [Account2] from;
+
+
+
+ readonly attribute [Account2] to;
+
+
+
+ readonly attribute float amount;
+
+
+
+ readonly attribute DOMString description;
+
+
+
+ readonly attribute unsigned long number;
+
+
+
+ serializer = { from, to, amount, description };
+
+
+
+
+
+
+
+
+
+ interface Account2 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = number;
+};
+
+ attribute DOMString name;
+
+
+
+ attribute unsigned long number;
+
+
+
+ serializer = number;
+
+
+
+ interface Account3 {
+ attribute DOMString name;
+ attribute unsigned long number;
+
+ serializer = { attribute };
+};
+
+ attribute DOMString name;
+
+
+
+ attribute unsigned long number;
+
+
+
+ serializer = { attribute };
+
+
+
+
+ interface Account4 {
+ getter object getItem(unsigned long index);
+ serializer = { getter };
+};
+
+ getter object getItem(unsigned long index);
+
+
+
+
+
+
+
+
+ serializer = { getter };
+
+
+
+
+ interface Account5 : [Account] {
+ attribute DOMString secondname;
+ serializer = { inherit, secondname };
+};
+
+
+
+
+ attribute DOMString secondname;
+
+
+
+ serializer = { inherit, secondname };
+
+
+
+
+
+
+ interface Account6 : [Account] {
+ attribute DOMString secondname;
+ serializer = { inherit, attribute };
+};
+
+
+
+
+ attribute DOMString secondname;
+
+
+
+ serializer = { inherit, attribute };
+
+
+
+
+ interface Account7 {
+ attribute DOMString name;
+ attribute unsigned long number;
+ serializer = [ name, number ];
+};
+
+ attribute DOMString name;
+
+
+
+ attribute unsigned long number;
+
+
+
+ serializer = [ name, number ];
+
+
+
+
+
+
+
+ interface Account8 {
+ getter object getItem(unsigned long index);
+ serializer = [ getter ];
+};
+
+ getter object getItem(unsigned long index);
+
+
+
+
+
+
+
+
+ serializer = [ getter ];
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/special-omittable.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/special-omittable.widlprocxml
new file mode 100644
index 00000000000..1986d190a80
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/special-omittable.widlprocxml
@@ -0,0 +1,37 @@
+
+
+
+
+ interface Dictionary {
+ readonly attribute unsigned long propertyCount;
+
+ omittable getter float getProperty(DOMString propertyName);
+ omittable setter void setProperty(DOMString propertyName, float propertyValue);
+};
+
+ readonly attribute unsigned long propertyCount;
+
+
+
+ omittable getter float getProperty(DOMString propertyName);
+
+
+
+
+
+
+
+
+ omittable setter void setProperty(DOMString propertyName, float propertyValue);
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/static.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/static.widlprocxml
new file mode 100644
index 00000000000..03c14e16eba
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/static.widlprocxml
@@ -0,0 +1,58 @@
+
+
+
+ interface Point { };
+
+interface Circle {
+ attribute float cx;
+ attribute float cy;
+ attribute float radius;
+
+ static readonly attribute long triangulationCount;
+ static [Point] triangulate([Circle] c1, [Circle] c2, [Circle] c3);
+};
+
+ interface Point { };
+
+
+ interface Circle {
+ attribute float cx;
+ attribute float cy;
+ attribute float radius;
+
+ static readonly attribute long triangulationCount;
+ static [Point] triangulate([Circle] c1, [Circle] c2, [Circle] c3);
+};
+
+ attribute float cx;
+
+
+
+ attribute float cy;
+
+
+
+ attribute float radius;
+
+
+
+ static readonly attribute long triangulationCount;
+
+
+
+ static [Point] triangulate([Circle] c1, [Circle] c2, [Circle] c3);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-attribute.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-attribute.widlprocxml
new file mode 100644
index 00000000000..082ce4d341b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-attribute.widlprocxml
@@ -0,0 +1,29 @@
+
+
+
+ [Constructor]
+interface Student {
+ attribute unsigned long id;
+ stringifier attribute DOMString name;
+};
+
+ [Constructor]
+interface Student {
+ attribute unsigned long id;
+ stringifier attribute DOMString name;
+};
+
+
+ Constructor
+
+
+
+ attribute unsigned long id;
+
+
+
+ stringifier attribute DOMString name;
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-custom.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-custom.widlprocxml
new file mode 100644
index 00000000000..cdab1ccfc37
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier-custom.widlprocxml
@@ -0,0 +1,44 @@
+
+
+
+ [Constructor]
+interface Student {
+ attribute unsigned long id;
+ attribute DOMString? familyName;
+ attribute DOMString givenName;
+
+ stringifier DOMString ();
+};
+
+ [Constructor]
+interface Student {
+ attribute unsigned long id;
+ attribute DOMString? familyName;
+ attribute DOMString givenName;
+
+ stringifier DOMString ();
+};
+
+
+ Constructor
+
+
+
+ attribute unsigned long id;
+
+
+
+ attribute DOMString? familyName;
+
+
+
+ attribute DOMString givenName;
+
+
+
+ stringifier DOMString ();
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier.widlprocxml
new file mode 100644
index 00000000000..4a18b80b704
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/stringifier.widlprocxml
@@ -0,0 +1,29 @@
+
+
+
+ interface A {
+ stringifier DOMString ();
+};
+
+interface A {
+ stringifier;
+};
+
+ interface A {
+ stringifier DOMString ();
+};
+
+ stringifier DOMString ();
+
+
+
+
+
+ interface A {
+ stringifier;
+};
+
+ stringifier;
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasnull.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasnull.widlprocxml
new file mode 100644
index 00000000000..a57ae163f0b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasnull.widlprocxml
@@ -0,0 +1,40 @@
+
+
+
+ interface Dog {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatNullAs=EmptyString] DOMString breedName);
+};
+
+ interface Dog {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatNullAs=EmptyString] DOMString breedName);
+};
+
+ attribute DOMString name;
+
+
+
+ attribute DOMString owner;
+
+
+
+ boolean isMemberOfBreed([TreatNullAs=EmptyString] DOMString breedName);
+
+
+
+
+
+ TreatNullAs
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasundefined.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasundefined.widlprocxml
new file mode 100644
index 00000000000..17e71081da0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/treatasundefined.widlprocxml
@@ -0,0 +1,40 @@
+
+
+
+ interface Cat {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatUndefinedAs=EmptyString] DOMString breedName);
+};
+
+ interface Cat {
+ attribute DOMString name;
+ attribute DOMString owner;
+
+ boolean isMemberOfBreed([TreatUndefinedAs=EmptyString] DOMString breedName);
+};
+
+ attribute DOMString name;
+
+
+
+ attribute DOMString owner;
+
+
+
+ boolean isMemberOfBreed([TreatUndefinedAs=EmptyString] DOMString breedName);
+
+
+
+
+
+ TreatUndefinedAs
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/typedef.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/typedef.widlprocxml
new file mode 100644
index 00000000000..785f6706e6d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/typedef.widlprocxml
@@ -0,0 +1,100 @@
+
+
+
+ interface Point {
+ attribute float x;
+ attribute float y;
+ };
+
+ typedef sequence<[Point]> PointSequence;
+
+ interface Rect {
+ attribute [Point] topleft;
+ attribute [Point] bottomright;
+ };
+
+ interface Widget {
+
+ readonly attribute [Rect] bounds;
+
+ boolean pointWithinBounds([Point] p);
+ boolean allPointsWithinBounds([PointSequence] ps);
+ };
+
+ typedef [Clamp] octet value;
+
+ interface Point {
+ attribute float x;
+ attribute float y;
+ };
+
+ attribute float x;
+
+
+
+ attribute float y;
+
+
+
+
+ typedef sequence<[Point]> PointSequence;
+
+
+
+
+
+ interface Rect {
+ attribute [Point] topleft;
+ attribute [Point] bottomright;
+ };
+
+ attribute [Point] topleft;
+
+
+
+ attribute [Point] bottomright;
+
+
+
+
+ interface Widget {
+
+ readonly attribute [Rect] bounds;
+
+ boolean pointWithinBounds([Point] p);
+ boolean allPointsWithinBounds([PointSequence] ps);
+ };
+
+ readonly attribute [Rect] bounds;
+
+
+
+ boolean pointWithinBounds([Point] p);
+
+
+
+
+
+
+
+
+ boolean allPointsWithinBounds([PointSequence] ps);
+
+
+
+
+
+
+
+
+
+ typedef [Clamp] octet value;
+
+
+
+ Clamp
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/typesuffixes.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/typesuffixes.widlprocxml
new file mode 100644
index 00000000000..830fe62bc0d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/typesuffixes.widlprocxml
@@ -0,0 +1,25 @@
+
+
+
+ interface Suffixes {
+ void test(sequence<DOMString[]?>? foo);
+};
+
+ interface Suffixes {
+ void test(sequence<DOMString[]?>? foo);
+};
+
+ void test(sequence<DOMString[]?>? foo);
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/uniontype.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/uniontype.widlprocxml
new file mode 100644
index 00000000000..7d088079956
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/uniontype.widlprocxml
@@ -0,0 +1,26 @@
+
+
+
+ interface Union {
+ attribute (float or (Date or [Event]) or ([Node] or DOMString)?) test;
+};
+
+ interface Union {
+ attribute (float or (Date or [Event]) or ([Node] or DOMString)?) test;
+};
+
+ attribute (float or (Date or [Event]) or ([Node] or DOMString)?) test;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/WebIDL/valid/xml/variadic-operations.widlprocxml b/tests/wpt/web-platform-tests/WebIDL/valid/xml/variadic-operations.widlprocxml
new file mode 100644
index 00000000000..0bc9f784413
--- /dev/null
+++ b/tests/wpt/web-platform-tests/WebIDL/valid/xml/variadic-operations.widlprocxml
@@ -0,0 +1,40 @@
+
+
+
+ interface IntegerSet {
+ readonly attribute unsigned long cardinality;
+
+ void union(long... ints);
+ void intersection(long... ints);
+};
+
+ interface IntegerSet {
+ readonly attribute unsigned long cardinality;
+
+ void union(long... ints);
+ void intersection(long... ints);
+};
+
+ readonly attribute unsigned long cardinality;
+
+
+
+ void union(long... ints);
+
+
+
+
+
+
+
+
+ void intersection(long... ints);
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/FormData-append.html b/tests/wpt/web-platform-tests/XMLHttpRequest/FormData-append.html
new file mode 100644
index 00000000000..f20009e2a81
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/FormData-append.html
@@ -0,0 +1,28 @@
+
+
+FormData.append
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.html b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.html
new file mode 100644
index 00000000000..c6b937bfce6
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.html
@@ -0,0 +1,14 @@
+
+
+XMLHttpRequest#withCredentials
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.js b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.js
new file mode 100644
index 00000000000..a2834ccce25
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.js
@@ -0,0 +1,43 @@
+function test_withCredentials(worker) {
+ test(function() {
+ var client = new XMLHttpRequest()
+ assert_false(client.withCredentials, "withCredentials defaults to false")
+ client.withCredentials = true
+ assert_true(client.withCredentials, "is true after setting")
+ }, "default value is false, set value is true")
+
+ test(function() {
+ var client = new XMLHttpRequest()
+ client.open("GET", "resources/delay.py?ms=1000", true)
+ client.withCredentials = true
+ assert_true(client.withCredentials, "set in OPEN state")
+ }, "can also be set in OPEN state")
+
+ test(function() {
+ var client = new XMLHttpRequest()
+ client.open("GET", "resources/delay.py?ms=1000", false)
+ if (worker) {
+ client.withCredentials = true
+ assert_true(client.withCredentials, "set in OPEN state")
+ } else {
+ assert_throws("InvalidAccessError", function() {
+ client.withCredentials = true
+ })
+ assert_false(client.withCredentials, "set in OPEN state")
+ }
+ }, "setting on synchronous XHR")
+
+ async_test("setting withCredentials when not in UNSENT, OPENED state").step(function() {
+ this.add_cleanup(done)
+ var client = new XMLHttpRequest()
+ client.open("GET", "resources/delay.py?ms=1000")
+ client.send()
+ assert_throws("InvalidStateError", function() { client.withCredentials = true })
+ client.onreadystatechange = this.step_func(function() {
+ assert_throws("InvalidStateError", function() { client.withCredentials = true })
+ if (client.readyState === 4) {
+ this.done()
+ }
+ })
+ })
+}
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.worker.js b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.worker.js
new file mode 100644
index 00000000000..dea0da24021
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/XMLHttpRequest-withCredentials.worker.js
@@ -0,0 +1,3 @@
+importScripts("/resources/testharness.js")
+importScripts("XMLHttpRequest-withCredentials.js")
+test_withCredentials(true);
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-receive.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-receive.htm
new file mode 100644
index 00000000000..bd97b68358d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-receive.htm
@@ -0,0 +1,42 @@
+
+
+
+ XMLHttpRequest: abort() after successful receive should not fire "abort" event
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-send.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-send.htm
new file mode 100644
index 00000000000..c4885c9911b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-send.htm
@@ -0,0 +1,55 @@
+
+
+
+ XMLHttpRequest: abort() after send()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-stop.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-stop.htm
new file mode 100644
index 00000000000..87e9ebcd853
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-stop.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: abort event should fire when stop() method is used
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-timeout.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-timeout.htm
new file mode 100644
index 00000000000..e8e84b1a35d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-after-timeout.htm
@@ -0,0 +1,58 @@
+
+
+
+ XMLHttpRequest: abort() after a timeout should not fire "abort" event
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-done.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-done.htm
new file mode 100644
index 00000000000..a8b604fe3f7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-done.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: abort() during DONE
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-open.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-open.htm
new file mode 100644
index 00000000000..60a6eeecd83
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-open.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: abort() during OPEN
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-unsent.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-unsent.htm
new file mode 100644
index 00000000000..bc2f5cab535
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-unsent.htm
@@ -0,0 +1,26 @@
+
+
+
+ XMLHttpRequest: abort() during UNSENT
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-upload.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-upload.htm
new file mode 100644
index 00000000000..afb28284645
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-during-upload.htm
@@ -0,0 +1,42 @@
+
+
+
+ XMLHttpRequest: abort() while sending data
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-abort.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-abort.htm
new file mode 100644
index 00000000000..2382241cad3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-abort.htm
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ XMLHttpRequest: The abort() method: do not fire abort event in OPENED state when send() flag is unset. send() throws after abort().
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-listeners.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-listeners.htm
new file mode 100644
index 00000000000..1c50ed394dc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-listeners.htm
@@ -0,0 +1,25 @@
+
+
+
+ XMLHttpRequest: abort() should not reset event listeners
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-loadend.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-loadend.htm
new file mode 100644
index 00000000000..8b8dfdaa422
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-loadend.htm
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ XMLHttpRequest: The abort() method: Fire a progress event named loadend
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-order.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-order.htm
new file mode 100644
index 00000000000..b349a27d26a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-event-order.htm
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+ XMLHttpRequest: The abort() method: abort and loadend events
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-abort.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-abort.htm
new file mode 100644
index 00000000000..1d045448b5f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-abort.htm
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ XMLHttpRequest: The abort() method: Fire a progress event named abort on the XMLHttpRequestUpload object
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-loadend.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-loadend.htm
new file mode 100644
index 00000000000..5b10b6530fd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/abort-upload-event-loadend.htm
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ XMLHttpRequest: The abort() method: Fire a progress event named loadend on the XMLHttpRequestUpload object
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/anonymous-mode-unsupported.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/anonymous-mode-unsupported.htm
new file mode 100644
index 00000000000..9cacf61b7d2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/anonymous-mode-unsupported.htm
@@ -0,0 +1,40 @@
+
+
+
+ XMLHttpRequest: anonymous mode unsupported
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/data-uri.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/data-uri.htm
new file mode 100644
index 00000000000..f3edd3b6d04
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/data-uri.htm
@@ -0,0 +1,53 @@
+
+
+XMLHttpRequest: data uri
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-abort.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-abort.htm
new file mode 100644
index 00000000000..ce8d937d7fa
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-abort.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: abort event
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-load.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-load.htm
new file mode 100644
index 00000000000..9098eebc743
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-load.htm
@@ -0,0 +1,32 @@
+
+
+XMLHttpRequest: The send() method: Fire an event named load (synchronous flag is unset)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadend.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadend.htm
new file mode 100644
index 00000000000..b0c62131725
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadend.htm
@@ -0,0 +1,35 @@
+
+
+
+ XMLHttpRequest: loadend event
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadstart.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadstart.htm
new file mode 100644
index 00000000000..5149003034d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-loadstart.htm
@@ -0,0 +1,31 @@
+
+
+
+ XMLHttpRequest: loadstart event
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-progress.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-progress.htm
new file mode 100644
index 00000000000..31b35b77217
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-progress.htm
@@ -0,0 +1,29 @@
+
+
+
+XMLHttpRequest: The send() method: Fire a progress event named progress (synchronous flag is unset)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-readystatechange-loaded.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-readystatechange-loaded.htm
new file mode 100644
index 00000000000..4368f8c9a5d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-readystatechange-loaded.htm
@@ -0,0 +1,38 @@
+
+
+
+
+ XMLHttpRequest: the LOADING state change should only happen once
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-timeout.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-timeout.htm
new file mode 100644
index 00000000000..3368efc4b9d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-timeout.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: timeout event
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress-crossorigin.sub.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress-crossorigin.sub.htm
new file mode 100644
index 00000000000..6130bba50a2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress-crossorigin.sub.htm
@@ -0,0 +1,26 @@
+
+
+
+XMLHttpRequest: upload progress event for cross-origin requests
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress.htm
new file mode 100644
index 00000000000..98c76cc3fc3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/event-upload-progress.htm
@@ -0,0 +1,26 @@
+
+
+
+XMLHttpRequest: upload progress event
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/folder.txt b/tests/wpt/web-platform-tests/XMLHttpRequest/folder.txt
new file mode 100644
index 00000000000..bf1a1fdefa3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/folder.txt
@@ -0,0 +1 @@
+top
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/formdata-blob.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/formdata-blob.htm
new file mode 100644
index 00000000000..5efef7b615b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/formdata-blob.htm
@@ -0,0 +1,46 @@
+
+
+
+XMLHttpRequest: upload formdata with blob
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/formdata.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/formdata.htm
new file mode 100644
index 00000000000..e0d0a4e1d4b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/formdata.htm
@@ -0,0 +1,43 @@
+
+
+
+XMLHttpRequest: upload formdata
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-cookies.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-cookies.htm
new file mode 100644
index 00000000000..2cd80981859
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-cookies.htm
@@ -0,0 +1,38 @@
+
+
+
+ XMLHttpRequest: getAllResponseHeaders() excludes cookies
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-status.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-status.htm
new file mode 100644
index 00000000000..b4afc61c469
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getallresponseheaders-status.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: getAllResponseHeaders() excludes status
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-case-insensitive.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-case-insensitive.htm
new file mode 100644
index 00000000000..8e0537edf17
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-case-insensitive.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() case-insensitive matching
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm
new file mode 100644
index 00000000000..3cbdb9c068c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-chunked-trailer.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() and HTTP trailer
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-cookies-and-more.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-cookies-and-more.htm
new file mode 100644
index 00000000000..053fe441faf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-cookies-and-more.htm
@@ -0,0 +1,36 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() custom/non-existent headers and cookies
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-error-state.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-error-state.htm
new file mode 100644
index 00000000000..c9695fdee0f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-error-state.htm
@@ -0,0 +1,36 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() in error state (failing cross-origin test)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-server-date.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-server-date.htm
new file mode 100644
index 00000000000..409bc350390
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-server-date.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() server and date
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-special-characters.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-special-characters.htm
new file mode 100644
index 00000000000..980f8481c7e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-special-characters.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() funny characters
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-unsent-opened-state.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-unsent-opened-state.htm
new file mode 100644
index 00000000000..e3bc2720f12
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/getresponseheader-unsent-opened-state.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: getResponseHeader() in unsent, opened states
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/interfaces.html b/tests/wpt/web-platform-tests/XMLHttpRequest/interfaces.html
new file mode 100644
index 00000000000..96de3c00f94
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/interfaces.html
@@ -0,0 +1,171 @@
+
+
+XMLHttpRequest IDL tests
+
+
+
+
+
+XMLHttpRequest IDL tests
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-abort.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-abort.htm
new file mode 100644
index 00000000000..ca8a4e1e62f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-abort.htm
@@ -0,0 +1,35 @@
+
+
+
+ XMLHttpRequest: open() after abort()
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-setrequestheader.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-setrequestheader.htm
new file mode 100644
index 00000000000..525edbfc1ab
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-after-setrequestheader.htm
@@ -0,0 +1,33 @@
+
+
+
+ XMLHttpRequest: open() after setRequestHeader()
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-during-abort.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-during-abort.htm
new file mode 100755
index 00000000000..1d01415d55b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-during-abort.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: open() during abort()
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-bogus.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-bogus.htm
new file mode 100644
index 00000000000..263e7b6db7e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-bogus.htm
@@ -0,0 +1,28 @@
+
+
+
+ XMLHttpRequest: open() - bogus methods
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-insensitive.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-insensitive.htm
new file mode 100644
index 00000000000..103381745a7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-insensitive.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: open() - case-insensitive methods test
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-sensitive.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-sensitive.htm
new file mode 100644
index 00000000000..270e32d67a3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-case-sensitive.htm
@@ -0,0 +1,31 @@
+
+
+
+ XMLHttpRequest: open() - case-sensitive methods test
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-insecure.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-insecure.htm
new file mode 100644
index 00000000000..1a77ff3ec79
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-insecure.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: open() - "insecure" methods
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-responsetype-set-sync.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-responsetype-set-sync.htm
new file mode 100644
index 00000000000..543a1390cdd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-method-responsetype-set-sync.htm
@@ -0,0 +1,29 @@
+
+
+
+ XMLHttpRequest: open() sync request not allowed if responseType is set
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-send.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-send.htm
new file mode 100644
index 00000000000..ebc1801ab53
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-send.htm
@@ -0,0 +1,33 @@
+
+
+
+ XMLHttpRequest: open() - open() - send()
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-sync-send.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-sync-send.htm
new file mode 100644
index 00000000000..b0badfd8aa0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-open-sync-send.htm
@@ -0,0 +1,31 @@
+
+
+
+ XMLHttpRequest: open() - open() (sync) - send()
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-referer.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-referer.htm
new file mode 100644
index 00000000000..4ffdfe0c5d5
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-referer.htm
@@ -0,0 +1,20 @@
+
+
+
+ XMLHttpRequest: open() - value of Referer header
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-send-open.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-send-open.htm
new file mode 100644
index 00000000000..d57592c0ba3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-send-open.htm
@@ -0,0 +1,33 @@
+
+
+
+ XMLHttpRequest: open() - send() - open()
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-sync-open-send.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-sync-open-send.htm
new file mode 100644
index 00000000000..cc81c522394
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-sync-open-send.htm
@@ -0,0 +1,41 @@
+
+
+
+ XMLHttpRequest: open() (sync) - send() - open()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-about-blank-window.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-about-blank-window.htm
new file mode 100644
index 00000000000..5be3b77ddfe
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-about-blank-window.htm
@@ -0,0 +1,23 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (about:blank iframe)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted-after-open.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted-after-open.htm
new file mode 100644
index 00000000000..a4d641fafcf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted-after-open.htm
@@ -0,0 +1,24 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs - insert <base> after open()
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted.htm
new file mode 100644
index 00000000000..69ad6193d8e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base-inserted.htm
@@ -0,0 +1,24 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs - insert <base>
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base.htm
new file mode 100644
index 00000000000..3c0e8c99d51
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-base.htm
@@ -0,0 +1,22 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs - <base>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-bogus.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-bogus.htm
new file mode 100644
index 00000000000..a4e296d5709
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-bogus.htm
@@ -0,0 +1,22 @@
+
+
+
+ XMLHttpRequest: open() - bogus URLs
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-encoding.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-encoding.htm
new file mode 100644
index 00000000000..a545d41b2a9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-encoding.htm
@@ -0,0 +1,21 @@
+
+
+
+
+ XMLHttpRequest: open() - URL encoding
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-fragment.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-fragment.htm
new file mode 100644
index 00000000000..6b3fdeb8ae8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-fragment.htm
@@ -0,0 +1,38 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs - fragment identifier
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window-2.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window-2.htm
new file mode 100644
index 00000000000..f5ddd424976
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window-2.htm
@@ -0,0 +1,19 @@
+
+
+
+ XMLHttpRequest: open() - resolving URLs (javascript: <iframe>; 2)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window.htm
new file mode 100644
index 00000000000..cd208d51ad3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-javascript-window.htm
@@ -0,0 +1,28 @@
+
+
+
+ XMLHttpRequest: open() - resolving URLs (javascript: <iframe>; 1)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-2.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-2.htm
new file mode 100644
index 00000000000..398764e7050
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-2.htm
@@ -0,0 +1,24 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (multi-Window; 2; evil)
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-3.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-3.htm
new file mode 100644
index 00000000000..b3652dfa508
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-3.htm
@@ -0,0 +1,24 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (multi-Window; 3; evil)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-4.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-4.htm
new file mode 100644
index 00000000000..9ddbb9b4772
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-4.htm
@@ -0,0 +1,50 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (multi-Window; 4; evil)
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-5.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-5.htm
new file mode 100644
index 00000000000..a27d2b366c0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window-5.htm
@@ -0,0 +1,30 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (multi-Window; 5)
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window.htm
new file mode 100644
index 00000000000..b84aaa57fed
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-multi-window.htm
@@ -0,0 +1,30 @@
+
+
+
+ XMLHttpRequest: open() resolving URLs (multi-Window; 1)
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-origin.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-origin.htm
new file mode 100644
index 00000000000..bad2ec4d6c4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-origin.htm
@@ -0,0 +1,44 @@
+
+
+
+
+ XMLHttpRequest: worker scripts, origin and referrer
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-simple.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-simple.htm
new file mode 100644
index 00000000000..f0613c1a2d7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-url-worker-simple.htm
@@ -0,0 +1,26 @@
+
+
+
+
+ XMLHttpRequest: relative URLs in worker scripts resolved by script URL
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/open-user-password-non-same-origin.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/open-user-password-non-same-origin.htm
new file mode 100644
index 00000000000..e49888cd493
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/open-user-password-non-same-origin.htm
@@ -0,0 +1,25 @@
+
+
+
+ XMLHttpRequest: open() - user/pass argument and non same-origin URL doesn't throw
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-done-state.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-done-state.htm
new file mode 100644
index 00000000000..a1711e6096f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-done-state.htm
@@ -0,0 +1,26 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in DONE state
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis.htm
new file mode 100644
index 00000000000..578e28cb227
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in HEADERS RECEIVED state, enforcing Shift-JIS encoding
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-invalid-mime-type.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-invalid-mime-type.htm
new file mode 100644
index 00000000000..9cfd801e05b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-invalid-mime-type.htm
@@ -0,0 +1,25 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in unsent state, invalid MIME types
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-loading-state.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-loading-state.htm
new file mode 100644
index 00000000000..cce3fa49ef7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-loading-state.htm
@@ -0,0 +1,32 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in LOADING state
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-utf-8.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-utf-8.htm
new file mode 100644
index 00000000000..5a261005d97
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-utf-8.htm
@@ -0,0 +1,27 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in open state, enforcing UTF-8 encoding
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-xml.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-xml.htm
new file mode 100644
index 00000000000..fd0664a7cce
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-open-state-force-xml.htm
@@ -0,0 +1,34 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in open state, XML MIME type with UTF-8 charset
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-unsent-state-force-shiftjis.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-unsent-state-force-shiftjis.htm
new file mode 100644
index 00000000000..98dfe1436d9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/overridemimetype-unsent-state-force-shiftjis.htm
@@ -0,0 +1,27 @@
+
+
+
+ XMLHttpRequest: overrideMimeType() in unsent state, enforcing Shift-JIS encoding
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/progress-events-response-data-gzip.htm b/tests/wpt/web-platform-tests/XMLHttpRequest/progress-events-response-data-gzip.htm
new file mode 100644
index 00000000000..dc166a2396a
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/progress-events-response-data-gzip.htm
@@ -0,0 +1,77 @@
+
+
+
+ XMLHttpRequest: progress events and GZIP encoding
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/readme.txt b/tests/wpt/web-platform-tests/XMLHttpRequest/readme.txt
new file mode 100644
index 00000000000..2e5f64cd518
--- /dev/null
+++ b/tests/wpt/web-platform-tests/XMLHttpRequest/readme.txt
@@ -0,0 +1,31 @@
+Currently this testsuite tries to provide tests for XMLHttpRequest level 1.
+This test suite is not stable and is still under development. Tests may
+contain bugs and may change over time as a result of those bugs being fixed.
+
+When more browsers implement XMLHttpRequest level 2 this testsuite will
+slowly evolve most likely.
+
+ http://dev.w3.org/2006/webapi/XMLHttpRequest/
+ http://dev.w3.org/2006/webapi/XMLHttpRequest-2/
+
+If the folders above give the status of the feature tested you can assume
+this is against level 1 unless explicitly stated otherwise.
+
+NOTE: readyState and onreadystatechange are tested throughout the various
+tests. statusText is tested together with status.
+
+NOTE: open-url-base* have absolute paths in them. They need to be adjusted
+on a per location basis.
+
+NOTE: open-url-base-inserted-after-open.htm, open-url-base-inserted.htm,
+send-authentication.htm and open-url-base.htm refer to localhost.
+
+
+TESTS THAT ARE UNSTABLE AND (PROBABLY) NEED CHANGES
+ responsexml-basic (see email WHATWG)
+ send-authentication (see "user:password" debacle)
+
+
+TESTS NOT STARTED ON YET
+
+