summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/tools/w3ctestlib
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/tools/w3ctestlib')
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/Groups.py201
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/HTMLSerializer.py277
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/Indexer.py250
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/OutputFormats.py207
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/Sources.py1473
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/Suite.py121
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/Utils.py161
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/__init__.py3
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/catalog.xml27
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-lat1.ent196
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-special.ent80
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-symbol.ent237
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-frameset.dtd1235
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-strict.dtd978
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-transitional.dtd1201
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml11.dtd294
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/chapter-toc.tmpl46
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/implementation-report-TEMPLATE.data.tmpl21
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/index.content.tmpl195
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/index.htm.tmpl20
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/index.xht.tmpl20
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/indices.css96
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest-toc.tmpl74
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest.tmpl7
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/suitedata.tmpl23
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/test-toc.tmpl97
-rw-r--r--testing/web-platform/tests/css/tools/w3ctestlib/templates/testinfo.data.tmpl16
27 files changed, 7556 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/Groups.py b/testing/web-platform/tests/css/tools/w3ctestlib/Groups.py
new file mode 100644
index 0000000000..192ae9b6fd
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/Groups.py
@@ -0,0 +1,201 @@
+#!/usr/bin/python
+# CSS Test Suite Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+import shutil
+import filecmp
+import os.path
+import Utils
+from os.path import exists, join
+from Sources import SourceCache, SourceSet, ConfigSource, ReftestManifest
+from Utils import listfiles
+
+excludeDirs = ['CVS', '.svn', '.hg']
+
+class TestGroup:
+ """Base class for test groups. Should never be used directly.
+ """
+
+ @staticmethod
+ def combine(groupA, groupB):
+ """Merge TestGroup `groupB` into `groupA`. Return the result of the merge.
+ Can accept none as arguments.
+ """
+ if groupA and groupB:
+ groupA.merge(groupB)
+ return groupA or groupB
+
+ def __init__(self, sourceCache, importDir, name=None, title=None, ui = None, **kwargs):
+ """Initialize with:
+ SourceCache `sourceCache`
+ Group name `name`, which must be a possible directory name or None
+ Directory path `importDir`, whose context is imported into the group
+ Option: Tuple of support directory names `supportDirNames` defaults
+ to ('support',).
+ Kwarg: File path manifestPath relative to `importDir` that
+ identifies the reftest manifest file (usually called 'reftest.list').
+ Kwarg: File path manifestDest as destination (relative) path for
+ the reftest manifest file. Defaults to value of manifestPath.
+ If manifest provided, assumes that only the files listed in the manifest,
+ the .htaccess files in its parent directory, and the `importDir`'s
+ .htaccess file and support directory are relevant to the test suite.
+ """
+ assert exists(importDir), "Directory to import %s does not exist" % importDir
+
+ # Save name
+ self.name = name
+ self.title = title
+
+ self.ui = ui
+
+ sourceTree = sourceCache.sourceTree
+
+ # Load htaccess
+ htapath = join(importDir, '.htaccess')
+ self.htaccess = ConfigSource(sourceTree, htapath, '.htaccess') \
+ if exists(htapath) else None
+
+ # Load support files
+ self.support = SourceSet(sourceCache)
+ supportDirNames = kwargs.get('supportDirNames', ('support',))
+ for supportName in supportDirNames:
+ supportDir = join(importDir, supportName)
+ if exists(supportDir):
+ for (root, dirs, files) in os.walk(supportDir):
+ for dir in excludeDirs:
+ if dir in dirs:
+ dirs.remove(dir)
+ for name in files:
+ sourcepath = join(root, name)
+ relpath = Utils.relpath(sourcepath, importDir)
+ self.support.add(sourcepath, relpath, self.ui)
+
+ # Load tests
+ self.tests = SourceSet(sourceCache)
+ self.refs = SourceSet(sourceCache)
+
+ # Read manifest
+ manifestPath = kwargs.get('manifestPath', None)
+ manifestDest = kwargs.get('manifestDest', manifestPath)
+ if (manifestPath):
+ self.manifest = ReftestManifest(join(importDir, manifestPath), manifestDest)
+
+ # Import tests
+ for (testSrc, refSrc), (testRel, refRel), refType in self.manifest:
+ test = sourceCache.generateSource(testSrc, testRel)
+ ref = sourceCache.generateSource(refSrc, refRel)
+ test.addReference(ref, refType)
+ self.tests.addSource(test, self.ui)
+ else:
+ self.manifest = None
+ # Import tests
+ fileNameList = []
+ if kwargs.get('selfTestExt'):
+ fileNameList += listfiles(importDir, kwargs['selfTestExt'])
+ if kwargs.get('selfTestList'):
+ fileNameList += kwargs['selfTestList']
+ for fileName in fileNameList:
+ filePath = join(importDir, fileName)
+ if sourceTree.isTestCase(filePath):
+ test = sourceCache.generateSource(filePath, fileName)
+ if (test.isTest()):
+ self.tests.addSource(test, self.ui)
+
+ for test in self.tests.iter():
+ if (test.isReftest()):
+ usedRefs = {}
+ usedRefs[test.sourcepath] = '=='
+ def loadReferences(source): # XXX need to verify refType for mutual exclusion (ie: a == b != a)
+ for refSrcPath, refRelPath, refType in source.getReferencePaths():
+ if (exists(refSrcPath)):
+ ref = sourceCache.generateSource(refSrcPath, refRelPath)
+ source.addReference(ref)
+ if (refSrcPath not in usedRefs):
+ usedRefs[refSrcPath] = refType
+ if (ref not in self.tests):
+ self.refs.addSource(ref, self.ui)
+ loadReferences(ref)
+ else:
+ ui.warn("Missing Reference file: ", refSrcPath, "\n referenced from: ", source.sourcepath, "\n")
+ loadReferences(test)
+
+
+ def sourceCache(self):
+ return self.support.sourceCache
+
+ def count(self):
+ """Returns number of tests.
+ """
+ return len(self.tests)
+
+ def iterTests(self):
+ return self.tests.iter()
+
+ def _initFrom(self, group=None):
+ """Initialize with data from TestGroup `group`."""
+ # copy
+ self.name = group.name if group else None
+ self.title = group.title if group else None
+ self.htaccess = group.htaccess if group else None
+ self.support = group.support if group else None
+ self.tests = group.tests if group else None
+
+ def merge(self, other):
+ """Merge Group `other`'s contents into this Group and clear its contents.
+ """
+ assert isinstance(other, TestGroup), \
+ "Expected Group instance, got %s" % type(other)
+ if self.htaccess and other.htaccess:
+ self.htaccess.append(other.htaccess)
+ else:
+ self.htaccess = self.htaccess or other.htaccess
+ other.htaccess = None
+
+ self.support = SourceSet.combine(self.support, other.support, self.ui)
+ other.support = None
+
+ self.tests = SourceSet.combine(self.tests, other.tests, self.ui)
+ other.tests = None
+
+ self.refs = SourceSet.combine(self.refs, other.refs, self.ui)
+ other.refs = None
+ if self.manifest and other.manifest:
+ self.manifest.append(other.manifest)
+ else:
+ self.manifest = self.manifest or other.manifest
+ other.manifest = None
+
+
+ def build(self, format):
+ """Build Group's contents through OutputFormat `format`.
+ """
+ format.setSubDir(self.name)
+
+ # Write .htaccess
+ if self.htaccess:
+ format.write(self.htaccess)
+
+ # Write support files
+ format.convert = False # XXX hack turn off format conversion
+ self.support.write(format)
+ format.convert = True # XXX undo hack
+
+ # Write tests
+ self.tests.adjustContentPaths(format)
+ self.tests.write(format)
+
+ # Write refs
+ self.refs.write(format)
+ if self.manifest:
+ format.write(self.manifest)
+
+ # copy support files to reference directory (XXX temp until proper support path fixup)
+ formatDir = format.destDir()
+ supportDir = join(formatDir, 'support')
+ referenceDir = join(formatDir, 'reference')
+ if exists(supportDir) and exists(referenceDir):
+ shutil.copytree(supportDir, join(referenceDir, 'support'))
+
+ format.setSubDir()
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/HTMLSerializer.py b/testing/web-platform/tests/css/tools/w3ctestlib/HTMLSerializer.py
new file mode 100644
index 0000000000..7f73bc17ec
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/HTMLSerializer.py
@@ -0,0 +1,277 @@
+#!/usr/bin/python
+# CSS Test Source Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# additions by peter.linss@hp.com copyright 2013 Hewlett-Packard
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+import lxml
+from lxml import etree
+import htmlentitydefs
+import copy
+
+
+class HTMLSerializer(object):
+
+ gXMLns = 'http://www.w3.org/XML/1998/namespace'
+ gHTMLns = 'http://www.w3.org/1999/xhtml'
+
+ gDefaultNamespaces = {'http://www.w3.org/XML/1998/namespace': 'xmlns',
+ 'http://www.w3.org/2000/xmlns/': 'xmlns',
+ 'http://www.w3.org/1999/xlink': 'xlink'}
+
+ gVoidElements = frozenset((
+ 'base',
+ 'command',
+ 'event-source',
+ 'link',
+ 'meta',
+ 'hr',
+ 'br',
+ 'img',
+ 'embed',
+ 'param',
+ 'area',
+ 'col',
+ 'input',
+ 'source'
+ ))
+
+ gCDataElements = frozenset((
+ 'style',
+ 'script'
+ ))
+
+ gInvisibleChars = frozenset(
+ # ASCII control chars
+ range(0x0, 0x9) + range(0xB, 0xD) + range(0xE, 0x20) +
+ # Other control chars
+ # fixed-width spaces, zero-width marks, bidi marks
+ range(0x2000, 0x2010) +
+ # LS, PS, bidi control codes
+ range(0x2028, 0x2030) +
+ # nbsp, mathsp, ideosp, WJ, interlinear
+ [0x00A0, 0x205F, 0x3000, 0x2060, 0xFFF9, 0xFFFA, 0xFFFB]
+ )
+
+ gXMLEscapes = frozenset(gInvisibleChars |
+ frozenset((ord('&'), ord('<'), ord('>'))))
+
+ gXMLEntityNames = {'"': 'quot', '&': 'amp', "'": 'apos', '<': 'lt', '>': 'gt'}
+
+ gDocTypes = {
+ 'html': '<!DOCTYPE html>',
+ 'html4':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
+ 'html4-transitional':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+ 'html4-frameset':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
+ 'svg11':
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
+ 'svg11-tiny':
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
+ 'xhtml10':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+ 'xhtml10-transitional':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+ 'xhtml10-frameset':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+ 'xhtml11':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+ 'xhtml-basic11':
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
+ }
+
+
+ def __init__(self):
+ self._reset()
+
+ def _reset(self, xhtml = False):
+ self.mOutput = u''
+ self.mXHTML = xhtml
+
+ def _output(self, *args):
+ for arg in args:
+ self.mOutput += unicode(arg)
+
+ def _escape(self, text, escapeChars):
+ # This algorithm is O(MN) for M len(text) and N num escapable
+ # But it doesn't modify the text when N is zero (common case) and
+ # N is expected to be small (usually 1 or 2) in most other cases.
+ escapable = set()
+ for char in text:
+ if ord(char) in escapeChars:
+ escapable.add(char)
+ for char in escapable:
+ if (self.mXHTML):
+ name = self.gXMLEntityNames.get(char)
+ else:
+ name = htmlentitydefs.codepoint2name.get(ord(char))
+ escape = u'&%s;' % name if name else u'&#x%X;' % ord(char)
+ text = text.replace(char, escape)
+ return text
+
+ def _escapeXML(self, text):
+ return self._escape(text, self.gXMLEscapes)
+
+ def _escapeInvisible(self, text):
+ return self._escape(text, self.gInvisibleChars)
+
+ def _serializeElement(self, element, namespacePrefixes):
+ qName = etree.QName(element)
+ attrs = element.attrib.items() # in tree order
+
+ if (not namespacePrefixes):
+ namespacePrefixes = self.gDefaultNamespaces
+
+ if (self.mXHTML):
+ namespacePrefixes = copy.copy(namespacePrefixes)
+ for attr, value in attrs:
+ attrQName = etree.QName(attr)
+ if (self.gXMLns == attrQName.namespace):
+ namespacePrefixes[value] = attrQName.localname
+ elif ('xmlns' == attrQName.localname):
+ namespacePrefixes[value] = ''
+
+ if (self.mXHTML and qName.namespace and namespacePrefixes[qName.namespace]):
+ self._output('<', namespacePrefixes[qName.namespace], ':', qName.localname)
+ else:
+ self._output('<', qName.localname)
+
+ for attr, value in attrs:
+ attrQName = etree.QName(attr)
+ if ((attrQName.namespace == self.gXMLns) and ('lang' == attrQName.localname)):
+ if (self.mXHTML):
+ attr = 'xml:lang'
+ else:
+ attr = 'lang'
+ elif (attrQName.namespace and namespacePrefixes[attrQName.namespace]):
+ attr = namespacePrefixes[attrQName.namespace] + ':' + attrQName.localname
+ else:
+ attr = attrQName.localname
+
+ self._output(' ', attr, '=')
+ value = value.replace('&', '&amp;')
+ if (self.mXHTML):
+ value = value.replace('<', '&lt;')
+
+ if (('"' in value) and ("'" not in value)):
+ self._output("'", self._escapeInvisible(value), "'")
+ else:
+ self._output('"', self._escapeInvisible(value.replace('"', '&quot;')), '"')
+
+ if ((qName.namespace == self.gHTMLns) and (qName.localname in self.gVoidElements)):
+ if (self.mXHTML):
+ self._output(' />')
+ else:
+ self._output('>')
+ else:
+ self._output('>')
+
+ if (None != element.text):
+ if ((qName.namespace == self.gHTMLns) and (qName.localname in self.gCDataElements)):
+ if (self.mXHTML):
+ self._output(self._escapeXML(element.text)) # or self._output('<![CDATA[', element.text, ']]>')
+ else:
+ self._output(element.text)
+ else:
+ self._output(self._escapeXML(element.text))
+
+ for child in list(element):
+ self._serializeNode(child, namespacePrefixes)
+
+ self._output('</', qName.localname, '>')
+
+ if (None != element.tail):
+ self._output(self._escapeXML(element.tail))
+
+ def _serializeEntity(self, entity):
+ self._output(entity.text)
+ if (None != entity.tail):
+ self._output(self._escapeXML(entity.tail))
+
+ def _serializePI(self, pi):
+ if (self.mXHTML):
+ self._output('<?', pi.target, ' ', pi.text, '?>')
+ else:
+ raise Exception("Processing Instructions can't be converted to HTML")
+ if (None != pi.tail):
+ self._output(self._escapeXML(pi.tail))
+
+ def _serializeComment(self, comment):
+ self._output('<!--', comment.text, '-->') # XXX escape comment?
+ if (None != comment.tail):
+ self._output(self._escapeXML(comment.tail))
+
+ def _serializeNode(self, node, namespacePrefixes = None):
+ if (isinstance(node, etree._Entity)):
+ self._serializeEntity(node)
+ elif (isinstance(node, etree._ProcessingInstruction)):
+ self._serializePI(node)
+ elif (isinstance(node, etree._Comment)):
+ self._serializeComment(node)
+ else:
+ self._serializeElement(node, namespacePrefixes)
+
+
+ def _serializeTree(self, tree):
+ root = tree.getroot()
+ preceding = [node for node in root.itersiblings(preceding = True)]
+ preceding.reverse()
+ for node in preceding:
+ self._serializeNode(node)
+ self._serializeNode(root)
+ for node in root.itersiblings():
+ self._serializeNode(node)
+
+ def _serializeDoctype(self, tree, doctype, default):
+ if (doctype):
+ self._output(self.gDocTypes[doctype], '\n')
+ else:
+ if (hasattr(tree, 'docinfo') and tree.docinfo and tree.docinfo.doctype):
+ doctypeSearch = tree.docinfo.doctype.lower()
+ for doctype in self.gDocTypes:
+ if (self.gDocTypes[doctype].lower() == doctypeSearch):
+ break
+ else:
+ doctype = None
+ if (self.mXHTML):
+ if ('html' == doctype):
+ doctype = 'xhtml10'
+ elif ('html4' == doctype):
+ doctype = 'xhtml10'
+ elif ('html4-transitional' == doctype):
+ doctype = 'xhtml10-transitional'
+ elif ('html4-frameset' == doctype):
+ doctype = 'xhtml10-frameset'
+ else:
+ if ('xhtml10' == doctype):
+ doctype = 'html4'
+ elif ('xhtml10-transitional' == doctype):
+ doctype = 'html4-transitional'
+ elif ('xhtml10-frameset' == doctype):
+ doctype = 'html4-frameset'
+ elif ('xhtml11' == doctype):
+ doctype = 'html4'
+ if (doctype):
+ self._output(self.gDocTypes[doctype], '\n')
+ else:
+ self._output(tree.docinfo.doctype, '\n')
+ else:
+ self._output(self.gDocTypes[default], '\n')
+
+
+ def serializeHTML(self, tree, doctype = None):
+ self._reset()
+ self._serializeDoctype(tree, doctype, 'html')
+ self._serializeTree(tree)
+ return self.mOutput
+
+ def serializeXHTML(self, tree, doctype = None):
+ self._reset(True)
+ # XXX '<!xml ...' ??
+ self._serializeDoctype(tree, doctype, 'xhtml11')
+ self._serializeTree(tree)
+ return self.mOutput
+
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/Indexer.py b/testing/web-platform/tests/css/tools/w3ctestlib/Indexer.py
new file mode 100644
index 0000000000..f7e2eb2a17
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/Indexer.py
@@ -0,0 +1,250 @@
+#!/usr/bin/python
+# CSS Test Suite Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+# Define contains vmethod for Template Toolkit
+from template.stash import list_op
+@list_op("contains")
+def list_contains(l, x):
+ return x in l
+
+import sys
+import re
+import os
+import codecs
+from os.path import join, exists, abspath
+from template import Template
+import w3ctestlib
+from Utils import listfiles, escapeToNamedASCII
+from OutputFormats import ExtensionMap
+import shutil
+
+class Section:
+ def __init__(self, uri, title, numstr):
+ self.uri = uri
+ self.title = title
+ self.numstr = numstr
+ self.tests = []
+ def __cmp__(self, other):
+ return cmp(self.natsortkey(), other.natsortkey())
+ def chapterNum(self):
+ return self.numstr.partition('.')[0]
+ def natsortkey(self):
+ chunks = self.numstr.partition('.#')[0].split('.')
+ for index in range(len(chunks)):
+ if chunks[index].isdigit():
+ # wrap in tuple with '0' to explicitly specify numbers come first
+ chunks[index] = (0, int(chunks[index]))
+ else:
+ chunks[index] = (1, chunks[index])
+ return (chunks, self.numstr)
+
+class Indexer:
+
+ def __init__(self, suite, sections, suites, flags, splitChapter=False, templatePathList=None,
+ extraData=None, overviewTmplNames=None, overviewCopyExts=('.css', 'htaccess')):
+ """Initialize indexer with TestSuite `suite` toc data file
+ `tocDataPath` and additional template paths in list `templatePathList`.
+
+ The toc data file should be list of tab-separated records, one
+ per line, of each spec section's uri, number/letter, and title.
+ `splitChapter` selects a single page index if False, chapter
+ indicies if True.
+ `extraData` can be a dictionary whose data gets passed to the templates.
+ `overviewCopyExts` lists file extensions that should be found
+ and copied from the template path into the main build directory.
+ The default value is ['.css', 'htaccess'].
+ `overviewTemplateNames` lists template names that should be
+ processed from the template path into the main build directory.
+ The '.tmpl' extension, if any, is stripped from the output filename.
+ The default value is ['index.htm.tmpl', 'index.xht.tmpl', 'testinfo.data.tmpl']
+ """
+ self.suite = suite
+ self.splitChapter = splitChapter
+ self.extraData = extraData
+ self.overviewCopyExtPat = re.compile('.*(%s)$' % '|'.join(overviewCopyExts))
+ self.overviewTmplNames = overviewTmplNames if overviewTmplNames is not None \
+ else ['index.htm.tmpl', 'index.xht.tmpl', 'testinfo.data.tmpl',
+ 'implementation-report-TEMPLATE.data.tmpl']
+
+ # Initialize template engine
+ self.templatePath = [join(w3ctestlib.__path__[0], 'templates')]
+ if templatePathList:
+ self.templatePath.extend(templatePathList)
+ self.templatePath = [abspath(path) for path in self.templatePath]
+ self.tt = Template({
+ 'INCLUDE_PATH': self.templatePath,
+ 'ENCODING' : 'utf-8',
+ 'PRE_CHOMP' : 1,
+ 'POST_CHOMP' : 0,
+ })
+
+ # Load toc data
+ self.sections = {}
+ for uri, numstr, title in sections:
+ uri = intern(uri.encode('utf-8'))
+ uriKey = intern(self._normalizeScheme(uri))
+ numstr = escapeToNamedASCII(numstr)
+ title = escapeToNamedASCII(title) if title else None
+ self.sections[uriKey] = Section(uri, title, numstr)
+
+ self.suites = suites
+ self.flags = flags
+
+ # Initialize storage
+ self.errors = {}
+ self.contributors = {}
+ self.alltests = []
+
+ def _normalizeScheme(self, uri):
+ if (uri and uri.startswith('http:')):
+ return 'https:' + uri[5:]
+ return uri
+
+ def indexGroup(self, group):
+ for test in group.iterTests():
+ data = test.getMetadata()
+ if data: # Shallow copy for template output
+ data = dict(data)
+ data['file'] = '/'.join((group.name, test.relpath)) \
+ if group.name else test.relpath
+ if (data['scripttest']):
+ data['flags'].append(intern('script'))
+ self.alltests.append(data)
+ for uri in data['links']:
+ uri = self._normalizeScheme(uri)
+ uri = uri.replace(self._normalizeScheme(self.suite.draftroot), self._normalizeScheme(self.suite.specroot))
+ if self.sections.has_key(uri):
+ testlist = self.sections[uri].tests.append(data)
+ for credit in data['credits']:
+ self.contributors[credit[0]] = credit[1]
+ else:
+ self.errors[test.sourcepath] = test.errors
+
+ def __writeTemplate(self, template, data, outfile):
+ o = self.tt.process(template, data)
+ with open(outfile, 'w') as f:
+ f.write(o.encode('utf-8'))
+
+ def writeOverview(self, destDir, errorOut=sys.stderr, addTests=[]):
+ """Write format-agnostic pages such as test suite overview pages,
+ test data files, and error reports.
+
+ Indexed errors are reported to errorOut, which must be either
+ an output handle such as sys.stderr, a tuple of
+ (template filename string, output filename string)
+ or None to suppress error output.
+
+ `addTests` is a list of additional test paths, relative to the
+ overview root; it is intended for indexing raw tests
+ """
+
+ # Set common values
+ data = self.extraData.copy()
+ data['suitetitle'] = self.suite.title
+ data['suite'] = self.suite.name
+ data['specroot'] = self.suite.specroot
+ data['draftroot'] = self.suite.draftroot
+ data['contributors'] = self.contributors
+ data['tests'] = self.alltests
+ data['extmap'] = ExtensionMap({'.xht':'', '.html':'', '.htm':'', '.svg':''})
+ data['formats'] = self.suite.formats
+ data['addtests'] = addTests
+ data['suites'] = self.suites
+ data['flagInfo'] = self.flags
+ data['formatInfo'] = { 'html4': { 'report': True, 'path': 'html4', 'ext': 'htm', 'filter': 'nonHTML'},
+ 'html5': { 'report': True, 'path': 'html', 'ext': 'htm', 'filter': 'nonHTML' },
+ 'xhtml1': { 'report': True, 'path': 'xhtml1', 'ext': 'xht', 'filter': 'HTMLonly' },
+ 'xhtml1print': { 'report': False, 'path': 'xhtml1print', 'ext': 'xht', 'filter': 'HTMLonly' },
+ 'svg': { 'report': True, 'path': 'svg', 'ext': 'svg', 'filter': 'HTMLonly' }
+ }
+
+ # Copy simple copy files
+ for tmplDir in reversed(self.templatePath):
+ files = listfiles(tmplDir)
+ for file in files:
+ if self.overviewCopyExtPat.match(file):
+ shutil.copy(join(tmplDir, file), join(destDir, file))
+
+ # Generate indexes
+ for tmpl in self.overviewTmplNames:
+ out = tmpl[0:-5] if tmpl.endswith('.tmpl') else tmpl
+ self.__writeTemplate(tmpl, data, join(destDir, out))
+
+ # Report errors
+ if (self.errors):
+ if type(errorOut) is type(('tmpl','out')):
+ data['errors'] = errors
+ self.__writeTemplate(errorOut[0], data, join(destDir, errorOut[1]))
+ else:
+ sys.stdout.flush()
+ for errorLocation in self.errors:
+ print >> errorOut, "Error in %s: %s" % \
+ (errorLocation, ' '.join([str(error) for error in self.errors[errorLocation]]))
+
+ def writeIndex(self, format):
+ """Write indices into test suite build output through format `format`.
+ """
+
+ # Set common values
+ data = self.extraData.copy()
+ data['suitetitle'] = self.suite.title
+ data['suite'] = self.suite.name
+ data['specroot'] = self.suite.specroot
+ data['draftroot'] = self.suite.draftroot
+
+ data['indexext'] = format.indexExt
+ data['isXML'] = format.indexExt.startswith('.x')
+ data['formatdir'] = format.formatDirName
+ data['extmap'] = format.extMap
+ data['tests'] = self.alltests
+ data['suites'] = self.suites
+ data['flagInfo'] = self.flags
+
+ # Generate indices:
+
+ # Reftest indices
+ self.__writeTemplate('reftest-toc.tmpl', data,
+ format.dest('reftest-toc%s' % format.indexExt))
+ self.__writeTemplate('reftest.tmpl', data,
+ format.dest('reftest.list'))
+
+ # Table of Contents
+ sectionlist = sorted(self.sections.values())
+ if self.splitChapter:
+ # Split sectionlist into chapters
+ chapters = []
+ lastChapNum = '$' # some nonmatching initial char
+ chap = None
+ for section in sectionlist:
+ if (section.title and (section.chapterNum() != lastChapNum)):
+ lastChapNum = section.chapterNum()
+ chap = section
+ chap.sections = []
+ chap.testcount = 0
+ chap.testnames = set()
+ chapters.append(chap)
+ chap.testnames.update([test['name'] for test in section.tests])
+ chap.testcount = len(chap.testnames)
+ chap.sections.append(section)
+
+ # Generate main toc
+ data['chapters'] = chapters
+ self.__writeTemplate('chapter-toc.tmpl', data,
+ format.dest('toc%s' % format.indexExt))
+ del data['chapters']
+
+ # Generate chapter tocs
+ for chap in chapters:
+ data['chaptertitle'] = chap.title
+ data['testcount'] = chap.testcount
+ data['sections'] = chap.sections
+ self.__writeTemplate('test-toc.tmpl', data, format.dest('chapter-%s%s' \
+ % (chap.numstr, format.indexExt)))
+
+ else: # not splitChapter
+ data['chapters'] = sectionlist
+ self.__writeTemplate('test-toc.tmpl', data,
+ format.dest('toc%s' % format.indexExt))
+ del data['chapters']
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/OutputFormats.py b/testing/web-platform/tests/css/tools/w3ctestlib/OutputFormats.py
new file mode 100644
index 0000000000..084e66d02f
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/OutputFormats.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# CSS Test Source Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+import re
+import os
+from os.path import join, exists, splitext, dirname, basename
+from Sources import XHTMLSource, HTMLSource, SVGSource, SourceTree
+
+class ExtensionMap:
+ """ Given a file extension mapping (e.g. {'.xht' : '.htm'}), provides
+ a translate function for paths.
+ """
+ def __init__(self, extMap):
+ self.extMap = extMap
+
+ def translate(self, path):
+ for ext in self.extMap:
+ if path.endswith(ext):
+ return splitext(path)[0] + self.extMap[ext]
+ return path
+
+class BasicFormat:
+ """Base class. A Format manages all the conversions and location
+ transformations (e.g. subdirectory for all tests in that format)
+ associated with a test suite format.
+
+ The base class implementation performs no conversions or
+ format-specific location transformations."""
+ formatDirName = None
+ indexExt = '.htm'
+ convert = True # XXX hack to supress format conversion in support dirs, need to clean up output code to make this cleaner
+
+ def __init__(self, destroot, sourceTree, extMap=None, outputDirName=None):
+ """Creates format root of the output tree. `destroot` is the root path
+ of the output tree.
+
+ extMap provides a file extension mapping, e.g. {'.xht' : '.htm'}
+ """
+ self.root = join(destroot, outputDirName) if outputDirName else destroot
+ self.sourceTree = sourceTree
+ self.formatDirName = outputDirName
+ if not exists(self.root):
+ os.makedirs(self.root)
+ self.extMap = ExtensionMap(extMap or {})
+ self.subdir = None
+
+ def setSubDir(self, name=None):
+ """Sets format to write into group subdirectory `name`.
+ """
+ self.subdir = name
+
+ def destDir(self):
+ return join(self.root, self.subdir) if self.subdir else self.root
+
+ def dest(self, relpath):
+ """Returns final destination of relpath in this format and ensures that the
+ parent directory exists."""
+ # Translate path
+ if (self.convert):
+ relpath = self.extMap.translate(relpath)
+ if (self.sourceTree.isReferenceAnywhere(relpath)):
+ relpath = join('reference', basename(relpath))
+ # XXX when forcing support files into support path, need to account for support/support
+ dest = join(self.root, self.subdir, relpath) if self.subdir \
+ else join(self.root, relpath)
+ # Ensure parent
+ parent = dirname(dest)
+ if not exists(parent):
+ os.makedirs(parent)
+
+ return dest
+
+ def write(self, source):
+ """Write FileSource to destination, following all necessary
+ conversion methods."""
+ source.write(self, source)
+
+ testTransform = False
+ # def testTransform(self, outputString, source) if needed
+
+class XHTMLFormat(BasicFormat):
+ """Base class for XHTML test suite format. Builds into 'xhtml1' subfolder
+ of root.
+ """
+ indexExt = '.xht'
+
+ def __init__(self, destroot, sourceTree, extMap=None, outputDirName='xhtml1'):
+ if not extMap:
+ extMap = {'.htm' : '.xht', '.html' : '.xht', '.xhtml' : '.xht' }
+ BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
+
+ def write(self, source):
+ # skip HTMLonly tests
+ if hasattr(source, 'hasFlag') and source.hasFlag('HTMLonly'):
+ return
+ if isinstance(source, HTMLSource) and self.convert:
+ source.write(self, source.serializeXHTML())
+ else:
+ source.write(self)
+
+class HTMLFormat(BasicFormat):
+ """Base class for HTML test suite format. Builds into 'html4' subfolder
+ of root.
+ """
+
+ def __init__(self, destroot, sourceTree, extMap=None, outputDirName='html4'):
+ if not extMap:
+ extMap = {'.xht' : '.htm', '.xhtml' : '.htm', '.html' : '.htm' }
+ BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
+
+ def write(self, source):
+ # skip nonHTML tests
+ if hasattr(source, 'hasFlag') and source.hasFlag('nonHTML'):
+ return
+ if isinstance(source, XHTMLSource) and self.convert:
+ source.write(self, source.serializeHTML())
+ else:
+ source.write(self)
+
+
+class HTML5Format(HTMLFormat):
+ def __init__(self, destroot, sourceTree, extMap=None, outputDirName='html'):
+ HTMLFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
+
+ def write(self, source):
+ # skip nonHTML tests
+ if hasattr(source, 'hasFlag') and source.hasFlag('nonHTML'):
+ return
+ if isinstance(source, XHTMLSource) and self.convert:
+ source.write(self, source.serializeHTML())
+ else:
+ source.write(self)
+
+
+class SVGFormat(BasicFormat):
+ def __init__(self, destroot, sourceTree, extMap=None, outputDirName='svg'):
+ if not extMap:
+ extMap = {'.svg' : '.svg' }
+ BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
+
+ def write(self, source):
+ # skip non SVG tests
+ if isinstance(source, SVGSource):
+ source.write(self)
+
+
+class XHTMLPrintFormat(XHTMLFormat):
+ """Base class for XHTML Print test suite format. Builds into 'xhtml1print'
+ subfolder of root.
+ """
+
+ def __init__(self, destroot, sourceTree, testSuiteName, extMap=None, outputDirName='xhtml1print'):
+ if not extMap:
+ extMap = {'.htm' : '.xht', '.html' : '.xht', '.xhtml' : '.xht' }
+ BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
+ self.testSuiteName = testSuiteName
+
+ def write(self, source):
+ if (isinstance(source, XHTMLSource)):
+ if not source.hasFlag('HTMLonly'):
+ source.write(self, self.testTransform(source))
+ else:
+ XHTMLFormat.write(self, source)
+
+ def testTransform(self, source):
+ assert isinstance(source, XHTMLSource)
+ output = source.serializeXHTML('xhtml10')
+
+ headermeta = {'suitename' : self.testSuiteName,
+ 'testid' : source.name(),
+ 'margin' : '',
+ }
+ if re.search('@page\s*{[^}]*@', output):
+ # Don't use headers and footers when page tests margin boxes
+ output = re.sub('(<body[^>]*>)',
+ '\1\n' + self.__htmlstart % headermeta,
+ output);
+ output = re.sub('(</body[^>]*>)',
+ '\1\n' + self.__htmlend % headermeta,
+ output);
+ else:
+ # add margin rule only when @page statement does not exist
+ if not re.search('@page', output):
+ headermeta['margin'] = self.__margin
+ output = re.sub('</title>',
+ '</title>\n <style type="text/css">%s</style>' % \
+ (self.__css % headermeta),
+ output);
+ return output;
+
+ # template bits
+ __margin = 'margin: 7%;';
+ __font = 'font: italic 8pt sans-serif; color: gray;'
+ __css = """
+ @page { %s
+ %%(margin)s
+ counter-increment: page;
+ @top-left { content: "%%(suitename)s"; }
+ @top-right { content: "Test %%(testid)s"; }
+ @bottom-right { content: counter(page); }
+ }
+""" % __font
+ __htmlstart = '<p style="%s">Start of %%(suitename)s %%(testid)s.</p>' % __font
+ __htmlend = '<p style="%s">End of %%(suitename)s %%(testid)s.</p>' % __font
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/Sources.py b/testing/web-platform/tests/css/tools/w3ctestlib/Sources.py
new file mode 100644
index 0000000000..f3848030ba
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/Sources.py
@@ -0,0 +1,1473 @@
+#!/usr/bin/python
+# CSS Test Source Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+from __future__ import print_function
+from os.path import basename, exists, join
+import os
+import filecmp
+import shutil
+import re
+import codecs
+import collections
+from xml import dom
+import html5lib
+from html5lib import treebuilders
+from lxml import etree
+from lxml.etree import ParseError
+from Utils import getMimeFromExt, escapeToNamedASCII, basepath, isPathInsideBase, relativeURL, assetName
+import HTMLSerializer
+import warnings
+import hashlib
+
+class SourceTree(object):
+ """Class that manages structure of test repository source.
+ Temporarily hard-coded path and filename rules, this should be configurable.
+ """
+
+ def __init__(self, repository = None):
+ self.mTestExtensions = ['.xht', '.html', '.xhtml', '.htm', '.xml', '.svg']
+ self.mReferenceExtensions = ['.xht', '.html', '.xhtml', '.htm', '.xml', '.png', '.svg']
+ self.mRepository = repository
+
+ def _splitDirs(self, dir):
+ if ('' == dir):
+ pathList = []
+ elif ('/' in dir):
+ pathList = dir.split('/')
+ else:
+ pathList = dir.split(os.path.sep)
+ return pathList
+
+ def _splitPath(self, filePath):
+ """split a path into a list of directory names and the file name
+ paths may come form the os or mercurial, which always uses '/' as the
+ directory separator
+ """
+ dir, fileName = os.path.split(filePath.lower())
+ return (self._splitDirs(dir), fileName)
+
+ def isTracked(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName))
+
+ def _isApprovedPath(self, pathList):
+ return ((1 < len(pathList)) and ('approved' == pathList[0]) and (('support' == pathList[1]) or ('src' in pathList)))
+
+ def isApprovedPath(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName)) and self._isApprovedPath(pathList)
+
+ def _isIgnoredPath(self, pathList):
+ return (('.hg' in pathList) or ('.git' in pathList) or
+ ('.svn' in pathList) or ('cvs' in pathList) or
+ ('incoming' in pathList) or ('work-in-progress' in pathList) or
+ ('data' in pathList) or ('archive' in pathList) or
+ ('reports' in pathList) or ('tools' == pathList[0]) or
+ ('test-plan' in pathList) or ('test-plans' in pathList))
+
+ def _isIgnored(self, pathList, fileName):
+ if (pathList): # ignore files in root
+ return (self._isIgnoredPath(pathList) or
+ fileName.startswith('.directory') or ('lock' == fileName) or
+ ('.ds_store' == fileName) or
+ fileName.startswith('.hg') or fileName.startswith('.git') or
+ ('sections.dat' == fileName) or ('get-spec-sections.pl' == fileName))
+ return True
+
+ def isIgnored(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return self._isIgnored(pathList, fileName)
+
+ def isIgnoredDir(self, dir):
+ pathList = self._splitDirs(dir)
+ return self._isIgnoredPath(pathList)
+
+ def _isToolPath(self, pathList):
+ return ('tools' in pathList)
+
+ def _isTool(self, pathList, fileName):
+ return self._isToolPath(pathList)
+
+ def isTool(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName)) and self._isTool(pathList, fileName)
+
+ def _isSupportPath(self, pathList):
+ return ('support' in pathList)
+
+ def _isSupport(self, pathList, fileName):
+ return (self._isSupportPath(pathList) or
+ ((not self._isTool(pathList, fileName)) and
+ (not self._isReference(pathList, fileName)) and
+ (not self._isTestCase(pathList, fileName))))
+
+ def isSupport(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName)) and self._isSupport(pathList, fileName)
+
+ def _isReferencePath(self, pathList):
+ return (('reftest' in pathList) or ('reference' in pathList))
+
+ def _isReference(self, pathList, fileName):
+ if ((not self._isSupportPath(pathList)) and (not self._isToolPath(pathList))):
+ baseName, fileExt = os.path.splitext(fileName)[:2]
+ if (bool(re.search('(^ref-|^notref-).+', baseName)) or
+ bool(re.search('.+(-ref[0-9]*$|-notref[0-9]*$)', baseName)) or
+ ('-ref-' in baseName) or ('-notref-' in baseName)):
+ return (fileExt in self.mReferenceExtensions)
+ if (self._isReferencePath(pathList)):
+ return (fileExt in self.mReferenceExtensions)
+ return False
+
+ def isReference(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName)) and self._isReference(pathList, fileName)
+
+ def isReferenceAnywhere(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return self._isReference(pathList, fileName)
+
+ def _isTestCase(self, pathList, fileName):
+ if ((not self._isToolPath(pathList)) and (not self._isSupportPath(pathList)) and (not self._isReference(pathList, fileName))):
+ fileExt = os.path.splitext(fileName)[1]
+ return (fileExt in self.mTestExtensions)
+ return False
+
+ def isTestCase(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ return (not self._isIgnored(pathList, fileName)) and self._isTestCase(pathList, fileName)
+
+ def getAssetName(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ if (self._isReference(pathList, fileName) or self._isTestCase(pathList, fileName)):
+ return assetName(fileName)
+ return fileName.lower() # support files keep full name
+
+ def getAssetType(self, filePath):
+ pathList, fileName = self._splitPath(filePath)
+ if (self._isReference(pathList, fileName)):
+ return intern('reference')
+ if (self._isTestCase(pathList, fileName)):
+ return intern('testcase')
+ if (self._isTool(pathList, fileName)):
+ return intern('tool')
+ return intern('support')
+
+
+class SourceCache:
+ """Cache for FileSource objects. Supports one FileSource object
+ per sourcepath.
+ """
+ def __init__(self, sourceTree):
+ self.__cache = {}
+ self.sourceTree = sourceTree
+
+ def generateSource(self, sourcepath, relpath, data = None):
+ """Return a FileSource or derivative based on the extensionMap.
+
+ Uses a cache to avoid creating more than one of the same object:
+ does not support creating two FileSources with the same sourcepath;
+ asserts if this is tried. (.htaccess files are not cached.)
+
+ Cache is bypassed if loading form a change context
+ """
+ if ((None == data) and self.__cache.has_key(sourcepath)):
+ source = self.__cache[sourcepath]
+ assert relpath == source.relpath
+ return source
+
+ if basename(sourcepath) == '.htaccess':
+ return ConfigSource(self.sourceTree, sourcepath, relpath, data)
+ mime = getMimeFromExt(sourcepath)
+ if (mime == 'application/xhtml+xml'):
+ source = XHTMLSource(self.sourceTree, sourcepath, relpath, data)
+ elif (mime == 'text/html'):
+ source = HTMLSource(self.sourceTree, sourcepath, relpath, data)
+ elif (mime == 'image/svg+xml'):
+ source = SVGSource(self.sourceTree, sourcepath, relpath, data)
+ elif (mime == 'application/xml'):
+ source = XMLSource(self.sourceTree, sourcepath, relpath, data)
+ else:
+ source = FileSource(self.sourceTree, sourcepath, relpath, mime, data)
+ if (None == data):
+ self.__cache[sourcepath] = source
+ return source
+
+class SourceSet:
+ """Set of FileSource objects. No two FileSources of the same type in the set may
+ have the same name (except .htaccess files, which are merged).
+ """
+ def __init__(self, sourceCache):
+ self.sourceCache = sourceCache
+ self.pathMap = {} # type/name -> source
+
+ def __len__(self):
+ return len(self.pathMap)
+
+ def _keyOf(self, source):
+ return source.type() + '/' + source.keyName()
+
+ def __contains__(self, source):
+ return self._keyOf(source) in self.pathMap
+
+
+ def iter(self):
+ """Iterate over FileSource objects in SourceSet.
+ """
+ return self.pathMap.itervalues()
+
+ def addSource(self, source, ui):
+ """Add FileSource `source`. Throws exception if we already have
+ a FileSource with the same path relpath but different contents.
+ (ConfigSources are exempt from this requirement.)
+ """
+ cachedSource = self.pathMap.get(self._keyOf(source))
+ if not cachedSource:
+ self.pathMap[self._keyOf(source)] = source
+ else:
+ if source != cachedSource:
+ if isinstance(source, ConfigSource):
+ cachedSource.append(source)
+ else:
+ ui.warn("File merge mismatch %s vs %s for %s\n" % \
+ (cachedSource.sourcepath, source.sourcepath, source.name()))
+
+ def add(self, sourcepath, relpath, ui):
+ """Generate and add FileSource from sourceCache. Return the resulting
+ FileSource.
+
+ Throws exception if we already have a FileSource with the same path
+ relpath but different contents.
+ """
+ source = self.sourceCache.generateSource(sourcepath, relpath)
+ self.addSource(source, ui)
+ return source
+
+ @staticmethod
+ def combine(a, b, ui):
+ """Merges a and b, and returns whichever one contains the merger (which
+ one is chosen based on merge efficiency). Can accept None as an argument.
+ """
+ if not (a and b):
+ return a or b
+ if len(a) < len(b):
+ return b.merge(a, ui)
+ return a.merge(b, ui)
+
+ def merge(self, other, ui):
+ """Merge sourceSet's contents into this SourceSet.
+
+ Throws a RuntimeError if there's a sourceCache mismatch.
+ Throws an Exception if two files with the same relpath mismatch.
+ Returns merge result (i.e. self)
+ """
+ if self.sourceCache is not other.sourceCache:
+ raise RuntimeError
+
+ for source in other.pathMap.itervalues():
+ self.addSource(source, ui)
+ return self
+
+ def adjustContentPaths(self, format):
+ for source in self.pathMap.itervalues():
+ source.adjustContentPaths(format)
+
+ def write(self, format):
+ """Write files out through OutputFormat `format`.
+ """
+ for source in self.pathMap.itervalues():
+ format.write(source)
+
+
+class StringReader(object):
+ """Wrapper around a string to give it a file-like api
+ """
+ def __init__(self, string):
+ self.mString = string
+ self.mIndex = 0
+
+ def read(self, maxSize = None):
+ if (self.mIndex < len(self.mString)):
+ if (maxSize and (0 < maxSize)):
+ slice = self.mString[self.mIndex:self.mIndex + maxSize]
+ self.mIndex += len(slice)
+ return slice
+ else:
+ self.mIndex = len(self.mString)
+ return self.mString
+ return ''
+
+
+class NamedDict(object):
+ def get(self, key):
+ if (key in self):
+ return self[key]
+ return None
+
+ def __eq__(self, other):
+ for key in self.__slots__:
+ if (self[key] != other[key]):
+ return False
+ return True
+
+ def __ne__(self, other):
+ for key in self.__slots__:
+ if (self[key] != other[key]):
+ return True
+ return False
+
+ def __len__(self):
+ return len(self.__slots__)
+
+ def __iter__(self):
+ return iter(self.__slots__)
+
+ def __contains__(self, key):
+ return (key in self.__slots__)
+
+ def copy(self):
+ clone = self.__class__()
+ for key in self.__slots__:
+ clone[key] = self[key]
+ return clone
+
+ def keys(self):
+ return self.__slots__
+
+ def has_key(self, key):
+ return (key in self)
+
+ def items(self):
+ return [(key, self[key]) for key in self.__slots__]
+
+ def iteritems(self):
+ return iter(self.items())
+
+ def iterkeys(self):
+ return self.__iter__()
+
+ def itervalues(self):
+ return iter(self.items())
+
+ def __str__(self):
+ return '{ ' + ', '.join([key + ': ' + str(self[key]) for key in self.__slots__]) + ' }'
+
+
+class Metadata(NamedDict):
+ __slots__ = ('name', 'title', 'asserts', 'credits', 'reviewers', 'flags', 'links', 'references', 'revision', 'selftest', 'scripttest')
+
+ def __init__(self, name = None, title = None, asserts = [], credits = [], reviewers = [], flags = [], links = [],
+ references = [], revision = None, selftest = True, scripttest = False):
+ self.name = name
+ self.title = title
+ self.asserts = asserts
+ self.credits = credits
+ self.reviewers = reviewers
+ self.flags = flags
+ self.links = links
+ self.references = references
+ self.revision = revision
+ self.selftest = selftest
+ self.scripttest = scripttest
+
+ def __getitem__(self, key):
+ if ('name' == key):
+ return self.name
+ if ('title' == key):
+ return self.title
+ if ('asserts' == key):
+ return self.asserts
+ if ('credits' == key):
+ return self.credits
+ if ('reviewers' == key):
+ return self.reviewers
+ if ('flags' == key):
+ return self.flags
+ if ('links' == key):
+ return self.links
+ if ('references' == key):
+ return self.references
+ if ('revision' == key):
+ return self.revision
+ if ('selftest' == key):
+ return self.selftest
+ if ('scripttest' == key):
+ return self.scripttest
+ return None
+
+ def __setitem__(self, key, value):
+ if ('name' == key):
+ self.name = value
+ elif ('title' == key):
+ self.title = value
+ elif ('asserts' == key):
+ self.asserts = value
+ elif ('credits' == key):
+ self.credits = value
+ elif ('reviewers' == key):
+ self.reviewers = value
+ elif ('flags' == key):
+ self.flags = value
+ elif ('links' == key):
+ self.links = value
+ elif ('references' == key):
+ self.references = value
+ elif ('revision' == key):
+ self.revision = value
+ elif ('selftest' == key):
+ self.selftest = value
+ elif ('scripttest' == key):
+ self.scripttest = value
+ else:
+ raise KeyError()
+
+
+class ReferenceData(NamedDict):
+ __slots__ = ('name', 'type', 'relpath', 'repopath')
+
+ def __init__(self, name = None, type = None, relpath = None, repopath = None):
+ self.name = name
+ self.type = type
+ self.relpath = relpath
+ self.repopath = repopath
+
+ def __getitem__(self, key):
+ if ('name' == key):
+ return self.name
+ if ('type' == key):
+ return self.type
+ if ('relpath' == key):
+ return self.relpath
+ if ('repopath' == key):
+ return self.repopath
+ return None
+
+ def __setitem__(self, key, value):
+ if ('name' == key):
+ self.name = value
+ elif ('type' == key):
+ self.type = value
+ elif ('relpath' == key):
+ self.relpath = value
+ elif ('repopath' == key):
+ self.repopath = value
+ else:
+ raise KeyError()
+
+UserData = collections.namedtuple('UserData', ('name', 'link'))
+
+class LineString(str):
+ def __new__(cls, value, line):
+ self = str.__new__(cls, value)
+ self.line = line
+ return self
+
+ def lineValue(self):
+ return 'Line ' + str(self.line) + ': ' + str.__str__(self) if (self.line) else str.__str__(self)
+
+
+class FileSource:
+ """Object representing a file. Two FileSources are equal if they represent
+ the same file contents. It is recommended to use a SourceCache to generate
+ FileSources.
+ """
+
+ def __init__(self, sourceTree, sourcepath, relpath, mimetype = None, data = None):
+ """Init FileSource from source path. Give it relative path relpath.
+
+ `mimetype` should be the canonical MIME type for the file, if known.
+ If `mimetype` is None, guess type from file extension, defaulting to
+ the None key's value in extensionMap.
+
+ `data` if provided, is a the contents of the file. Otherwise the file is read
+ from disk.
+ """
+ self.sourceTree = sourceTree
+ self.sourcepath = sourcepath
+ self.relpath = relpath
+ self.mimetype = mimetype or getMimeFromExt(sourcepath)
+ self._data = data
+ self.errors = None
+ self.encoding = 'utf-8'
+ self.refs = {}
+ self.scripts = {}
+ self.metadata = None
+ self.metaSource = None
+
+ def __eq__(self, other):
+ if not isinstance(other, FileSource):
+ return False
+ return self.sourcepath == other.sourcepath or \
+ filecmp.cmp(self.sourcepath, other.sourcepath)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __cmp__(self, other):
+ return cmp(self.name(), other.name())
+
+ def name(self):
+ return self.sourceTree.getAssetName(self.sourcepath)
+
+ def keyName(self):
+ if ('support' == self.type()):
+ return os.path.relpath(self.relpath, 'support')
+ return self.name()
+
+ def type(self):
+ return self.sourceTree.getAssetType(self.sourcepath)
+
+ def relativeURL(self, other):
+ return relativeURL(self.relpath, other.relpath)
+
+ def data(self):
+ """Return file contents as a byte string."""
+ if (self._data is None):
+ with open(self.sourcepath, 'r') as f:
+ self._data = f.read()
+ if (self._data.startswith(codecs.BOM_UTF8)):
+ self.encoding = 'utf-8-sig' # XXX look for other unicode BOMs
+ return self._data
+
+ def unicode(self):
+ try:
+ return self.data().decode(self.encoding)
+ except UnicodeDecodeError:
+ return None
+
+ def parse(self):
+ """Parses and validates FileSource data from sourcepath."""
+ self.loadMetadata()
+
+ def validate(self):
+ """Ensure data is loaded from sourcepath."""
+ self.parse()
+
+ def adjustContentPaths(self, format):
+ """Adjust any paths in file content for output format
+ XXX need to account for group paths"""
+ if (self.refs):
+ seenRefs = {}
+ seenRefs[self.sourcepath] = '=='
+ def adjustReferences(source):
+ newRefs = {}
+ for refName in source.refs:
+ refType, refPath, refNode, refSource = source.refs[refName]
+ if refSource:
+ refPath = relativeURL(format.dest(self.relpath), format.dest(refSource.relpath))
+ if (refSource.sourcepath not in seenRefs):
+ seenRefs[refSource.sourcepath] = refType
+ adjustReferences(refSource)
+ else:
+ refPath = relativeURL(format.dest(self.relpath), format.dest(refPath))
+ if (refPath != refNode.get('href')):
+ refNode.set('href', refPath)
+ newRefs[refName] = (refType, refPath, refNode, refSource) # update path in metadata
+ source.refs = newRefs
+ adjustReferences(self)
+
+ if (self.scripts): # force testharness.js scripts to absolute path
+ for src in self.scripts:
+ if (src.endswith('/resources/testharness.js')): # accept relative paths to testharness.js
+ scriptNode = self.scripts[src]
+ scriptNode.set('src', '/resources/testharness.js')
+ elif (src.endswith('/resources/testharnessreport.js')):
+ scriptNode = self.scripts[src]
+ scriptNode.set('src', '/resources/testharnessreport.js')
+
+
+ def write(self, format):
+ """Writes FileSource.data() out to `self.relpath` through Format `format`."""
+ data = self.data()
+ with open(format.dest(self.relpath), 'w') as f:
+ f.write(data)
+ if (self.metaSource):
+ self.metaSource.write(format) # XXX need to get output path from format, but not let it choose actual format
+
+ def compact(self):
+ """Clears all cached data, preserves computed data."""
+ pass
+
+ def revision(self):
+ """Returns hash of the contents of this file and any related file, references, support files, etc.
+ XXX also needs to account for .meta file
+ """
+ sha = hashlib.sha1()
+ sha.update(self.data())
+ seenRefs = set(self.sourcepath)
+ def hashReference(source):
+ for refName in source.refs:
+ refSource = source.refs[refName][3]
+ if (refSource and (refSource.sourcepath not in seenRefs)):
+ sha.update(refSource.data())
+ seenRefs.add(refSource.sourcepath)
+ hashReference(refSource)
+ hashReference(self)
+ return sha.hexdigest()
+
+ def loadMetadata(self):
+ """Look for .meta file and load any metadata from it if present
+ """
+ pass
+
+ def augmentMetadata(self, next=None, prev=None, reference=None, notReference=None):
+ if (self.metaSource):
+ return self.metaSource.augmentMetadata(next, prev, reference, notReference)
+ return None
+
+ # See http://wiki.csswg.org/test/css2.1/format for more info on metadata
+ def getMetadata(self, asUnicode = False):
+ """Return dictionary of test metadata. Stores list of errors
+ in self.errors if there are parse or metadata errors.
+ Data fields include:
+ - asserts [list of strings]
+ - credits [list of (name string, url string) tuples]
+ - reviewers [ list of (name string, url string) tuples]
+ - flags [list of token strings]
+ - links [list of url strings]
+ - name [string]
+ - title [string]
+ - references [list of ReferenceData per reference; None if not reftest]
+ - revision [revision id of last commit]
+ - selftest [bool]
+ - scripttest [bool]
+ Strings are given in ascii unless asUnicode==True.
+ """
+
+ self.validate()
+
+ def encode(str):
+ return str if (hasattr(str, 'line')) else intern(str.encode('utf-8'))
+
+ def escape(str, andIntern = True):
+ return str.encode('utf-8') if asUnicode else intern(escapeToNamedASCII(str)) if andIntern else escapeToNamedASCII(str)
+
+ def listReferences(source, seen):
+ refGroups = []
+ for refType, refRelPath, refNode, refSource in source.refs.values():
+ if ('==' == refType):
+ if (refSource):
+ refSourcePath = refSource.sourcepath
+ else:
+ refSourcePath = os.path.normpath(join(basepath(source.sourcepath), refRelPath))
+ if (refSourcePath in seen):
+ continue
+ seen.add(refSourcePath)
+ if (refSource):
+ sourceData = ReferenceData(name = self.sourceTree.getAssetName(refSourcePath), type = refType,
+ relpath = refRelPath, repopath = refSourcePath)
+ if (refSource.refs):
+ subRefLists = listReferences(refSource, seen.copy())
+ if (subRefLists):
+ for subRefList in subRefLists:
+ refGroups.append([sourceData] + subRefList)
+ else:
+ refGroups.append([sourceData])
+ else:
+ refGroups.append([sourceData])
+ else:
+ sourceData = ReferenceData(name = self.sourceTree.getAssetName(refSourcePath), type = refType,
+ relpath = relativeURL(self.sourcepath, refSourcePath),
+ repopath = refSourcePath)
+ refGroups.append([sourceData])
+ notRefs = {}
+ for refType, refRelPath, refNode, refSource in source.refs.values():
+ if ('!=' == refType):
+ if (refSource):
+ refSourcePath = refSource.sourcepath
+ else:
+ refSourcePath = os.path.normpath(join(basepath(source.sourcepath), refRelPath))
+ if (refSourcePath in seen):
+ continue
+ seen.add(refSourcePath)
+ if (refSource):
+ sourceData = ReferenceData(name = self.sourceTree.getAssetName(refSourcePath), type = refType,
+ relpath = refRelPath, repopath = refSourcePath)
+ notRefs[sourceData.name] = sourceData
+ if (refSource.refs):
+ for subRefList in listReferences(refSource, seen):
+ for subRefData in subRefList:
+ notRefs[subRefData.name] = subRefData
+ else:
+ sourceData = ReferenceData(name = self.sourceTree.getAssetName(refSourcePath), type = refType,
+ relpath = relativeURL(self.sourcepath, refSourcePath),
+ repopath = refSourcePath)
+ notRefs[sourceData.name] = sourceData
+ if (notRefs):
+ for refData in notRefs.values():
+ refData.type = '!='
+ if (refGroups):
+ for refGroup in refGroups:
+ for notRef in notRefs.values():
+ for ref in refGroup:
+ if (ref.name == notRef.name):
+ break
+ else:
+ refGroup.append(notRef)
+ else:
+ refGroups.append(notRefs.values())
+ return refGroups
+
+ references = listReferences(self, set([self.sourcepath])) if (self.refs) else None
+
+ if (self.metadata):
+ data = Metadata(
+ name = encode(self.name()),
+ title = escape(self.metadata['title'], False),
+ asserts = [escape(assertion, False) for assertion in self.metadata['asserts']],
+ credits = [UserData(escape(name), encode(link)) for name, link in self.metadata['credits']],
+ reviewers = [UserData(escape(name), encode(link)) for name, link in self.metadata['reviewers']],
+ flags = [encode(flag) for flag in self.metadata['flags']],
+ links = [encode(link) for link in self.metadata['links']],
+ references = references,
+ revision = self.revision(),
+ selftest = self.isSelftest(),
+ scripttest = self.isScripttest()
+ )
+ return data
+ return None
+
+ def addReference(self, referenceSource, match = None):
+ """Add reference source."""
+ self.validate()
+ refName = referenceSource.name()
+ refPath = self.relativeURL(referenceSource)
+ if refName not in self.refs:
+ node = None
+ if match == '==':
+ node = self.augmentMetadata(reference=referenceSource).reference
+ elif match == '!=':
+ node = self.augmentMetadata(notReference=referenceSource).notReference
+ self.refs[refName] = (match, refPath, node, referenceSource)
+ else:
+ node = self.refs[refName][2]
+ node.set('href', refPath)
+ if (match):
+ node.set('rel', 'mismatch' if ('!=' == match) else 'match')
+ else:
+ match = self.refs[refName][0]
+ self.refs[refName] = (match, refPath, node, referenceSource)
+
+ def getReferencePaths(self):
+ """Get list of paths to references as tuple(path, relPath, refType)."""
+ self.validate()
+ return [(os.path.join(os.path.dirname(self.sourcepath), ref[1]),
+ os.path.join(os.path.dirname(self.relpath), ref[1]),
+ ref[0])
+ for ref in self.refs.values()]
+
+ def isTest(self):
+ self.validate()
+ return bool(self.metadata) and bool(self.metadata.get('links'))
+
+ def isReftest(self):
+ return self.isTest() and bool(self.refs)
+
+ def isSelftest(self):
+ return self.isTest() and (not bool(self.refs))
+
+ def isScripttest(self):
+ if (self.isTest() and self.scripts):
+ for src in self.scripts:
+ if (src.endswith('/resources/testharness.js')): # accept relative paths to testharness.js
+ return True
+ return False
+
+ def hasFlag(self, flag):
+ data = self.getMetadata()
+ if data:
+ return flag in data['flags']
+ return False
+
+
+
+class ConfigSource(FileSource):
+ """Object representing a text-based configuration file.
+ Capable of merging multiple config-file contents.
+ """
+
+ def __init__(self, sourceTree, sourcepath, relpath, mimetype = None, data = None):
+ """Init ConfigSource from source path. Give it relative path relpath.
+ """
+ FileSource.__init__(self, sourceTree, sourcepath, relpath, mimetype, data)
+ self.sourcepath = [sourcepath]
+
+ def __eq__(self, other):
+ if not isinstance(other, ConfigSource):
+ return False
+ if self is other or self.sourcepath == other.sourcepath:
+ return True
+ if len(self.sourcepath) != len(other.sourcepath):
+ return False
+ for this, that in zip(self.sourcepath, other.sourcepath):
+ if not filecmp.cmp(this, that):
+ return False
+ return True
+
+ def __ne__(self, other):
+ return not self == other
+
+ def name(self):
+ return '.htaccess'
+
+ def type(self):
+ return intern('support')
+
+ def data(self):
+ """Merge contents of all config files represented by this source."""
+ data = ''
+ for src in self.sourcepath:
+ with open(src) as f:
+ data += f.read()
+ data += '\n'
+ return data
+
+ def getMetadata(self, asUnicode = False):
+ return None
+
+ def append(self, other):
+ """Appends contents of ConfigSource `other` to this source.
+ Asserts if self.relpath != other.relpath.
+ """
+ assert isinstance(other, ConfigSource)
+ assert self != other and self.relpath == other.relpath
+ self.sourcepath.extend(other.sourcepath)
+
+class ReftestFilepathError(Exception):
+ pass
+
+class ReftestManifest(ConfigSource):
+ """Object representing a reftest manifest file.
+ Iterating the ReftestManifest returns (testpath, refpath) tuples
+ with paths relative to the manifest.
+ """
+ def __init__(self, sourceTree, sourcepath, relpath, data = None):
+ """Init ReftestManifest from source path. Give it relative path `relpath`
+ and load its .htaccess file.
+ """
+ ConfigSource.__init__(self, sourceTree, sourcepath, relpath, mimetype = 'config/reftest', data = data)
+
+ def basepath(self):
+ """Returns the base relpath of this reftest manifest path, i.e.
+ the parent of the manifest file.
+ """
+ return basepath(self.relpath)
+
+ baseRE = re.compile(r'^#\s*relstrip\s+(\S+)\s*')
+ stripRE = re.compile(r'#.*')
+ parseRE = re.compile(r'^\s*([=!]=)\s*(\S+)\s+(\S+)')
+
+ def __iter__(self):
+ """Parse the reftest manifest files represented by this ReftestManifest
+ and return path information about each reftest pair as
+ ((test-sourcepath, ref-sourcepath), (test-relpath, ref-relpath), reftype)
+ Raises a ReftestFilepathError if any sources file do not exist or
+ if any relpaths point higher than the relpath root.
+ """
+ striplist = []
+ for src in self.sourcepath:
+ relbase = basepath(self.relpath)
+ srcbase = basepath(src)
+ with open(src) as f:
+ for line in f:
+ strip = self.baseRE.search(line)
+ if strip:
+ striplist.append(strip.group(1))
+ line = self.stripRE.sub('', line)
+ m = self.parseRE.search(line)
+ if m:
+ record = ((join(srcbase, m.group(2)), join(srcbase, m.group(3))), \
+ (join(relbase, m.group(2)), join(relbase, m.group(3))), \
+ m.group(1))
+ # for strip in striplist:
+ # strip relrecord
+ if not exists(record[0][0]):
+ raise ReftestFilepathError("Manifest Error in %s: "
+ "Reftest test file %s does not exist." \
+ % (src, record[0][0]))
+ elif not exists(record[0][1]):
+ raise ReftestFilepathError("Manifest Error in %s: "
+ "Reftest reference file %s does not exist." \
+ % (src, record[0][1]))
+ elif not isPathInsideBase(record[1][0]):
+ raise ReftestFilepathError("Manifest Error in %s: "
+ "Reftest test replath %s not within relpath root." \
+ % (src, record[1][0]))
+ elif not isPathInsideBase(record[1][1]):
+ raise ReftestFilepathError("Manifest Error in %s: "
+ "Reftest test replath %s not within relpath root." \
+ % (src, record[1][1]))
+ yield record
+
+import Utils # set up XML catalog
+xhtmlns = '{http://www.w3.org/1999/xhtml}'
+svgns = '{http://www.w3.org/2000/svg}'
+xmlns = '{http://www.w3.org/XML/1998/namespace}'
+xlinkns = '{http://www.w3.org/1999/xlink}'
+
+class XMLSource(FileSource):
+ """FileSource object with support reading XML trees."""
+
+ NodeTuple = collections.namedtuple('NodeTuple', ['next', 'prev', 'reference', 'notReference'])
+
+ # Public Data
+ syntaxErrorDoc = \
+ u"""
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head><title>Syntax Error</title></head>
+ <body>
+ <p>The XML file <![CDATA[%s]]> contains a syntax error and could not be parsed.
+ Please correct it and try again.</p>
+ <p>The parser's error report was:</p>
+ <pre><![CDATA[%s]]></pre>
+ </body>
+ </html>
+ """
+
+ # Private Data and Methods
+ __parser = etree.XMLParser(no_network=True,
+ # perf nightmare dtd_validation=True,
+ remove_comments=False,
+ strip_cdata=False,
+ resolve_entities=False)
+
+ # Public Methods
+
+ def __init__(self, sourceTree, sourcepath, relpath, data = None):
+ """Initialize XMLSource by loading from XML file `sourcepath`.
+ Parse errors are reported in `self.errors`,
+ and the source is replaced with an XHTML error message.
+ """
+ FileSource.__init__(self, sourceTree, sourcepath, relpath, data = data)
+ self.tree = None
+ self.injectedTags = {}
+
+ def cacheAsParseError(self, filename, e):
+ """Replace document with an error message."""
+ errorDoc = self.syntaxErrorDoc % (filename, e)
+ from StringIO import StringIO
+ self.tree = etree.parse(StringIO(errorDoc), parser=self.__parser)
+
+ def parse(self):
+ """Parse file and store any parse errors in self.errors"""
+ self.errors = None
+ try:
+ data = self.data()
+ if (data):
+ self.tree = etree.parse(StringReader(data), parser=self.__parser)
+ self.encoding = self.tree.docinfo.encoding or 'utf-8'
+ self.injectedTags = {}
+ else:
+ self.tree = None
+ self.errors = ['Empty source file']
+ self.encoding = 'utf-8'
+
+ FileSource.loadMetadata(self)
+ if ((not self.metadata) and self.tree and (not self.errors)):
+ self.extractMetadata(self.tree)
+ except etree.ParseError as e:
+ print("PARSE ERROR: " + self.sourcepath)
+ self.cacheAsParseError(self.sourcepath, e)
+ e.W3CTestLibErrorLocation = self.sourcepath
+ self.errors = [str(e)]
+ self.encoding = 'utf-8'
+
+ def validate(self):
+ """Parse file if not parsed, and store any parse errors in self.errors"""
+ if self.tree is None:
+ self.parse()
+
+ def getMeatdataContainer(self):
+ return self.tree.getroot().find(xhtmlns+'head')
+
+ def injectMetadataLink(self, rel, href, tagCode = None):
+ """Inject (prepend) <link> with data given inside metadata container.
+ Injected element is tagged with `tagCode`, which can be
+ used to clear it with clearInjectedTags later.
+ """
+ self.validate()
+ container = self.getMeatdataContainer()
+ if (container):
+ node = etree.Element(xhtmlns+'link', {'rel': rel, 'href': href})
+ node.tail = container.text
+ container.insert(0, node)
+ self.injectedTags[node] = tagCode or True
+ return node
+ return None
+
+ def clearInjectedTags(self, tagCode = None):
+ """Clears all injected elements from the tree, or clears injected
+ elements tagged with `tagCode` if `tagCode` is given.
+ """
+ if not self.injectedTags or not self.tree: return
+ for node in self.injectedTags:
+ node.getparent().remove(node)
+ del self.injectedTags[node]
+
+ def serializeXML(self):
+ self.validate()
+ return etree.tounicode(self.tree)
+
+ def data(self):
+ if ((not self.tree) or (self.metaSource)):
+ return FileSource.data(self)
+ return self.serializeXML().encode(self.encoding, 'xmlcharrefreplace')
+
+ def unicode(self):
+ if ((not self.tree) or (self.metaSource)):
+ return FileSource.unicode(self)
+ return self.serializeXML()
+
+ def write(self, format, output=None):
+ """Write Source through OutputFormat `format`.
+ Write contents as string `output` instead if specified.
+ """
+ if not output:
+ output = self.unicode()
+
+ # write
+ with open(format.dest(self.relpath), 'w') as f:
+ f.write(output.encode(self.encoding, 'xmlcharrefreplace'))
+
+ def compact(self):
+ self.tree = None
+
+ def getMetadataElements(self, tree):
+ container = self.getMeatdataContainer()
+ if (None != container):
+ return [node for node in container]
+ return None
+
+ def extractMetadata(self, tree):
+ """Extract metadata from tree."""
+ links = []; credits = []; reviewers = []; flags = []; asserts = []; title = ''
+
+ def tokenMatch(token, string):
+ return bool(re.search('(^|\s+)%s($|\s+)' % token, string)) if (string) else False
+
+ errors = []
+ readFlags = False
+ metaElements = self.getMetadataElements(tree)
+ if (not metaElements):
+ errors.append("Missing <head> element")
+ else:
+ # Scan and cache metadata
+ for node in metaElements:
+ if (node.tag == xhtmlns+'link'):
+ # help links
+ if tokenMatch('help', node.get('rel')):
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Help link missing href value.", node.sourceline))
+ elif (not (link.startswith('http://') or link.startswith('https://'))):
+ errors.append(LineString("Help link " + link.encode('utf-8') + " must be absolute URL.", node.sourceline))
+ elif (link in links):
+ errors.append(LineString("Duplicate help link " + link.encode('utf-8') + ".", node.sourceline))
+ else:
+ links.append(LineString(link, node.sourceline))
+ # == references
+ elif tokenMatch('match', node.get('rel')) or tokenMatch('reference', node.get('rel')):
+ refPath = node.get('href').strip() if node.get('href') else None
+ if (not refPath):
+ errors.append(LineString("Reference link missing href value.", node.sourceline))
+ else:
+ refName = self.sourceTree.getAssetName(join(self.sourcepath, refPath))
+ if (refName in self.refs):
+ errors.append(LineString("Reference " + refName.encode('utf-8') + " already specified.", node.sourceline))
+ else:
+ self.refs[refName] = ('==', refPath, node, None)
+ # != references
+ elif tokenMatch('mismatch', node.get('rel')) or tokenMatch('not-reference', node.get('rel')):
+ refPath = node.get('href').strip() if node.get('href') else None
+ if (not refPath):
+ errors.append(LineString("Reference link missing href value.", node.sourceline))
+ else:
+ refName = self.sourceTree.getAssetName(join(self.sourcepath, refPath))
+ if (refName in self.refs):
+ errors.append(LineString("Reference " + refName.encode('utf-8') + " already specified.", node.sourceline))
+ else:
+ self.refs[refName] = ('!=', refPath, node, None)
+ else: # may have both author and reviewer in the same link
+ # credits
+ if tokenMatch('author', node.get('rel')):
+ name = node.get('title')
+ name = name.strip() if name else name
+ if (not name):
+ errors.append(LineString("Author link missing name (title attribute).", node.sourceline))
+ else:
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Author link for \"" + name.encode('utf-8') + "\" missing contact URL (http or mailto).", node.sourceline))
+ else:
+ credits.append((name, link))
+ # reviewers
+ if tokenMatch('reviewer', node.get('rel')):
+ name = node.get('title')
+ name = name.strip() if name else name
+ if (not name):
+ errors.append(LineString("Reviewer link missing name (title attribute).", node.sourceline))
+ else:
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Reviewer link for \"" + name.encode('utf-8') + "\" missing contact URL (http or mailto).", node.sourceline))
+ else:
+ reviewers.append((name, link))
+ elif (node.tag == xhtmlns+'meta'):
+ metatype = node.get('name')
+ metatype = metatype.strip() if metatype else metatype
+ # requirement flags
+ if ('flags' == metatype):
+ if (readFlags):
+ errors.append(LineString("Flags must only be specified once.", node.sourceline))
+ else:
+ readFlags = True
+ if (None == node.get('content')):
+ errors.append(LineString("Flags meta missing content attribute.", node.sourceline))
+ else:
+ for flag in sorted(node.get('content').split()):
+ flags.append(flag)
+ # test assertions
+ elif ('assert' == metatype):
+ if (None == node.get('content')):
+ errors.append(LineString("Assert meta missing content attribute.", node.sourceline))
+ else:
+ asserts.append(node.get('content').strip().replace('\t', ' '))
+ # title
+ elif (node.tag == xhtmlns+'title'):
+ title = node.text.strip() if node.text else ''
+ match = re.match('(?:[^:]*)[tT]est(?:[^:]*):(.*)', title, re.DOTALL)
+ if (match):
+ title = match.group(1)
+ title = title.strip()
+ # script
+ elif (node.tag == xhtmlns+'script'):
+ src = node.get('src').strip() if node.get('src') else None
+ if (src):
+ self.scripts[src] = node
+
+ if (asserts or credits or reviewers or flags or links or title):
+ self.metadata = {'asserts' : asserts,
+ 'credits' : credits,
+ 'reviewers' : reviewers,
+ 'flags' : flags,
+ 'links' : links,
+ 'title' : title
+ }
+
+ if (errors):
+ if (self.errors):
+ self.errors += errors
+ else:
+ self.errors = errors
+
+
+ def augmentMetadata(self, next=None, prev=None, reference=None, notReference=None):
+ """Add extra useful metadata to the head. All arguments are optional.
+ * Adds next/prev links to next/prev Sources given
+ * Adds reference link to reference Source given
+ """
+ self.validate()
+ if next:
+ next = self.injectMetadataLink('next', self.relativeURL(next), 'next')
+ if prev:
+ prev = self.injectMetadataLink('prev', self.relativeURL(prev), 'prev')
+ if reference:
+ reference = self.injectMetadataLink('match', self.relativeURL(reference), 'ref')
+ if notReference:
+ notReference = self.injectMetadataLink('mismatch', self.relativeURL(notReference), 'not-ref')
+ return self.NodeTuple(next, prev, reference, notReference)
+
+
+class XHTMLSource(XMLSource):
+ """FileSource object with support for XHTML->HTML conversions."""
+
+ # Public Methods
+
+ def __init__(self, sourceTree, sourcepath, relpath, data = None):
+ """Initialize XHTMLSource by loading from XHTML file `sourcepath`.
+ Parse errors are stored in `self.errors`,
+ and the source is replaced with an XHTML error message.
+ """
+ XMLSource.__init__(self, sourceTree, sourcepath, relpath, data = data)
+
+ def serializeXHTML(self, doctype = None):
+ return self.serializeXML()
+
+ def serializeHTML(self, doctype = None):
+ self.validate()
+ # Serialize
+# print self.relpath
+ serializer = HTMLSerializer.HTMLSerializer()
+ output = serializer.serializeHTML(self.tree, doctype)
+ return output
+
+
+class SVGSource(XMLSource):
+ """FileSource object with support for extracting metadata from SVG."""
+
+ def __init__(self, sourceTree, sourcepath, relpath, data = None):
+ """Initialize SVGSource by loading from SVG file `sourcepath`.
+ Parse errors are stored in `self.errors`,
+ and the source is replaced with an XHTML error message.
+ """
+ XMLSource.__init__(self, sourceTree, sourcepath, relpath, data = data)
+
+ def getMeatdataContainer(self):
+ groups = self.tree.getroot().findall(svgns+'g')
+ for group in groups:
+ if ('testmeta' == group.get('id')):
+ return group
+ return None
+
+ def extractMetadata(self, tree):
+ """Extract metadata from tree."""
+ links = []; credits = []; reviewers = []; flags = []; asserts = []; title = ''
+
+ def tokenMatch(token, string):
+ return bool(re.search('(^|\s+)%s($|\s+)' % token, string)) if (string) else False
+
+ errors = []
+ readFlags = False
+ metaElements = self.getMetadataElements(tree)
+ if (not metaElements):
+ errors.append("Missing <g id='testmeta'> element")
+ else:
+ # Scan and cache metadata
+ for node in metaElements:
+ if (node.tag == xhtmlns+'link'):
+ # help links
+ if tokenMatch('help', node.get('rel')):
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Help link missing href value.", node.sourceline))
+ elif (not (link.startswith('http://') or link.startswith('https://'))):
+ errors.append(LineString("Help link " + link.encode('utf-8') + " must be absolute URL.", node.sourceline))
+ elif (link in links):
+ errors.append(LineString("Duplicate help link " + link.encode('utf-8') + ".", node.sourceline))
+ else:
+ links.append(LineString(link, node.sourceline))
+ # == references
+ elif tokenMatch('match', node.get('rel')) or tokenMatch('reference', node.get('rel')):
+ refPath = node.get('href').strip() if node.get('href') else None
+ if (not refPath):
+ errors.append(LineString("Reference link missing href value.", node.sourceline))
+ else:
+ refName = self.sourceTree.getAssetName(join(self.sourcepath, refPath))
+ if (refName in self.refs):
+ errors.append(LineString("Reference " + refName.encode('utf-8') + " already specified.", node.sourceline))
+ else:
+ self.refs[refName] = ('==', refPath, node, None)
+ # != references
+ elif tokenMatch('mismatch', node.get('rel')) or tokenMatch('not-reference', node.get('rel')):
+ refPath = node.get('href').strip() if node.get('href') else None
+ if (not refPath):
+ errors.append(LineString("Reference link missing href value.", node.sourceline))
+ else:
+ refName = self.sourceTree.getAssetName(join(self.sourcepath, refPath))
+ if (refName in self.refs):
+ errors.append(LineString("Reference " + refName.encode('utf-8') + " already specified.", node.sourceline))
+ else:
+ self.refs[refName] = ('!=', refPath, node, None)
+ else: # may have both author and reviewer in the same link
+ # credits
+ if tokenMatch('author', node.get('rel')):
+ name = node.get('title')
+ name = name.strip() if name else name
+ if (not name):
+ errors.append(LineString("Author link missing name (title attribute).", node.sourceline))
+ else:
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Author link for \"" + name.encode('utf-8') + "\" missing contact URL (http or mailto).", node.sourceline))
+ else:
+ credits.append((name, link))
+ # reviewers
+ if tokenMatch('reviewer', node.get('rel')):
+ name = node.get('title')
+ name = name.strip() if name else name
+ if (not name):
+ errors.append(LineString("Reviewer link missing name (title attribute).", node.sourceline))
+ else:
+ link = node.get('href').strip() if node.get('href') else None
+ if (not link):
+ errors.append(LineString("Reviewer link for \"" + name.encode('utf-8') + "\" missing contact URL (http or mailto).", node.sourceline))
+ else:
+ reviewers.append((name, link))
+ elif (node.tag == svgns+'metadata'):
+ metatype = node.get('class')
+ metatype = metatype.strip() if metatype else metatype
+ # requirement flags
+ if ('flags' == metatype):
+ if (readFlags):
+ errors.append(LineString("Flags must only be specified once.", node.sourceline))
+ else:
+ readFlags = True
+ text = node.find(svgns+'text')
+ flagString = text.text if (text) else node.text
+ if (flagString):
+ for flag in sorted(flagString.split()):
+ flags.append(flag)
+ elif (node.tag == svgns+'desc'):
+ metatype = node.get('class')
+ metatype = metatype.strip() if metatype else metatype
+ # test assertions
+ if ('assert' == metatype):
+ asserts.append(node.text.strip().replace('\t', ' '))
+ # test title
+ elif node.tag == svgns+'title':
+ title = node.text.strip() if node.text else ''
+ match = re.match('(?:[^:]*)[tT]est(?:[^:]*):(.*)', title, re.DOTALL)
+ if (match):
+ title = match.group(1)
+ title = title.strip()
+ # script tag (XXX restricted to metadata container?)
+ elif (node.tag == svgns+'script'):
+ src = node.get('src').strip() if node.get('src') else None
+ if (src):
+ self.scripts[src] = node
+
+ if (asserts or credits or reviewers or flags or links or title):
+ self.metadata = {'asserts' : asserts,
+ 'credits' : credits,
+ 'reviewers' : reviewers,
+ 'flags' : flags,
+ 'links' : links,
+ 'title' : title
+ }
+ if (errors):
+ if (self.errors):
+ self.errors += errors
+ else:
+ self.errors = errors
+
+
+
+class HTMLSource(XMLSource):
+ """FileSource object with support for HTML metadata and HTML->XHTML conversions (untested)."""
+
+ # Private Data and Methods
+ __parser = html5lib.HTMLParser(tree = treebuilders.getTreeBuilder('lxml'))
+
+ # Public Methods
+
+ def __init__(self, sourceTree, sourcepath, relpath, data = None):
+ """Initialize HTMLSource by loading from HTML file `sourcepath`.
+ """
+ XMLSource.__init__(self, sourceTree, sourcepath, relpath, data = data)
+
+ def parse(self):
+ """Parse file and store any parse errors in self.errors"""
+ self.errors = None
+ try:
+ data = self.data()
+ if data:
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ self.tree = self.__parser.parse(data)
+ self.encoding = self.__parser.documentEncoding
+ self.injectedTags = {}
+ else:
+ self.tree = None
+ self.errors = ['Empty source file']
+ self.encoding = 'utf-8'
+
+ FileSource.loadMetadata(self)
+ if ((not self.metadata) and self.tree and (not self.errors)):
+ self.extractMetadata(self.tree)
+ except Exception as e:
+ print("PARSE ERROR: " + self.sourcepath)
+ e.W3CTestLibErrorLocation = self.sourcepath
+ self.errors = [str(e)]
+ self.encoding = 'utf-8'
+
+ def _injectXLinks(self, element, nodeList):
+ injected = False
+
+ xlinkAttrs = ['href', 'type', 'role', 'arcrole', 'title', 'show', 'actuate']
+ if (element.get('href') or element.get(xlinkns + 'href')):
+ for attr in xlinkAttrs:
+ if (element.get(xlinkns + attr)):
+ injected = True
+ if (element.get(attr)):
+ injected = True
+ value = element.get(attr)
+ del element.attrib[attr]
+ element.set(xlinkns + attr, value)
+ nodeList.append((element, xlinkns + attr, attr))
+
+ for child in element:
+ if (type(child.tag) == type('')): # element node
+ qName = etree.QName(child.tag)
+ if ('foreignobject' != qName.localname.lower()):
+ injected |= self._injectXLinks(child, nodeList)
+ return injected
+
+
+ def _findElements(self, namespace, elementName):
+ elements = self.tree.findall('.//{' + namespace + '}' + elementName)
+ if (self.tree.getroot().tag == '{' + namespace + '}' + elementName):
+ elements.insert(0, self.tree.getroot())
+ return elements
+
+ def _injectNamespace(self, elementName, prefix, namespace, doXLinks, nodeList):
+ attr = xmlns + prefix if (prefix) else 'xmlns'
+ elements = self._findElements(namespace, elementName)
+ for element in elements:
+ if not element.get(attr):
+ element.set(attr, namespace)
+ nodeList.append((element, attr, None))
+ if (doXLinks):
+ if (self._injectXLinks(element, nodeList)):
+ element.set(xmlns + 'xlink', 'http://www.w3.org/1999/xlink')
+ nodeList.append((element, xmlns + 'xlink', None))
+
+ def injectNamespaces(self):
+ nodeList = []
+ self._injectNamespace('html', None, 'http://www.w3.org/1999/xhtml', False, nodeList)
+ self._injectNamespace('svg', None, 'http://www.w3.org/2000/svg', True, nodeList)
+ self._injectNamespace('math', None, 'http://www.w3.org/1998/Math/MathML', True, nodeList)
+ return nodeList
+
+ def removeNamespaces(self, nodeList):
+ if nodeList:
+ for element, attr, oldAttr in nodeList:
+ if (oldAttr):
+ value = element.get(attr)
+ del element.attrib[attr]
+ element.set(oldAttr, value)
+ else:
+ del element.attrib[attr]
+
+ def serializeXHTML(self, doctype = None):
+ self.validate()
+ # Serialize
+ nodeList = self.injectNamespaces()
+# print self.relpath
+ serializer = HTMLSerializer.HTMLSerializer()
+ o = serializer.serializeXHTML(self.tree, doctype)
+
+ self.removeNamespaces(nodeList)
+ return o
+
+ def serializeHTML(self, doctype = None):
+ self.validate()
+ # Serialize
+# print self.relpath
+ serializer = HTMLSerializer.HTMLSerializer()
+ o = serializer.serializeHTML(self.tree, doctype)
+
+ return o
+
+ def data(self):
+ if ((not self.tree) or (self.metaSource)):
+ return FileSource.data(self)
+ return self.serializeHTML().encode(self.encoding, 'xmlcharrefreplace')
+
+ def unicode(self):
+ if ((not self.tree) or (self.metaSource)):
+ return FileSource.unicode(self)
+ return self.serializeHTML()
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/Suite.py b/testing/web-platform/tests/css/tools/w3ctestlib/Suite.py
new file mode 100644
index 0000000000..c5fa03a155
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/Suite.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+# CSS Test Suite Manipulation Library
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+import OutputFormats
+import Utils
+from Groups import TestGroup, excludeDirs
+from Sources import SourceTree, SourceCache
+from shutil import copytree, rmtree
+from os.path import join
+import os
+from mercurial import ui as UserInterface, hg
+
+class TestSuite:
+ """Representation of a standard CSS test suite."""
+
+ def __init__(self, name, title, specUri, draftUri, sourceCache = None, ui = None):
+ self.name = name
+ self.title = title
+ self.specroot = specUri
+ self.draftroot = draftUri
+
+ self.ui = ui if ui else UserInterface.ui()
+ self.defaultReftestRelpath='reftest.list'
+ self.groups = {}
+ self.sourcecache = sourceCache if sourceCache else SourceCache(SourceTree(hg.repository(self.ui, '.')))
+ self.formats = ('html4', 'xhtml1', 'xhtml1print') # XXX FIXME, hardcoded list is lame
+ self.rawgroups = {}
+
+ def addTestsByExt(self, dir, ext, groupName='', groupTitle=''):
+ """Add tests from directory `dir` by file extension (via `ext`, e.g. ext='.xht').
+ """
+ group = TestGroup(self.sourcecache, dir, selfTestExt=ext,
+ name=groupName, title=groupTitle, ui = self.ui)
+ self.addGroup(group)
+
+
+ def addTestsByList(self, dir, filenames, groupName='', groupTitle=''):
+ """Add tests from directory `dir`, via file name list `filenames`.
+ """
+ group = TestGroup(self.sourcecache, dir, selfTestList=filenames,
+ name=groupName, title=groupTitle, ui = self.ui)
+ self.addGroup(group)
+
+ def addReftests(self, dir, manifestPath, groupName='', groupTitle=''):
+ """Add tests by importing context of directory `dir` and importing all
+ tests listed in the `reftestManifestName` manifest inside `dir`.
+ """
+ group = TestGroup(self.sourcecache,
+ dir, manifestPath=manifestPath,
+ manifestDest=self.defaultReftestRelpath,
+ name=groupName, title=groupTitle, ui = self.ui)
+ self.addGroup(group)
+
+ def addGroup(self, group):
+ """ Add CSSTestGroup `group` to store. """
+ master = self.groups.get(group.name)
+ if master:
+ master.merge(group)
+ else:
+ self.groups[group.name] = group
+
+ def addRaw(self, dir, relpath):
+ """Add the contents of directory `dir` to the test suite by copying
+ (not processing). Note this means such tests will not be indexed.
+ `relpath` gives the directory's path within the build destination.
+ """
+ self.rawgroups[dir] = relpath
+
+ def setFormats(self, formats):
+ self.formats = formats
+
+ def buildInto(self, dest, indexer):
+ """Builds test suite through all OutputFormats into directory at path `dest`
+ or through OutputFormat destination `dest`, using Indexer `indexer`.
+ """
+ if isinstance(dest, OutputFormats.BasicFormat):
+ formats = (dest,)
+ dest = dest.root
+ else:
+ formats = []
+ for format in self.formats:
+ if (format == 'html4'):
+ formats.append(OutputFormats.HTMLFormat(dest, self.sourcecache.sourceTree))
+ elif (format == 'html5'):
+ formats.append(OutputFormats.HTML5Format(dest, self.sourcecache.sourceTree))
+ elif (format == 'xhtml1'):
+ formats.append(OutputFormats.XHTMLFormat(dest, self.sourcecache.sourceTree))
+ elif (format == 'xhtml1print'):
+ formats.append(OutputFormats.XHTMLPrintFormat(dest, self.sourcecache.sourceTree, self.title))
+ elif (format == 'svg'):
+ formats.append(OutputFormats.SVGFormat(dest, self.sourcecache.sourceTree))
+
+ for format in formats:
+ for group in self.groups.itervalues():
+ group.build(format)
+
+ for group in self.groups.itervalues():
+ indexer.indexGroup(group)
+
+ for format in formats:
+ indexer.writeIndex(format)
+
+
+ rawtests = []
+ for src, relpath in self.rawgroups.items():
+ copytree(src, join(dest,relpath))
+ for (root, dirs, files) in os.walk(join(dest,relpath)):
+ for xdir in excludeDirs:
+ if xdir in dirs:
+ dirs.remove(xdir)
+ rmtree(join(root,xdir))
+ rawtests.extend(
+ [join(Utils.relpath(root,dest),file)
+ for file in files]
+ )
+
+ rawtests.sort()
+ indexer.writeOverview(dest, addTests=rawtests)
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/Utils.py b/testing/web-platform/tests/css/tools/w3ctestlib/Utils.py
new file mode 100644
index 0000000000..065c30491c
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/Utils.py
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+# CSS Test Suite Manipulation Library Utilities
+# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
+# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
+
+###### XML Parsing ######
+
+import os
+import w3ctestlib
+os.environ['XML_CATALOG_FILES'] = os.path.join(w3ctestlib.__path__[0], 'catalog/catalog.xml')
+
+###### File path manipulation ######
+
+import os.path
+from os.path import sep, pardir
+
+def assetName(path):
+ return intern(os.path.splitext(os.path.basename(path))[0].lower().encode('ascii'))
+
+def basepath(path):
+ """ Returns the path part of os.path.split.
+ """
+ return os.path.dirname(path)
+
+def isPathInsideBase(path, base=''):
+ path = os.path.normpath(path)
+ if base:
+ base = os.path.normpath(base)
+ pathlist = path.split(os.path.sep)
+ baselist = base.split(os.path.sep)
+ while baselist:
+ p = pathlist.pop(0)
+ b = baselist.pop(0)
+ if p != b:
+ return False
+ return not pathlist[0].startswith(os.path.pardir)
+ return not path.startswith(os.path.pardir)
+
+def relpath(path, start):
+ """Return relative path from start to end. WARNING: this is not the
+ same as a relative URL; see relativeURL()."""
+ try:
+ return os.path.relpath(path, start)
+ except AttributeError:
+ # This function is copied directly from the Python 2.6 source
+ # code, and is therefore under a different license.
+
+ if not path:
+ raise ValueError("no path specified")
+ start_list = os.path.abspath(start).split(sep)
+ path_list = os.path.abspath(path).split(sep)
+ if start_list[0].lower() != path_list[0].lower():
+ unc_path, rest = os.path.splitunc(path)
+ unc_start, rest = os.path.splitunc(start)
+ if bool(unc_path) ^ bool(unc_start):
+ raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
+ % (path, start))
+ else:
+ raise ValueError("path is on drive %s, start on drive %s"
+ % (path_list[0], start_list[0]))
+ # Work out how much of the filepath is shared by start and path.
+ for i in range(min(len(start_list), len(path_list))):
+ if start_list[i].lower() != path_list[i].lower():
+ break
+ else:
+ i += 1
+
+ rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return os.path.curdir
+ return os.path.join(*rel_list)
+
+def relativeURL(start, end):
+ """ Returns relative URL from `start` to `end`.
+ """
+# if isPathInsideBase(end, start):
+# return relpath(end, start)
+# else:
+ return relpath(end, basepath(start))
+
+def listfiles(path, ext = None):
+ """ Returns a list of all files in a directory.
+ Optionally lists only files with a given extension.
+ """
+ try:
+ _,_,files = os.walk(path).next()
+ if (ext):
+ files = [fileName for fileName in files if fileName.endswith(ext)]
+ except StopIteration:
+ files = []
+ return files
+
+def listdirs(path):
+ """ Returns a list of all subdirectories in a directory.
+ """
+ try:
+ _,dirs,_ = os.walk(path).next()
+ except StopIteration:
+ dirs = []
+ return dirs
+
+###### MIME types and file extensions ######
+
+extensionMap = { None : 'application/octet-stream', # default
+ '.xht' : 'application/xhtml+xml',
+ '.xhtml' : 'application/xhtml+xml',
+ '.xml' : 'application/xml',
+ '.htm' : 'text/html',
+ '.html' : 'text/html',
+ '.txt' : 'text/plain',
+ '.jpg' : 'image/jpeg',
+ '.png' : 'image/png',
+ '.svg' : 'image/svg+xml',
+ }
+
+def getMimeFromExt(filepath):
+ """Convenience function: equal to extenionMap.get(ext, extensionMap[None]).
+ """
+ if filepath.endswith('.htaccess'):
+ return 'config/htaccess'
+ ext = os.path.splitext(filepath)[1]
+ return extensionMap.get(ext, extensionMap[None])
+
+###### Escaping ######
+
+import types
+from htmlentitydefs import entitydefs
+
+entityify = dict([c,e] for e,c in entitydefs.iteritems())
+
+def escapeMarkup(data):
+ """Escape markup characters (&, >, <). Copied from xml.sax.saxutils.
+ """
+ # must do ampersand first
+ data = data.replace("&", "&amp;")
+ data = data.replace(">", "&gt;")
+ data = data.replace("<", "&lt;")
+ return data
+
+def escapeToNamedASCII(text):
+ """Escapes to named entities where possible and numeric-escapes non-ASCII
+ """
+ return escapeToNamed(text).encode('ascii', 'xmlcharrefreplace')
+
+def escapeToNamed(text):
+ """Escape characters with named entities.
+ """
+ escapable = set()
+
+ for c in text:
+ if ord(c) > 127:
+ escapable.add(c)
+ if type(text) == types.UnicodeType:
+ for c in escapable:
+ cLatin = c.encode('Latin-1', 'ignore')
+ if (cLatin in entityify):
+ text = text.replace(c, "&%s;" % entityify[cLatin])
+ else:
+ for c in escapable:
+ text = text.replace(c, "&%s;" % entityify[c])
+ return text
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/__init__.py b/testing/web-platform/tests/css/tools/w3ctestlib/__init__.py
new file mode 100644
index 0000000000..8ce9f985c3
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/__init__.py
@@ -0,0 +1,3 @@
+
+
+__all__ = ['Sources', 'Groups', 'Indexer', 'Suite', 'OutputFormats', 'HTMLSerializer'] \ No newline at end of file
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/catalog.xml b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/catalog.xml
new file mode 100644
index 0000000000..d9c5926235
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/catalog.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!-- <!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.0//EN" "file:///usr/share/xml/schema/xml-core/catalog.dtd"> -->
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+ <group prefer="public">
+ <public
+ publicId="-//W3C//DTD XHTML 1.1//EN"
+ uri="xhtml11.dtd"/>
+ <public
+ publicId="-//W3C//DTD XHTML 1.0 Strict//EN"
+ uri="xhtml1-strict.dtd"/>
+ <public
+ publicId="-//W3C//DTD XHTML 1.0 Transitional//EN"
+ uri="xhtml1-transitional.dtd"/>
+ <public
+ publicId="-//W3C//DTD XHTML 1.0 Frameset//EN"
+ uri="xhtml1-frameset.dtd"/>
+ <public
+ publicId="-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ uri="xhtml-lat1.ent"/>
+ <public
+ publicId="-//W3C//ENTITIES Special for XHTML//EN"
+ uri="xhtml-special.ent"/>
+ <public
+ publicId="-//W3C//ENTITIES Symbols for XHTML//EN"
+ uri="xhtml-special.ent"/>
+ </group>
+</catalog>
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-lat1.ent b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-lat1.ent
new file mode 100644
index 0000000000..ffee223eb1
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-lat1.ent
@@ -0,0 +1,196 @@
+<!-- Portions (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
+ %HTMLlat1;
+-->
+
+<!ENTITY nbsp "&#160;"> <!-- no-break space = non-breaking space,
+ U+00A0 ISOnum -->
+<!ENTITY iexcl "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
+<!ENTITY cent "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
+<!ENTITY pound "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
+<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
+<!ENTITY yen "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
+<!ENTITY brvbar "&#166;"> <!-- broken bar = broken vertical bar,
+ U+00A6 ISOnum -->
+<!ENTITY sect "&#167;"> <!-- section sign, U+00A7 ISOnum -->
+<!ENTITY uml "&#168;"> <!-- diaeresis = spacing diaeresis,
+ U+00A8 ISOdia -->
+<!ENTITY copy "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
+<!ENTITY ordf "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
+<!ENTITY laquo "&#171;"> <!-- left-pointing double angle quotation mark
+ = left pointing guillemet, U+00AB ISOnum -->
+<!ENTITY not "&#172;"> <!-- not sign = angled dash,
+ U+00AC ISOnum -->
+<!ENTITY shy "&#173;"> <!-- soft hyphen = discretionary hyphen,
+ U+00AD ISOnum -->
+<!ENTITY reg "&#174;"> <!-- registered sign = registered trade mark sign,
+ U+00AE ISOnum -->
+<!ENTITY macr "&#175;"> <!-- macron = spacing macron = overline
+ = APL overbar, U+00AF ISOdia -->
+<!ENTITY deg "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
+<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign,
+ U+00B1 ISOnum -->
+<!ENTITY sup2 "&#178;"> <!-- superscript two = superscript digit two
+ = squared, U+00B2 ISOnum -->
+<!ENTITY sup3 "&#179;"> <!-- superscript three = superscript digit three
+ = cubed, U+00B3 ISOnum -->
+<!ENTITY acute "&#180;"> <!-- acute accent = spacing acute,
+ U+00B4 ISOdia -->
+<!ENTITY micro "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
+<!ENTITY para "&#182;"> <!-- pilcrow sign = paragraph sign,
+ U+00B6 ISOnum -->
+<!ENTITY middot "&#183;"> <!-- middle dot = Georgian comma
+ = Greek middle dot, U+00B7 ISOnum -->
+<!ENTITY cedil "&#184;"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
+<!ENTITY sup1 "&#185;"> <!-- superscript one = superscript digit one,
+ U+00B9 ISOnum -->
+<!ENTITY ordm "&#186;"> <!-- masculine ordinal indicator,
+ U+00BA ISOnum -->
+<!ENTITY raquo "&#187;"> <!-- right-pointing double angle quotation mark
+ = right pointing guillemet, U+00BB ISOnum -->
+<!ENTITY frac14 "&#188;"> <!-- vulgar fraction one quarter
+ = fraction one quarter, U+00BC ISOnum -->
+<!ENTITY frac12 "&#189;"> <!-- vulgar fraction one half
+ = fraction one half, U+00BD ISOnum -->
+<!ENTITY frac34 "&#190;"> <!-- vulgar fraction three quarters
+ = fraction three quarters, U+00BE ISOnum -->
+<!ENTITY iquest "&#191;"> <!-- inverted question mark
+ = turned question mark, U+00BF ISOnum -->
+<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave
+ = latin capital letter A grave,
+ U+00C0 ISOlat1 -->
+<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute,
+ U+00C1 ISOlat1 -->
+<!ENTITY Acirc "&#194;"> <!-- latin capital letter A with circumflex,
+ U+00C2 ISOlat1 -->
+<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde,
+ U+00C3 ISOlat1 -->
+<!ENTITY Auml "&#196;"> <!-- latin capital letter A with diaeresis,
+ U+00C4 ISOlat1 -->
+<!ENTITY Aring "&#197;"> <!-- latin capital letter A with ring above
+ = latin capital letter A ring,
+ U+00C5 ISOlat1 -->
+<!ENTITY AElig "&#198;"> <!-- latin capital letter AE
+ = latin capital ligature AE,
+ U+00C6 ISOlat1 -->
+<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla,
+ U+00C7 ISOlat1 -->
+<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave,
+ U+00C8 ISOlat1 -->
+<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute,
+ U+00C9 ISOlat1 -->
+<!ENTITY Ecirc "&#202;"> <!-- latin capital letter E with circumflex,
+ U+00CA ISOlat1 -->
+<!ENTITY Euml "&#203;"> <!-- latin capital letter E with diaeresis,
+ U+00CB ISOlat1 -->
+<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave,
+ U+00CC ISOlat1 -->
+<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute,
+ U+00CD ISOlat1 -->
+<!ENTITY Icirc "&#206;"> <!-- latin capital letter I with circumflex,
+ U+00CE ISOlat1 -->
+<!ENTITY Iuml "&#207;"> <!-- latin capital letter I with diaeresis,
+ U+00CF ISOlat1 -->
+<!ENTITY ETH "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
+<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde,
+ U+00D1 ISOlat1 -->
+<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave,
+ U+00D2 ISOlat1 -->
+<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute,
+ U+00D3 ISOlat1 -->
+<!ENTITY Ocirc "&#212;"> <!-- latin capital letter O with circumflex,
+ U+00D4 ISOlat1 -->
+<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde,
+ U+00D5 ISOlat1 -->
+<!ENTITY Ouml "&#214;"> <!-- latin capital letter O with diaeresis,
+ U+00D6 ISOlat1 -->
+<!ENTITY times "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
+<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke
+ = latin capital letter O slash,
+ U+00D8 ISOlat1 -->
+<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave,
+ U+00D9 ISOlat1 -->
+<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute,
+ U+00DA ISOlat1 -->
+<!ENTITY Ucirc "&#219;"> <!-- latin capital letter U with circumflex,
+ U+00DB ISOlat1 -->
+<!ENTITY Uuml "&#220;"> <!-- latin capital letter U with diaeresis,
+ U+00DC ISOlat1 -->
+<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute,
+ U+00DD ISOlat1 -->
+<!ENTITY THORN "&#222;"> <!-- latin capital letter THORN,
+ U+00DE ISOlat1 -->
+<!ENTITY szlig "&#223;"> <!-- latin small letter sharp s = ess-zed,
+ U+00DF ISOlat1 -->
+<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave
+ = latin small letter a grave,
+ U+00E0 ISOlat1 -->
+<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute,
+ U+00E1 ISOlat1 -->
+<!ENTITY acirc "&#226;"> <!-- latin small letter a with circumflex,
+ U+00E2 ISOlat1 -->
+<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde,
+ U+00E3 ISOlat1 -->
+<!ENTITY auml "&#228;"> <!-- latin small letter a with diaeresis,
+ U+00E4 ISOlat1 -->
+<!ENTITY aring "&#229;"> <!-- latin small letter a with ring above
+ = latin small letter a ring,
+ U+00E5 ISOlat1 -->
+<!ENTITY aelig "&#230;"> <!-- latin small letter ae
+ = latin small ligature ae, U+00E6 ISOlat1 -->
+<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla,
+ U+00E7 ISOlat1 -->
+<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave,
+ U+00E8 ISOlat1 -->
+<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute,
+ U+00E9 ISOlat1 -->
+<!ENTITY ecirc "&#234;"> <!-- latin small letter e with circumflex,
+ U+00EA ISOlat1 -->
+<!ENTITY euml "&#235;"> <!-- latin small letter e with diaeresis,
+ U+00EB ISOlat1 -->
+<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave,
+ U+00EC ISOlat1 -->
+<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute,
+ U+00ED ISOlat1 -->
+<!ENTITY icirc "&#238;"> <!-- latin small letter i with circumflex,
+ U+00EE ISOlat1 -->
+<!ENTITY iuml "&#239;"> <!-- latin small letter i with diaeresis,
+ U+00EF ISOlat1 -->
+<!ENTITY eth "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
+<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde,
+ U+00F1 ISOlat1 -->
+<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave,
+ U+00F2 ISOlat1 -->
+<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute,
+ U+00F3 ISOlat1 -->
+<!ENTITY ocirc "&#244;"> <!-- latin small letter o with circumflex,
+ U+00F4 ISOlat1 -->
+<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde,
+ U+00F5 ISOlat1 -->
+<!ENTITY ouml "&#246;"> <!-- latin small letter o with diaeresis,
+ U+00F6 ISOlat1 -->
+<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
+<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke,
+ = latin small letter o slash,
+ U+00F8 ISOlat1 -->
+<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave,
+ U+00F9 ISOlat1 -->
+<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute,
+ U+00FA ISOlat1 -->
+<!ENTITY ucirc "&#251;"> <!-- latin small letter u with circumflex,
+ U+00FB ISOlat1 -->
+<!ENTITY uuml "&#252;"> <!-- latin small letter u with diaeresis,
+ U+00FC ISOlat1 -->
+<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute,
+ U+00FD ISOlat1 -->
+<!ENTITY thorn "&#254;"> <!-- latin small letter thorn,
+ U+00FE ISOlat1 -->
+<!ENTITY yuml "&#255;"> <!-- latin small letter y with diaeresis,
+ U+00FF ISOlat1 -->
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-special.ent b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-special.ent
new file mode 100644
index 0000000000..ca358b2fec
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-special.ent
@@ -0,0 +1,80 @@
+<!-- Special characters for XHTML -->
+
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
+ %HTMLspecial;
+-->
+
+<!-- Portions (C) International Organization for Standardization 1986:
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+
+<!-- Relevant ISO entity set is given unless names are newly introduced.
+ New names (i.e., not in ISO 8879 list) do not clash with any
+ existing ISO 8879 entity names. ISO 10646 character numbers
+ are given for each character, in hex. values are decimal
+ conversions of the ISO 10646 values and refer to the document
+ character set. Names are Unicode names.
+-->
+
+<!-- C0 Controls and Basic Latin -->
+<!ENTITY quot "&#34;"> <!-- quotation mark, U+0022 ISOnum -->
+<!ENTITY amp "&#38;#38;"> <!-- ampersand, U+0026 ISOnum -->
+<!ENTITY lt "&#38;#60;"> <!-- less-than sign, U+003C ISOnum -->
+<!ENTITY gt "&#62;"> <!-- greater-than sign, U+003E ISOnum -->
+<!ENTITY apos "&#39;"> <!-- apostrophe = APL quote, U+0027 ISOnum -->
+
+<!-- Latin Extended-A -->
+<!ENTITY OElig "&#338;"> <!-- latin capital ligature OE,
+ U+0152 ISOlat2 -->
+<!ENTITY oelig "&#339;"> <!-- latin small ligature oe, U+0153 ISOlat2 -->
+<!-- ligature is a misnomer, this is a separate character in some languages -->
+<!ENTITY Scaron "&#352;"> <!-- latin capital letter S with caron,
+ U+0160 ISOlat2 -->
+<!ENTITY scaron "&#353;"> <!-- latin small letter s with caron,
+ U+0161 ISOlat2 -->
+<!ENTITY Yuml "&#376;"> <!-- latin capital letter Y with diaeresis,
+ U+0178 ISOlat2 -->
+
+<!-- Spacing Modifier Letters -->
+<!ENTITY circ "&#710;"> <!-- modifier letter circumflex accent,
+ U+02C6 ISOpub -->
+<!ENTITY tilde "&#732;"> <!-- small tilde, U+02DC ISOdia -->
+
+<!-- General Punctuation -->
+<!ENTITY ensp "&#8194;"> <!-- en space, U+2002 ISOpub -->
+<!ENTITY emsp "&#8195;"> <!-- em space, U+2003 ISOpub -->
+<!ENTITY thinsp "&#8201;"> <!-- thin space, U+2009 ISOpub -->
+<!ENTITY zwnj "&#8204;"> <!-- zero width non-joiner,
+ U+200C NEW RFC 2070 -->
+<!ENTITY zwj "&#8205;"> <!-- zero width joiner, U+200D NEW RFC 2070 -->
+<!ENTITY lrm "&#8206;"> <!-- left-to-right mark, U+200E NEW RFC 2070 -->
+<!ENTITY rlm "&#8207;"> <!-- right-to-left mark, U+200F NEW RFC 2070 -->
+<!ENTITY ndash "&#8211;"> <!-- en dash, U+2013 ISOpub -->
+<!ENTITY mdash "&#8212;"> <!-- em dash, U+2014 ISOpub -->
+<!ENTITY lsquo "&#8216;"> <!-- left single quotation mark,
+ U+2018 ISOnum -->
+<!ENTITY rsquo "&#8217;"> <!-- right single quotation mark,
+ U+2019 ISOnum -->
+<!ENTITY sbquo "&#8218;"> <!-- single low-9 quotation mark, U+201A NEW -->
+<!ENTITY ldquo "&#8220;"> <!-- left double quotation mark,
+ U+201C ISOnum -->
+<!ENTITY rdquo "&#8221;"> <!-- right double quotation mark,
+ U+201D ISOnum -->
+<!ENTITY bdquo "&#8222;"> <!-- double low-9 quotation mark, U+201E NEW -->
+<!ENTITY dagger "&#8224;"> <!-- dagger, U+2020 ISOpub -->
+<!ENTITY Dagger "&#8225;"> <!-- double dagger, U+2021 ISOpub -->
+<!ENTITY permil "&#8240;"> <!-- per mille sign, U+2030 ISOtech -->
+<!ENTITY lsaquo "&#8249;"> <!-- single left-pointing angle quotation mark,
+ U+2039 ISO proposed -->
+<!-- lsaquo is proposed but not yet ISO standardized -->
+<!ENTITY rsaquo "&#8250;"> <!-- single right-pointing angle quotation mark,
+ U+203A ISO proposed -->
+<!-- rsaquo is proposed but not yet ISO standardized -->
+
+<!-- Currency Symbols -->
+<!ENTITY euro "&#8364;"> <!-- euro sign, U+20AC NEW -->
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-symbol.ent b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-symbol.ent
new file mode 100644
index 0000000000..63c2abfa6f
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml-symbol.ent
@@ -0,0 +1,237 @@
+<!-- Mathematical, Greek and Symbolic characters for XHTML -->
+
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
+ %HTMLsymbol;
+-->
+
+<!-- Portions (C) International Organization for Standardization 1986:
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+
+<!-- Relevant ISO entity set is given unless names are newly introduced.
+ New names (i.e., not in ISO 8879 list) do not clash with any
+ existing ISO 8879 entity names. ISO 10646 character numbers
+ are given for each character, in hex. values are decimal
+ conversions of the ISO 10646 values and refer to the document
+ character set. Names are Unicode names.
+-->
+
+<!-- Latin Extended-B -->
+<!ENTITY fnof "&#402;"> <!-- latin small letter f with hook = function
+ = florin, U+0192 ISOtech -->
+
+<!-- Greek -->
+<!ENTITY Alpha "&#913;"> <!-- greek capital letter alpha, U+0391 -->
+<!ENTITY Beta "&#914;"> <!-- greek capital letter beta, U+0392 -->
+<!ENTITY Gamma "&#915;"> <!-- greek capital letter gamma,
+ U+0393 ISOgrk3 -->
+<!ENTITY Delta "&#916;"> <!-- greek capital letter delta,
+ U+0394 ISOgrk3 -->
+<!ENTITY Epsilon "&#917;"> <!-- greek capital letter epsilon, U+0395 -->
+<!ENTITY Zeta "&#918;"> <!-- greek capital letter zeta, U+0396 -->
+<!ENTITY Eta "&#919;"> <!-- greek capital letter eta, U+0397 -->
+<!ENTITY Theta "&#920;"> <!-- greek capital letter theta,
+ U+0398 ISOgrk3 -->
+<!ENTITY Iota "&#921;"> <!-- greek capital letter iota, U+0399 -->
+<!ENTITY Kappa "&#922;"> <!-- greek capital letter kappa, U+039A -->
+<!ENTITY Lambda "&#923;"> <!-- greek capital letter lamda,
+ U+039B ISOgrk3 -->
+<!ENTITY Mu "&#924;"> <!-- greek capital letter mu, U+039C -->
+<!ENTITY Nu "&#925;"> <!-- greek capital letter nu, U+039D -->
+<!ENTITY Xi "&#926;"> <!-- greek capital letter xi, U+039E ISOgrk3 -->
+<!ENTITY Omicron "&#927;"> <!-- greek capital letter omicron, U+039F -->
+<!ENTITY Pi "&#928;"> <!-- greek capital letter pi, U+03A0 ISOgrk3 -->
+<!ENTITY Rho "&#929;"> <!-- greek capital letter rho, U+03A1 -->
+<!-- there is no Sigmaf, and no U+03A2 character either -->
+<!ENTITY Sigma "&#931;"> <!-- greek capital letter sigma,
+ U+03A3 ISOgrk3 -->
+<!ENTITY Tau "&#932;"> <!-- greek capital letter tau, U+03A4 -->
+<!ENTITY Upsilon "&#933;"> <!-- greek capital letter upsilon,
+ U+03A5 ISOgrk3 -->
+<!ENTITY Phi "&#934;"> <!-- greek capital letter phi,
+ U+03A6 ISOgrk3 -->
+<!ENTITY Chi "&#935;"> <!-- greek capital letter chi, U+03A7 -->
+<!ENTITY Psi "&#936;"> <!-- greek capital letter psi,
+ U+03A8 ISOgrk3 -->
+<!ENTITY Omega "&#937;"> <!-- greek capital letter omega,
+ U+03A9 ISOgrk3 -->
+
+<!ENTITY alpha "&#945;"> <!-- greek small letter alpha,
+ U+03B1 ISOgrk3 -->
+<!ENTITY beta "&#946;"> <!-- greek small letter beta, U+03B2 ISOgrk3 -->
+<!ENTITY gamma "&#947;"> <!-- greek small letter gamma,
+ U+03B3 ISOgrk3 -->
+<!ENTITY delta "&#948;"> <!-- greek small letter delta,
+ U+03B4 ISOgrk3 -->
+<!ENTITY epsilon "&#949;"> <!-- greek small letter epsilon,
+ U+03B5 ISOgrk3 -->
+<!ENTITY zeta "&#950;"> <!-- greek small letter zeta, U+03B6 ISOgrk3 -->
+<!ENTITY eta "&#951;"> <!-- greek small letter eta, U+03B7 ISOgrk3 -->
+<!ENTITY theta "&#952;"> <!-- greek small letter theta,
+ U+03B8 ISOgrk3 -->
+<!ENTITY iota "&#953;"> <!-- greek small letter iota, U+03B9 ISOgrk3 -->
+<!ENTITY kappa "&#954;"> <!-- greek small letter kappa,
+ U+03BA ISOgrk3 -->
+<!ENTITY lambda "&#955;"> <!-- greek small letter lamda,
+ U+03BB ISOgrk3 -->
+<!ENTITY mu "&#956;"> <!-- greek small letter mu, U+03BC ISOgrk3 -->
+<!ENTITY nu "&#957;"> <!-- greek small letter nu, U+03BD ISOgrk3 -->
+<!ENTITY xi "&#958;"> <!-- greek small letter xi, U+03BE ISOgrk3 -->
+<!ENTITY omicron "&#959;"> <!-- greek small letter omicron, U+03BF NEW -->
+<!ENTITY pi "&#960;"> <!-- greek small letter pi, U+03C0 ISOgrk3 -->
+<!ENTITY rho "&#961;"> <!-- greek small letter rho, U+03C1 ISOgrk3 -->
+<!ENTITY sigmaf "&#962;"> <!-- greek small letter final sigma,
+ U+03C2 ISOgrk3 -->
+<!ENTITY sigma "&#963;"> <!-- greek small letter sigma,
+ U+03C3 ISOgrk3 -->
+<!ENTITY tau "&#964;"> <!-- greek small letter tau, U+03C4 ISOgrk3 -->
+<!ENTITY upsilon "&#965;"> <!-- greek small letter upsilon,
+ U+03C5 ISOgrk3 -->
+<!ENTITY phi "&#966;"> <!-- greek small letter phi, U+03C6 ISOgrk3 -->
+<!ENTITY chi "&#967;"> <!-- greek small letter chi, U+03C7 ISOgrk3 -->
+<!ENTITY psi "&#968;"> <!-- greek small letter psi, U+03C8 ISOgrk3 -->
+<!ENTITY omega "&#969;"> <!-- greek small letter omega,
+ U+03C9 ISOgrk3 -->
+<!ENTITY thetasym "&#977;"> <!-- greek theta symbol,
+ U+03D1 NEW -->
+<!ENTITY upsih "&#978;"> <!-- greek upsilon with hook symbol,
+ U+03D2 NEW -->
+<!ENTITY piv "&#982;"> <!-- greek pi symbol, U+03D6 ISOgrk3 -->
+
+<!-- General Punctuation -->
+<!ENTITY bull "&#8226;"> <!-- bullet = black small circle,
+ U+2022 ISOpub -->
+<!-- bullet is NOT the same as bullet operator, U+2219 -->
+<!ENTITY hellip "&#8230;"> <!-- horizontal ellipsis = three dot leader,
+ U+2026 ISOpub -->
+<!ENTITY prime "&#8242;"> <!-- prime = minutes = feet, U+2032 ISOtech -->
+<!ENTITY Prime "&#8243;"> <!-- double prime = seconds = inches,
+ U+2033 ISOtech -->
+<!ENTITY oline "&#8254;"> <!-- overline = spacing overscore,
+ U+203E NEW -->
+<!ENTITY frasl "&#8260;"> <!-- fraction slash, U+2044 NEW -->
+
+<!-- Letterlike Symbols -->
+<!ENTITY weierp "&#8472;"> <!-- script capital P = power set
+ = Weierstrass p, U+2118 ISOamso -->
+<!ENTITY image "&#8465;"> <!-- black-letter capital I = imaginary part,
+ U+2111 ISOamso -->
+<!ENTITY real "&#8476;"> <!-- black-letter capital R = real part symbol,
+ U+211C ISOamso -->
+<!ENTITY trade "&#8482;"> <!-- trade mark sign, U+2122 ISOnum -->
+<!ENTITY alefsym "&#8501;"> <!-- alef symbol = first transfinite cardinal,
+ U+2135 NEW -->
+<!-- alef symbol is NOT the same as hebrew letter alef,
+ U+05D0 although the same glyph could be used to depict both characters -->
+
+<!-- Arrows -->
+<!ENTITY larr "&#8592;"> <!-- leftwards arrow, U+2190 ISOnum -->
+<!ENTITY uarr "&#8593;"> <!-- upwards arrow, U+2191 ISOnum-->
+<!ENTITY rarr "&#8594;"> <!-- rightwards arrow, U+2192 ISOnum -->
+<!ENTITY darr "&#8595;"> <!-- downwards arrow, U+2193 ISOnum -->
+<!ENTITY harr "&#8596;"> <!-- left right arrow, U+2194 ISOamsa -->
+<!ENTITY crarr "&#8629;"> <!-- downwards arrow with corner leftwards
+ = carriage return, U+21B5 NEW -->
+<!ENTITY lArr "&#8656;"> <!-- leftwards double arrow, U+21D0 ISOtech -->
+<!-- Unicode does not say that lArr is the same as the 'is implied by' arrow
+ but also does not have any other character for that function. So lArr can
+ be used for 'is implied by' as ISOtech suggests -->
+<!ENTITY uArr "&#8657;"> <!-- upwards double arrow, U+21D1 ISOamsa -->
+<!ENTITY rArr "&#8658;"> <!-- rightwards double arrow,
+ U+21D2 ISOtech -->
+<!-- Unicode does not say this is the 'implies' character but does not have
+ another character with this function so rArr can be used for 'implies'
+ as ISOtech suggests -->
+<!ENTITY dArr "&#8659;"> <!-- downwards double arrow, U+21D3 ISOamsa -->
+<!ENTITY hArr "&#8660;"> <!-- left right double arrow,
+ U+21D4 ISOamsa -->
+
+<!-- Mathematical Operators -->
+<!ENTITY forall "&#8704;"> <!-- for all, U+2200 ISOtech -->
+<!ENTITY part "&#8706;"> <!-- partial differential, U+2202 ISOtech -->
+<!ENTITY exist "&#8707;"> <!-- there exists, U+2203 ISOtech -->
+<!ENTITY empty "&#8709;"> <!-- empty set = null set, U+2205 ISOamso -->
+<!ENTITY nabla "&#8711;"> <!-- nabla = backward difference,
+ U+2207 ISOtech -->
+<!ENTITY isin "&#8712;"> <!-- element of, U+2208 ISOtech -->
+<!ENTITY notin "&#8713;"> <!-- not an element of, U+2209 ISOtech -->
+<!ENTITY ni "&#8715;"> <!-- contains as member, U+220B ISOtech -->
+<!ENTITY prod "&#8719;"> <!-- n-ary product = product sign,
+ U+220F ISOamsb -->
+<!-- prod is NOT the same character as U+03A0 'greek capital letter pi' though
+ the same glyph might be used for both -->
+<!ENTITY sum "&#8721;"> <!-- n-ary summation, U+2211 ISOamsb -->
+<!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
+ though the same glyph might be used for both -->
+<!ENTITY minus "&#8722;"> <!-- minus sign, U+2212 ISOtech -->
+<!ENTITY lowast "&#8727;"> <!-- asterisk operator, U+2217 ISOtech -->
+<!ENTITY radic "&#8730;"> <!-- square root = radical sign,
+ U+221A ISOtech -->
+<!ENTITY prop "&#8733;"> <!-- proportional to, U+221D ISOtech -->
+<!ENTITY infin "&#8734;"> <!-- infinity, U+221E ISOtech -->
+<!ENTITY ang "&#8736;"> <!-- angle, U+2220 ISOamso -->
+<!ENTITY and "&#8743;"> <!-- logical and = wedge, U+2227 ISOtech -->
+<!ENTITY or "&#8744;"> <!-- logical or = vee, U+2228 ISOtech -->
+<!ENTITY cap "&#8745;"> <!-- intersection = cap, U+2229 ISOtech -->
+<!ENTITY cup "&#8746;"> <!-- union = cup, U+222A ISOtech -->
+<!ENTITY int "&#8747;"> <!-- integral, U+222B ISOtech -->
+<!ENTITY there4 "&#8756;"> <!-- therefore, U+2234 ISOtech -->
+<!ENTITY sim "&#8764;"> <!-- tilde operator = varies with = similar to,
+ U+223C ISOtech -->
+<!-- tilde operator is NOT the same character as the tilde, U+007E,
+ although the same glyph might be used to represent both -->
+<!ENTITY cong "&#8773;"> <!-- approximately equal to, U+2245 ISOtech -->
+<!ENTITY asymp "&#8776;"> <!-- almost equal to = asymptotic to,
+ U+2248 ISOamsr -->
+<!ENTITY ne "&#8800;"> <!-- not equal to, U+2260 ISOtech -->
+<!ENTITY equiv "&#8801;"> <!-- identical to, U+2261 ISOtech -->
+<!ENTITY le "&#8804;"> <!-- less-than or equal to, U+2264 ISOtech -->
+<!ENTITY ge "&#8805;"> <!-- greater-than or equal to,
+ U+2265 ISOtech -->
+<!ENTITY sub "&#8834;"> <!-- subset of, U+2282 ISOtech -->
+<!ENTITY sup "&#8835;"> <!-- superset of, U+2283 ISOtech -->
+<!ENTITY nsub "&#8836;"> <!-- not a subset of, U+2284 ISOamsn -->
+<!ENTITY sube "&#8838;"> <!-- subset of or equal to, U+2286 ISOtech -->
+<!ENTITY supe "&#8839;"> <!-- superset of or equal to,
+ U+2287 ISOtech -->
+<!ENTITY oplus "&#8853;"> <!-- circled plus = direct sum,
+ U+2295 ISOamsb -->
+<!ENTITY otimes "&#8855;"> <!-- circled times = vector product,
+ U+2297 ISOamsb -->
+<!ENTITY perp "&#8869;"> <!-- up tack = orthogonal to = perpendicular,
+ U+22A5 ISOtech -->
+<!ENTITY sdot "&#8901;"> <!-- dot operator, U+22C5 ISOamsb -->
+<!-- dot operator is NOT the same character as U+00B7 middle dot -->
+
+<!-- Miscellaneous Technical -->
+<!ENTITY lceil "&#8968;"> <!-- left ceiling = APL upstile,
+ U+2308 ISOamsc -->
+<!ENTITY rceil "&#8969;"> <!-- right ceiling, U+2309 ISOamsc -->
+<!ENTITY lfloor "&#8970;"> <!-- left floor = APL downstile,
+ U+230A ISOamsc -->
+<!ENTITY rfloor "&#8971;"> <!-- right floor, U+230B ISOamsc -->
+<!ENTITY lang "&#9001;"> <!-- left-pointing angle bracket = bra,
+ U+2329 ISOtech -->
+<!-- lang is NOT the same character as U+003C 'less than sign'
+ or U+2039 'single left-pointing angle quotation mark' -->
+<!ENTITY rang "&#9002;"> <!-- right-pointing angle bracket = ket,
+ U+232A ISOtech -->
+<!-- rang is NOT the same character as U+003E 'greater than sign'
+ or U+203A 'single right-pointing angle quotation mark' -->
+
+<!-- Geometric Shapes -->
+<!ENTITY loz "&#9674;"> <!-- lozenge, U+25CA ISOpub -->
+
+<!-- Miscellaneous Symbols -->
+<!ENTITY spades "&#9824;"> <!-- black spade suit, U+2660 ISOpub -->
+<!-- black here seems to mean filled as opposed to hollow -->
+<!ENTITY clubs "&#9827;"> <!-- black club suit = shamrock,
+ U+2663 ISOpub -->
+<!ENTITY hearts "&#9829;"> <!-- black heart suit = valentine,
+ U+2665 ISOpub -->
+<!ENTITY diams "&#9830;"> <!-- black diamond suit, U+2666 ISOpub -->
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-frameset.dtd b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-frameset.dtd
new file mode 100644
index 0000000000..d128f2eb7c
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-frameset.dtd
@@ -0,0 +1,1235 @@
+<!--
+ Extensible HTML version 1.0 Frameset DTD
+
+ This is the same as HTML 4 Frameset except for
+ changes due to the differences between XML and SGML.
+
+ Namespace = http://www.w3.org/1999/xhtml
+
+ For further information, see: http://www.w3.org/TR/xhtml1
+
+ Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
+ All Rights Reserved.
+
+ This DTD module is identified by the PUBLIC and SYSTEM identifiers:
+
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
+
+ $Revision: 1.2 $
+ $Date: 2002/08/01 18:37:55 $
+
+-->
+
+<!--================ Character mnemonic entities =========================-->
+
+<!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "xhtml-lat1.ent">
+%HTMLlat1;
+
+<!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "xhtml-symbol.ent">
+%HTMLsymbol;
+
+<!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "xhtml-special.ent">
+%HTMLspecial;
+
+<!--================== Imported Names ====================================-->
+
+<!ENTITY % ContentType "CDATA">
+ <!-- media type, as per [RFC2045] -->
+
+<!ENTITY % ContentTypes "CDATA">
+ <!-- comma-separated list of media types, as per [RFC2045] -->
+
+<!ENTITY % Charset "CDATA">
+ <!-- a character encoding, as per [RFC2045] -->
+
+<!ENTITY % Charsets "CDATA">
+ <!-- a space separated list of character encodings, as per [RFC2045] -->
+
+<!ENTITY % LanguageCode "NMTOKEN">
+ <!-- a language code, as per [RFC3066] -->
+
+<!ENTITY % Character "CDATA">
+ <!-- a single character, as per section 2.2 of [XML] -->
+
+<!ENTITY % Number "CDATA">
+ <!-- one or more digits -->
+
+<!ENTITY % LinkTypes "CDATA">
+ <!-- space-separated list of link types -->
+
+<!ENTITY % MediaDesc "CDATA">
+ <!-- single or comma-separated list of media descriptors -->
+
+<!ENTITY % URI "CDATA">
+ <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+ <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % Datetime "CDATA">
+ <!-- date and time information. ISO date format -->
+
+<!ENTITY % Script "CDATA">
+ <!-- script expression -->
+
+<!ENTITY % StyleSheet "CDATA">
+ <!-- style sheet data -->
+
+<!ENTITY % Text "CDATA">
+ <!-- used for titles etc. -->
+
+<!ENTITY % FrameTarget "NMTOKEN">
+ <!-- render in this frame -->
+
+<!ENTITY % Length "CDATA">
+ <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % MultiLength "CDATA">
+ <!-- pixel, percentage, or relative -->
+
+<!ENTITY % MultiLengths "CDATA">
+ <!-- comma-separated list of MultiLength -->
+
+<!ENTITY % Pixels "CDATA">
+ <!-- integer representing length in pixels -->
+
+<!-- these are used for image maps -->
+
+<!ENTITY % Shape "(rect|circle|poly|default)">
+
+<!ENTITY % Coords "CDATA">
+ <!-- comma separated list of lengths -->
+
+<!-- used for object, applet, img, input and iframe -->
+<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
+
+<!-- a color using sRGB: #RRGGBB as Hex values -->
+<!ENTITY % Color "CDATA">
+
+<!-- There are also 16 widely known color names with their sRGB values:
+
+ Black = #000000 Green = #008000
+ Silver = #C0C0C0 Lime = #00FF00
+ Gray = #808080 Olive = #808000
+ White = #FFFFFF Yellow = #FFFF00
+ Maroon = #800000 Navy = #000080
+ Red = #FF0000 Blue = #0000FF
+ Purple = #800080 Teal = #008080
+ Fuchsia= #FF00FF Aqua = #00FFFF
+-->
+
+<!--=================== Generic Attributes ===============================-->
+
+<!-- core attributes common to most elements
+ id document-wide unique id
+ class space separated list of classes
+ style associated style info
+ title advisory title/amplification
+-->
+<!ENTITY % coreattrs
+ "id ID #IMPLIED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED"
+ >
+
+<!-- internationalization attributes
+ lang language code (backwards compatible)
+ xml:lang language code (as per XML 1.0 spec)
+ dir direction for weak/neutral text
+-->
+<!ENTITY % i18n
+ "lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #IMPLIED"
+ >
+
+<!-- attributes for common UI events
+ onclick a pointer button was clicked
+ ondblclick a pointer button was double clicked
+ onmousedown a pointer button was pressed down
+ onmouseup a pointer button was released
+ onmousemove a pointer was moved onto the element
+ onmouseout a pointer was moved away from the element
+ onkeypress a key was pressed and released
+ onkeydown a key was pressed down
+ onkeyup a key was released
+-->
+<!ENTITY % events
+ "onclick %Script; #IMPLIED
+ ondblclick %Script; #IMPLIED
+ onmousedown %Script; #IMPLIED
+ onmouseup %Script; #IMPLIED
+ onmouseover %Script; #IMPLIED
+ onmousemove %Script; #IMPLIED
+ onmouseout %Script; #IMPLIED
+ onkeypress %Script; #IMPLIED
+ onkeydown %Script; #IMPLIED
+ onkeyup %Script; #IMPLIED"
+ >
+
+<!-- attributes for elements that can get the focus
+ accesskey accessibility key character
+ tabindex position in tabbing order
+ onfocus the element got the focus
+ onblur the element lost the focus
+-->
+<!ENTITY % focus
+ "accesskey %Character; #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED"
+ >
+
+<!ENTITY % attrs "%coreattrs; %i18n; %events;">
+
+<!-- text alignment for p, div, h1-h6. The default is
+ align="left" for ltr headings, "right" for rtl -->
+
+<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">
+
+<!--=================== Text Elements ====================================-->
+
+<!ENTITY % special.extra
+ "object | applet | img | map | iframe">
+
+<!ENTITY % special.basic
+ "br | span | bdo">
+
+<!ENTITY % special
+ "%special.basic; | %special.extra;">
+
+<!ENTITY % fontstyle.extra "big | small | font | basefont">
+
+<!ENTITY % fontstyle.basic "tt | i | b | u
+ | s | strike ">
+
+<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;">
+
+<!ENTITY % phrase.extra "sub | sup">
+<!ENTITY % phrase.basic "em | strong | dfn | code | q |
+ samp | kbd | var | cite | abbr | acronym">
+
+<!ENTITY % phrase "%phrase.basic; | %phrase.extra;">
+
+<!ENTITY % inline.forms "input | select | textarea | label | button">
+
+<!-- these can occur at block or inline level -->
+<!ENTITY % misc.inline "ins | del | script">
+
+<!-- these can only occur at block level -->
+<!ENTITY % misc "noscript | %misc.inline;">
+
+
+<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
+
+<!-- %Inline; covers inline or "text-level" elements -->
+<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
+
+<!--================== Block level elements ==============================-->
+
+<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
+<!ENTITY % lists "ul | ol | dl | menu | dir">
+<!ENTITY % blocktext "pre | hr | blockquote | address | center">
+
+<!ENTITY % block
+ "p | %heading; | div | %lists; | %blocktext; | isindex | fieldset | table">
+
+<!-- %Flow; mixes block and inline and is used for list items etc. -->
+<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
+
+<!--================== Content models for exclusions =====================-->
+
+<!-- a elements use %Inline; excluding a -->
+
+<!ENTITY % a.content
+ "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
+
+<!-- pre uses %Inline excluding img, object, applet, big, small,
+ sub, sup, font, or basefont -->
+
+<!ENTITY % pre.content
+ "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; |
+ %inline.forms; | %misc.inline;)*">
+
+
+<!-- form uses %Flow; excluding form -->
+
+<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*">
+
+<!-- button uses %Flow; but excludes a, form, form controls, iframe -->
+
+<!ENTITY % button.content
+ "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
+ table | br | span | bdo | object | applet | img | map |
+ %fontstyle; | %phrase; | %misc;)*">
+
+<!--================ Document Structure ==================================-->
+
+<!-- the namespace URI designates the document profile -->
+
+<!ELEMENT html (head, frameset)>
+<!ATTLIST html
+ %i18n;
+ id ID #IMPLIED
+ xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
+ >
+
+<!--================ Document Head =======================================-->
+
+<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*">
+
+<!-- content model is %head.misc; combined with a single
+ title and an optional base element in any order -->
+
+<!ELEMENT head (%head.misc;,
+ ((title, %head.misc;, (base, %head.misc;)?) |
+ (base, %head.misc;, (title, %head.misc;))))>
+
+<!ATTLIST head
+ %i18n;
+ id ID #IMPLIED
+ profile %URI; #IMPLIED
+ >
+
+<!-- The title element is not considered part of the flow of text.
+ It should be displayed, for example as the page header or
+ window title. Exactly one title is required per document.
+ -->
+<!ELEMENT title (#PCDATA)>
+<!ATTLIST title
+ %i18n;
+ id ID #IMPLIED
+ >
+
+<!-- document base URI -->
+
+<!ELEMENT base EMPTY>
+<!ATTLIST base
+ id ID #IMPLIED
+ href %URI; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!-- generic metainformation -->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+ %i18n;
+ id ID #IMPLIED
+ http-equiv CDATA #IMPLIED
+ name CDATA #IMPLIED
+ content CDATA #REQUIRED
+ scheme CDATA #IMPLIED
+ >
+
+<!--
+ Relationship values can be used in principle:
+
+ a) for document specific toolbars/menus when used
+ with the link element in document head e.g.
+ start, contents, previous, next, index, end, help
+ b) to link to a separate style sheet (rel="stylesheet")
+ c) to make a link to a script (rel="script")
+ d) by stylesheets to control how collections of
+ html nodes are rendered into printed documents
+ e) to make a link to a printable version of this document
+ e.g. a PostScript or PDF version (rel="alternate" media="print")
+-->
+
+<!ELEMENT link EMPTY>
+<!ATTLIST link
+ %attrs;
+ charset %Charset; #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ type %ContentType; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ media %MediaDesc; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!-- style info, which may include CDATA sections -->
+<!ELEMENT style (#PCDATA)>
+<!ATTLIST style
+ %i18n;
+ id ID #IMPLIED
+ type %ContentType; #REQUIRED
+ media %MediaDesc; #IMPLIED
+ title %Text; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- script statements, which may include CDATA sections -->
+<!ELEMENT script (#PCDATA)>
+<!ATTLIST script
+ id ID #IMPLIED
+ charset %Charset; #IMPLIED
+ type %ContentType; #REQUIRED
+ language CDATA #IMPLIED
+ src %URI; #IMPLIED
+ defer (defer) #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- alternate content container for non script-based rendering -->
+
+<!ELEMENT noscript %Flow;>
+<!ATTLIST noscript
+ %attrs;
+ >
+
+<!--======================= Frames =======================================-->
+
+<!-- only one noframes element permitted per document -->
+
+<!ELEMENT frameset (frameset|frame|noframes)*>
+<!ATTLIST frameset
+ %coreattrs;
+ rows %MultiLengths; #IMPLIED
+ cols %MultiLengths; #IMPLIED
+ onload %Script; #IMPLIED
+ onunload %Script; #IMPLIED
+ >
+
+<!-- reserved frame names start with "_" otherwise starts with letter -->
+
+<!-- tiled window within frameset -->
+
+<!ELEMENT frame EMPTY>
+<!ATTLIST frame
+ %coreattrs;
+ longdesc %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ src %URI; #IMPLIED
+ frameborder (1|0) "1"
+ marginwidth %Pixels; #IMPLIED
+ marginheight %Pixels; #IMPLIED
+ noresize (noresize) #IMPLIED
+ scrolling (yes|no|auto) "auto"
+ >
+
+<!-- inline subwindow -->
+
+<!ELEMENT iframe %Flow;>
+<!ATTLIST iframe
+ %coreattrs;
+ longdesc %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ src %URI; #IMPLIED
+ frameborder (1|0) "1"
+ marginwidth %Pixels; #IMPLIED
+ marginheight %Pixels; #IMPLIED
+ scrolling (yes|no|auto) "auto"
+ align %ImgAlign; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ >
+
+<!-- alternate content container for non frame-based rendering -->
+
+<!ELEMENT noframes (body)>
+<!ATTLIST noframes
+ %attrs;
+ >
+
+<!--=================== Document Body ====================================-->
+
+<!ELEMENT body %Flow;>
+<!ATTLIST body
+ %attrs;
+ onload %Script; #IMPLIED
+ onunload %Script; #IMPLIED
+ background %URI; #IMPLIED
+ bgcolor %Color; #IMPLIED
+ text %Color; #IMPLIED
+ link %Color; #IMPLIED
+ vlink %Color; #IMPLIED
+ alink %Color; #IMPLIED
+ >
+
+<!ELEMENT div %Flow;> <!-- generic language/style container -->
+<!ATTLIST div
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Paragraphs =======================================-->
+
+<!ELEMENT p %Inline;>
+<!ATTLIST p
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Headings =========================================-->
+
+<!--
+ There are six levels of headings from h1 (the most important)
+ to h6 (the least important).
+-->
+
+<!ELEMENT h1 %Inline;>
+<!ATTLIST h1
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h2 %Inline;>
+<!ATTLIST h2
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h3 %Inline;>
+<!ATTLIST h3
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h4 %Inline;>
+<!ATTLIST h4
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h5 %Inline;>
+<!ATTLIST h5
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h6 %Inline;>
+<!ATTLIST h6
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Lists ============================================-->
+
+<!-- Unordered list bullet styles -->
+
+<!ENTITY % ULStyle "(disc|square|circle)">
+
+<!-- Unordered list -->
+
+<!ELEMENT ul (li)+>
+<!ATTLIST ul
+ %attrs;
+ type %ULStyle; #IMPLIED
+ compact (compact) #IMPLIED
+ >
+
+<!-- Ordered list numbering style
+
+ 1 arabic numbers 1, 2, 3, ...
+ a lower alpha a, b, c, ...
+ A upper alpha A, B, C, ...
+ i lower roman i, ii, iii, ...
+ I upper roman I, II, III, ...
+
+ The style is applied to the sequence number which by default
+ is reset to 1 for the first list item in an ordered list.
+-->
+<!ENTITY % OLStyle "CDATA">
+
+<!-- Ordered (numbered) list -->
+
+<!ELEMENT ol (li)+>
+<!ATTLIST ol
+ %attrs;
+ type %OLStyle; #IMPLIED
+ compact (compact) #IMPLIED
+ start %Number; #IMPLIED
+ >
+
+<!-- single column list (DEPRECATED) -->
+<!ELEMENT menu (li)+>
+<!ATTLIST menu
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!-- multiple column list (DEPRECATED) -->
+<!ELEMENT dir (li)+>
+<!ATTLIST dir
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" -->
+<!ENTITY % LIStyle "CDATA">
+
+<!-- list item -->
+
+<!ELEMENT li %Flow;>
+<!ATTLIST li
+ %attrs;
+ type %LIStyle; #IMPLIED
+ value %Number; #IMPLIED
+ >
+
+<!-- definition lists - dt for term, dd for its definition -->
+
+<!ELEMENT dl (dt|dd)+>
+<!ATTLIST dl
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!ELEMENT dt %Inline;>
+<!ATTLIST dt
+ %attrs;
+ >
+
+<!ELEMENT dd %Flow;>
+<!ATTLIST dd
+ %attrs;
+ >
+
+<!--=================== Address ==========================================-->
+
+<!-- information on author -->
+
+<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*>
+<!ATTLIST address
+ %attrs;
+ >
+
+<!--=================== Horizontal Rule ==================================-->
+
+<!ELEMENT hr EMPTY>
+<!ATTLIST hr
+ %attrs;
+ align (left|center|right) #IMPLIED
+ noshade (noshade) #IMPLIED
+ size %Pixels; #IMPLIED
+ width %Length; #IMPLIED
+ >
+
+<!--=================== Preformatted Text ================================-->
+
+<!-- content is %Inline; excluding
+ "img|object|applet|big|small|sub|sup|font|basefont" -->
+
+<!ELEMENT pre %pre.content;>
+<!ATTLIST pre
+ %attrs;
+ width %Number; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!--=================== Block-like Quotes ================================-->
+
+<!ELEMENT blockquote %Flow;>
+<!ATTLIST blockquote
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!--=================== Text alignment ===================================-->
+
+<!-- center content -->
+<!ELEMENT center %Flow;>
+<!ATTLIST center
+ %attrs;
+ >
+
+<!--=================== Inserted/Deleted Text ============================-->
+
+
+<!--
+ ins/del are allowed in block and inline content, but its
+ inappropriate to include block content within an ins element
+ occurring in inline content.
+-->
+<!ELEMENT ins %Flow;>
+<!ATTLIST ins
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!ELEMENT del %Flow;>
+<!ATTLIST del
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!--================== The Anchor Element ================================-->
+
+<!-- content is %Inline; except that anchors shouldn't be nested -->
+
+<!ELEMENT a %a.content;>
+<!ATTLIST a
+ %attrs;
+ %focus;
+ charset %Charset; #IMPLIED
+ type %ContentType; #IMPLIED
+ name NMTOKEN #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--===================== Inline Elements ================================-->
+
+<!ELEMENT span %Inline;> <!-- generic language/style container -->
+<!ATTLIST span
+ %attrs;
+ >
+
+<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
+<!ATTLIST bdo
+ %coreattrs;
+ %events;
+ lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #REQUIRED
+ >
+
+<!ELEMENT br EMPTY> <!-- forced line break -->
+<!ATTLIST br
+ %coreattrs;
+ clear (left|all|right|none) "none"
+ >
+
+<!ELEMENT em %Inline;> <!-- emphasis -->
+<!ATTLIST em %attrs;>
+
+<!ELEMENT strong %Inline;> <!-- strong emphasis -->
+<!ATTLIST strong %attrs;>
+
+<!ELEMENT dfn %Inline;> <!-- definitional -->
+<!ATTLIST dfn %attrs;>
+
+<!ELEMENT code %Inline;> <!-- program code -->
+<!ATTLIST code %attrs;>
+
+<!ELEMENT samp %Inline;> <!-- sample -->
+<!ATTLIST samp %attrs;>
+
+<!ELEMENT kbd %Inline;> <!-- something user would type -->
+<!ATTLIST kbd %attrs;>
+
+<!ELEMENT var %Inline;> <!-- variable -->
+<!ATTLIST var %attrs;>
+
+<!ELEMENT cite %Inline;> <!-- citation -->
+<!ATTLIST cite %attrs;>
+
+<!ELEMENT abbr %Inline;> <!-- abbreviation -->
+<!ATTLIST abbr %attrs;>
+
+<!ELEMENT acronym %Inline;> <!-- acronym -->
+<!ATTLIST acronym %attrs;>
+
+<!ELEMENT q %Inline;> <!-- inlined quote -->
+<!ATTLIST q
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!ELEMENT sub %Inline;> <!-- subscript -->
+<!ATTLIST sub %attrs;>
+
+<!ELEMENT sup %Inline;> <!-- superscript -->
+<!ATTLIST sup %attrs;>
+
+<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
+<!ATTLIST tt %attrs;>
+
+<!ELEMENT i %Inline;> <!-- italic font -->
+<!ATTLIST i %attrs;>
+
+<!ELEMENT b %Inline;> <!-- bold font -->
+<!ATTLIST b %attrs;>
+
+<!ELEMENT big %Inline;> <!-- bigger font -->
+<!ATTLIST big %attrs;>
+
+<!ELEMENT small %Inline;> <!-- smaller font -->
+<!ATTLIST small %attrs;>
+
+<!ELEMENT u %Inline;> <!-- underline -->
+<!ATTLIST u %attrs;>
+
+<!ELEMENT s %Inline;> <!-- strike-through -->
+<!ATTLIST s %attrs;>
+
+<!ELEMENT strike %Inline;> <!-- strike-through -->
+<!ATTLIST strike %attrs;>
+
+<!ELEMENT basefont EMPTY> <!-- base font size -->
+<!ATTLIST basefont
+ id ID #IMPLIED
+ size CDATA #REQUIRED
+ color %Color; #IMPLIED
+ face CDATA #IMPLIED
+ >
+
+<!ELEMENT font %Inline;> <!-- local change to font -->
+<!ATTLIST font
+ %coreattrs;
+ %i18n;
+ size CDATA #IMPLIED
+ color %Color; #IMPLIED
+ face CDATA #IMPLIED
+ >
+
+<!--==================== Object ======================================-->
+<!--
+ object is used to embed objects as part of HTML pages.
+ param elements should precede other content. Parameters
+ can also be expressed as attribute/value pairs on the
+ object element itself when brevity is desired.
+-->
+
+<!ELEMENT object (#PCDATA | param | %block; | form |%inline; | %misc;)*>
+<!ATTLIST object
+ %attrs;
+ declare (declare) #IMPLIED
+ classid %URI; #IMPLIED
+ codebase %URI; #IMPLIED
+ data %URI; #IMPLIED
+ type %ContentType; #IMPLIED
+ codetype %ContentType; #IMPLIED
+ archive %UriList; #IMPLIED
+ standby %Text; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ tabindex %Number; #IMPLIED
+ align %ImgAlign; #IMPLIED
+ border %Pixels; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!--
+ param is used to supply a named property value.
+ In XML it would seem natural to follow RDF and support an
+ abbreviated syntax where the param elements are replaced
+ by attribute value pairs on the object start tag.
+-->
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+ id ID #IMPLIED
+ name CDATA #REQUIRED
+ value CDATA #IMPLIED
+ valuetype (data|ref|object) "data"
+ type %ContentType; #IMPLIED
+ >
+
+<!--=================== Java applet ==================================-->
+<!--
+ One of code or object attributes must be present.
+ Place param elements before other content.
+-->
+<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*>
+<!ATTLIST applet
+ %coreattrs;
+ codebase %URI; #IMPLIED
+ archive CDATA #IMPLIED
+ code CDATA #IMPLIED
+ object CDATA #IMPLIED
+ alt %Text; #IMPLIED
+ name NMTOKEN #IMPLIED
+ width %Length; #REQUIRED
+ height %Length; #REQUIRED
+ align %ImgAlign; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!--=================== Images ===========================================-->
+
+<!--
+ To avoid accessibility problems for people who aren't
+ able to see the image, you should provide a text
+ description using the alt and longdesc attributes.
+ In addition, avoid the use of server-side image maps.
+-->
+
+<!ELEMENT img EMPTY>
+<!ATTLIST img
+ %attrs;
+ src %URI; #REQUIRED
+ alt %Text; #REQUIRED
+ name NMTOKEN #IMPLIED
+ longdesc %URI; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ ismap (ismap) #IMPLIED
+ align %ImgAlign; #IMPLIED
+ border %Pixels; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!-- usemap points to a map element which may be in this document
+ or an external document, although the latter is not widely supported -->
+
+<!--================== Client-side image maps ============================-->
+
+<!-- These can be placed in the same document or grouped in a
+ separate document although this isn't yet widely supported -->
+
+<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
+<!ATTLIST map
+ %i18n;
+ %events;
+ id ID #REQUIRED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED
+ name NMTOKEN #IMPLIED
+ >
+
+<!ELEMENT area EMPTY>
+<!ATTLIST area
+ %attrs;
+ %focus;
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ href %URI; #IMPLIED
+ nohref (nohref) #IMPLIED
+ alt %Text; #REQUIRED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--================ Forms ===============================================-->
+
+<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
+
+<!ATTLIST form
+ %attrs;
+ action %URI; #REQUIRED
+ method (get|post) "get"
+ name NMTOKEN #IMPLIED
+ enctype %ContentType; "application/x-www-form-urlencoded"
+ onsubmit %Script; #IMPLIED
+ onreset %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ accept-charset %Charsets; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--
+ Each label must not contain more than ONE field
+ Label elements shouldn't be nested.
+-->
+<!ELEMENT label %Inline;>
+<!ATTLIST label
+ %attrs;
+ for IDREF #IMPLIED
+ accesskey %Character; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ >
+
+<!ENTITY % InputType
+ "(text | password | checkbox |
+ radio | submit | reset |
+ file | hidden | image | button)"
+ >
+
+<!-- the name attribute is required for all but submit & reset -->
+
+<!ELEMENT input EMPTY> <!-- form control -->
+<!ATTLIST input
+ %attrs;
+ %focus;
+ type %InputType; "text"
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ checked (checked) #IMPLIED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ size CDATA #IMPLIED
+ maxlength %Number; #IMPLIED
+ src %URI; #IMPLIED
+ alt CDATA #IMPLIED
+ usemap %URI; #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ align %ImgAlign; #IMPLIED
+ >
+
+<!ELEMENT select (optgroup|option)+> <!-- option selector -->
+<!ATTLIST select
+ %attrs;
+ name CDATA #IMPLIED
+ size %Number; #IMPLIED
+ multiple (multiple) #IMPLIED
+ disabled (disabled) #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!ELEMENT optgroup (option)+> <!-- option group -->
+<!ATTLIST optgroup
+ %attrs;
+ disabled (disabled) #IMPLIED
+ label %Text; #REQUIRED
+ >
+
+<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
+<!ATTLIST option
+ %attrs;
+ selected (selected) #IMPLIED
+ disabled (disabled) #IMPLIED
+ label %Text; #IMPLIED
+ value CDATA #IMPLIED
+ >
+
+<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
+<!ATTLIST textarea
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ rows %Number; #REQUIRED
+ cols %Number; #REQUIRED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!--
+ The fieldset element is used to group form fields.
+ Only one legend element should occur in the content
+ and if present should only be preceded by whitespace.
+-->
+<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
+<!ATTLIST fieldset
+ %attrs;
+ >
+
+<!ENTITY % LAlign "(top|bottom|left|right)">
+
+<!ELEMENT legend %Inline;> <!-- fieldset label -->
+<!ATTLIST legend
+ %attrs;
+ accesskey %Character; #IMPLIED
+ align %LAlign; #IMPLIED
+ >
+
+<!--
+ Content is %Flow; excluding a, form, form controls, iframe
+-->
+<!ELEMENT button %button.content;> <!-- push button -->
+<!ATTLIST button
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ type (button|submit|reset) "submit"
+ disabled (disabled) #IMPLIED
+ >
+
+<!-- single-line text input control (DEPRECATED) -->
+<!ELEMENT isindex EMPTY>
+<!ATTLIST isindex
+ %coreattrs;
+ %i18n;
+ prompt %Text; #IMPLIED
+ >
+
+<!--======================= Tables =======================================-->
+
+<!-- Derived from IETF HTML table standard, see [RFC1942] -->
+
+<!--
+ The border attribute sets the thickness of the frame around the
+ table. The default units are screen pixels.
+
+ The frame attribute specifies which parts of the frame around
+ the table should be rendered. The values are not the same as
+ CALS to avoid a name clash with the valign attribute.
+-->
+<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
+
+<!--
+ The rules attribute defines which rules to draw between cells:
+
+ If rules is absent then assume:
+ "none" if border is absent or border="0" otherwise "all"
+-->
+
+<!ENTITY % TRules "(none | groups | rows | cols | all)">
+
+<!-- horizontal placement of table relative to document -->
+<!ENTITY % TAlign "(left|center|right)">
+
+<!-- horizontal alignment attributes for cell contents
+
+ char alignment char, e.g. char=":"
+ charoff offset for alignment char
+-->
+<!ENTITY % cellhalign
+ "align (left|center|right|justify|char) #IMPLIED
+ char %Character; #IMPLIED
+ charoff %Length; #IMPLIED"
+ >
+
+<!-- vertical alignment attributes for cell contents -->
+<!ENTITY % cellvalign
+ "valign (top|middle|bottom|baseline) #IMPLIED"
+ >
+
+<!ELEMENT table
+ (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
+<!ELEMENT caption %Inline;>
+<!ELEMENT thead (tr)+>
+<!ELEMENT tfoot (tr)+>
+<!ELEMENT tbody (tr)+>
+<!ELEMENT colgroup (col)*>
+<!ELEMENT col EMPTY>
+<!ELEMENT tr (th|td)+>
+<!ELEMENT th %Flow;>
+<!ELEMENT td %Flow;>
+
+<!ATTLIST table
+ %attrs;
+ summary %Text; #IMPLIED
+ width %Length; #IMPLIED
+ border %Pixels; #IMPLIED
+ frame %TFrame; #IMPLIED
+ rules %TRules; #IMPLIED
+ cellspacing %Length; #IMPLIED
+ cellpadding %Length; #IMPLIED
+ align %TAlign; #IMPLIED
+ bgcolor %Color; #IMPLIED
+ >
+
+<!ENTITY % CAlign "(top|bottom|left|right)">
+
+<!ATTLIST caption
+ %attrs;
+ align %CAlign; #IMPLIED
+ >
+
+<!--
+colgroup groups a set of col elements. It allows you to group
+several semantically related columns together.
+-->
+<!ATTLIST colgroup
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ col elements define the alignment properties for cells in
+ one or more columns.
+
+ The width attribute specifies the width of the columns, e.g.
+
+ width=64 width in screen pixels
+ width=0.5* relative width of 0.5
+
+ The span attribute causes the attributes of one
+ col element to apply to more than one column.
+-->
+<!ATTLIST col
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ Use thead to duplicate headers when breaking table
+ across page boundaries, or for static headers when
+ tbody sections are rendered in scrolling panel.
+
+ Use tfoot to duplicate footers when breaking table
+ across page boundaries, or for static footers when
+ tbody sections are rendered in scrolling panel.
+
+ Use multiple tbody sections when rules are needed
+ between groups of table rows.
+-->
+<!ATTLIST thead
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tfoot
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tbody
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tr
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ bgcolor %Color; #IMPLIED
+ >
+
+<!-- Scope is simpler than headers attribute for common tables -->
+<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
+
+<!-- th is for headers, td for data and for cells acting as both -->
+
+<!ATTLIST th
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ nowrap (nowrap) #IMPLIED
+ bgcolor %Color; #IMPLIED
+ width %Pixels; #IMPLIED
+ height %Pixels; #IMPLIED
+ >
+
+<!ATTLIST td
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ nowrap (nowrap) #IMPLIED
+ bgcolor %Color; #IMPLIED
+ width %Pixels; #IMPLIED
+ height %Pixels; #IMPLIED
+ >
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-strict.dtd b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-strict.dtd
new file mode 100644
index 0000000000..2927b9ece7
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-strict.dtd
@@ -0,0 +1,978 @@
+<!--
+ Extensible HTML version 1.0 Strict DTD
+
+ This is the same as HTML 4 Strict except for
+ changes due to the differences between XML and SGML.
+
+ Namespace = http://www.w3.org/1999/xhtml
+
+ For further information, see: http://www.w3.org/TR/xhtml1
+
+ Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
+ All Rights Reserved.
+
+ This DTD module is identified by the PUBLIC and SYSTEM identifiers:
+
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+
+ $Revision: 1.1 $
+ $Date: 2002/08/01 13:56:03 $
+
+-->
+
+<!--================ Character mnemonic entities =========================-->
+
+<!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "xhtml-lat1.ent">
+%HTMLlat1;
+
+<!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "xhtml-symbol.ent">
+%HTMLsymbol;
+
+<!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "xhtml-special.ent">
+%HTMLspecial;
+
+<!--================== Imported Names ====================================-->
+
+<!ENTITY % ContentType "CDATA">
+ <!-- media type, as per [RFC2045] -->
+
+<!ENTITY % ContentTypes "CDATA">
+ <!-- comma-separated list of media types, as per [RFC2045] -->
+
+<!ENTITY % Charset "CDATA">
+ <!-- a character encoding, as per [RFC2045] -->
+
+<!ENTITY % Charsets "CDATA">
+ <!-- a space separated list of character encodings, as per [RFC2045] -->
+
+<!ENTITY % LanguageCode "NMTOKEN">
+ <!-- a language code, as per [RFC3066] -->
+
+<!ENTITY % Character "CDATA">
+ <!-- a single character, as per section 2.2 of [XML] -->
+
+<!ENTITY % Number "CDATA">
+ <!-- one or more digits -->
+
+<!ENTITY % LinkTypes "CDATA">
+ <!-- space-separated list of link types -->
+
+<!ENTITY % MediaDesc "CDATA">
+ <!-- single or comma-separated list of media descriptors -->
+
+<!ENTITY % URI "CDATA">
+ <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+ <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % Datetime "CDATA">
+ <!-- date and time information. ISO date format -->
+
+<!ENTITY % Script "CDATA">
+ <!-- script expression -->
+
+<!ENTITY % StyleSheet "CDATA">
+ <!-- style sheet data -->
+
+<!ENTITY % Text "CDATA">
+ <!-- used for titles etc. -->
+
+<!ENTITY % Length "CDATA">
+ <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % MultiLength "CDATA">
+ <!-- pixel, percentage, or relative -->
+
+<!ENTITY % Pixels "CDATA">
+ <!-- integer representing length in pixels -->
+
+<!-- these are used for image maps -->
+
+<!ENTITY % Shape "(rect|circle|poly|default)">
+
+<!ENTITY % Coords "CDATA">
+ <!-- comma separated list of lengths -->
+
+<!--=================== Generic Attributes ===============================-->
+
+<!-- core attributes common to most elements
+ id document-wide unique id
+ class space separated list of classes
+ style associated style info
+ title advisory title/amplification
+-->
+<!ENTITY % coreattrs
+ "id ID #IMPLIED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED"
+ >
+
+<!-- internationalization attributes
+ lang language code (backwards compatible)
+ xml:lang language code (as per XML 1.0 spec)
+ dir direction for weak/neutral text
+-->
+<!ENTITY % i18n
+ "lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #IMPLIED"
+ >
+
+<!-- attributes for common UI events
+ onclick a pointer button was clicked
+ ondblclick a pointer button was double clicked
+ onmousedown a pointer button was pressed down
+ onmouseup a pointer button was released
+ onmousemove a pointer was moved onto the element
+ onmouseout a pointer was moved away from the element
+ onkeypress a key was pressed and released
+ onkeydown a key was pressed down
+ onkeyup a key was released
+-->
+<!ENTITY % events
+ "onclick %Script; #IMPLIED
+ ondblclick %Script; #IMPLIED
+ onmousedown %Script; #IMPLIED
+ onmouseup %Script; #IMPLIED
+ onmouseover %Script; #IMPLIED
+ onmousemove %Script; #IMPLIED
+ onmouseout %Script; #IMPLIED
+ onkeypress %Script; #IMPLIED
+ onkeydown %Script; #IMPLIED
+ onkeyup %Script; #IMPLIED"
+ >
+
+<!-- attributes for elements that can get the focus
+ accesskey accessibility key character
+ tabindex position in tabbing order
+ onfocus the element got the focus
+ onblur the element lost the focus
+-->
+<!ENTITY % focus
+ "accesskey %Character; #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED"
+ >
+
+<!ENTITY % attrs "%coreattrs; %i18n; %events;">
+
+<!--=================== Text Elements ====================================-->
+
+<!ENTITY % special.pre
+ "br | span | bdo | map">
+
+
+<!ENTITY % special
+ "%special.pre; | object | img ">
+
+<!ENTITY % fontstyle "tt | i | b | big | small ">
+
+<!ENTITY % phrase "em | strong | dfn | code | q |
+ samp | kbd | var | cite | abbr | acronym | sub | sup ">
+
+<!ENTITY % inline.forms "input | select | textarea | label | button">
+
+<!-- these can occur at block or inline level -->
+<!ENTITY % misc.inline "ins | del | script">
+
+<!-- these can only occur at block level -->
+<!ENTITY % misc "noscript | %misc.inline;">
+
+<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
+
+<!-- %Inline; covers inline or "text-level" elements -->
+<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
+
+<!--================== Block level elements ==============================-->
+
+<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
+<!ENTITY % lists "ul | ol | dl">
+<!ENTITY % blocktext "pre | hr | blockquote | address">
+
+<!ENTITY % block
+ "p | %heading; | div | %lists; | %blocktext; | fieldset | table">
+
+<!ENTITY % Block "(%block; | form | %misc;)*">
+
+<!-- %Flow; mixes block and inline and is used for list items etc. -->
+<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
+
+<!--================== Content models for exclusions =====================-->
+
+<!-- a elements use %Inline; excluding a -->
+
+<!ENTITY % a.content
+ "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
+
+<!-- pre uses %Inline excluding big, small, sup or sup -->
+
+<!ENTITY % pre.content
+ "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline;
+ | %inline.forms;)*">
+
+<!-- form uses %Block; excluding form -->
+
+<!ENTITY % form.content "(%block; | %misc;)*">
+
+<!-- button uses %Flow; but excludes a, form and form controls -->
+
+<!ENTITY % button.content
+ "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
+ table | %special; | %fontstyle; | %phrase; | %misc;)*">
+
+<!--================ Document Structure ==================================-->
+
+<!-- the namespace URI designates the document profile -->
+
+<!ELEMENT html (head, body)>
+<!ATTLIST html
+ %i18n;
+ id ID #IMPLIED
+ xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
+ >
+
+<!--================ Document Head =======================================-->
+
+<!ENTITY % head.misc "(script|style|meta|link|object)*">
+
+<!-- content model is %head.misc; combined with a single
+ title and an optional base element in any order -->
+
+<!ELEMENT head (%head.misc;,
+ ((title, %head.misc;, (base, %head.misc;)?) |
+ (base, %head.misc;, (title, %head.misc;))))>
+
+<!ATTLIST head
+ %i18n;
+ id ID #IMPLIED
+ profile %URI; #IMPLIED
+ >
+
+<!-- The title element is not considered part of the flow of text.
+ It should be displayed, for example as the page header or
+ window title. Exactly one title is required per document.
+ -->
+<!ELEMENT title (#PCDATA)>
+<!ATTLIST title
+ %i18n;
+ id ID #IMPLIED
+ >
+
+<!-- document base URI -->
+
+<!ELEMENT base EMPTY>
+<!ATTLIST base
+ href %URI; #REQUIRED
+ id ID #IMPLIED
+ >
+
+<!-- generic metainformation -->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+ %i18n;
+ id ID #IMPLIED
+ http-equiv CDATA #IMPLIED
+ name CDATA #IMPLIED
+ content CDATA #REQUIRED
+ scheme CDATA #IMPLIED
+ >
+
+<!--
+ Relationship values can be used in principle:
+
+ a) for document specific toolbars/menus when used
+ with the link element in document head e.g.
+ start, contents, previous, next, index, end, help
+ b) to link to a separate style sheet (rel="stylesheet")
+ c) to make a link to a script (rel="script")
+ d) by stylesheets to control how collections of
+ html nodes are rendered into printed documents
+ e) to make a link to a printable version of this document
+ e.g. a PostScript or PDF version (rel="alternate" media="print")
+-->
+
+<!ELEMENT link EMPTY>
+<!ATTLIST link
+ %attrs;
+ charset %Charset; #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ type %ContentType; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ media %MediaDesc; #IMPLIED
+ >
+
+<!-- style info, which may include CDATA sections -->
+<!ELEMENT style (#PCDATA)>
+<!ATTLIST style
+ %i18n;
+ id ID #IMPLIED
+ type %ContentType; #REQUIRED
+ media %MediaDesc; #IMPLIED
+ title %Text; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- script statements, which may include CDATA sections -->
+<!ELEMENT script (#PCDATA)>
+<!ATTLIST script
+ id ID #IMPLIED
+ charset %Charset; #IMPLIED
+ type %ContentType; #REQUIRED
+ src %URI; #IMPLIED
+ defer (defer) #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- alternate content container for non script-based rendering -->
+
+<!ELEMENT noscript %Block;>
+<!ATTLIST noscript
+ %attrs;
+ >
+
+<!--=================== Document Body ====================================-->
+
+<!ELEMENT body %Block;>
+<!ATTLIST body
+ %attrs;
+ onload %Script; #IMPLIED
+ onunload %Script; #IMPLIED
+ >
+
+<!ELEMENT div %Flow;> <!-- generic language/style container -->
+<!ATTLIST div
+ %attrs;
+ >
+
+<!--=================== Paragraphs =======================================-->
+
+<!ELEMENT p %Inline;>
+<!ATTLIST p
+ %attrs;
+ >
+
+<!--=================== Headings =========================================-->
+
+<!--
+ There are six levels of headings from h1 (the most important)
+ to h6 (the least important).
+-->
+
+<!ELEMENT h1 %Inline;>
+<!ATTLIST h1
+ %attrs;
+ >
+
+<!ELEMENT h2 %Inline;>
+<!ATTLIST h2
+ %attrs;
+ >
+
+<!ELEMENT h3 %Inline;>
+<!ATTLIST h3
+ %attrs;
+ >
+
+<!ELEMENT h4 %Inline;>
+<!ATTLIST h4
+ %attrs;
+ >
+
+<!ELEMENT h5 %Inline;>
+<!ATTLIST h5
+ %attrs;
+ >
+
+<!ELEMENT h6 %Inline;>
+<!ATTLIST h6
+ %attrs;
+ >
+
+<!--=================== Lists ============================================-->
+
+<!-- Unordered list -->
+
+<!ELEMENT ul (li)+>
+<!ATTLIST ul
+ %attrs;
+ >
+
+<!-- Ordered (numbered) list -->
+
+<!ELEMENT ol (li)+>
+<!ATTLIST ol
+ %attrs;
+ >
+
+<!-- list item -->
+
+<!ELEMENT li %Flow;>
+<!ATTLIST li
+ %attrs;
+ >
+
+<!-- definition lists - dt for term, dd for its definition -->
+
+<!ELEMENT dl (dt|dd)+>
+<!ATTLIST dl
+ %attrs;
+ >
+
+<!ELEMENT dt %Inline;>
+<!ATTLIST dt
+ %attrs;
+ >
+
+<!ELEMENT dd %Flow;>
+<!ATTLIST dd
+ %attrs;
+ >
+
+<!--=================== Address ==========================================-->
+
+<!-- information on author -->
+
+<!ELEMENT address %Inline;>
+<!ATTLIST address
+ %attrs;
+ >
+
+<!--=================== Horizontal Rule ==================================-->
+
+<!ELEMENT hr EMPTY>
+<!ATTLIST hr
+ %attrs;
+ >
+
+<!--=================== Preformatted Text ================================-->
+
+<!-- content is %Inline; excluding "img|object|big|small|sub|sup" -->
+
+<!ELEMENT pre %pre.content;>
+<!ATTLIST pre
+ %attrs;
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!--=================== Block-like Quotes ================================-->
+
+<!ELEMENT blockquote %Block;>
+<!ATTLIST blockquote
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!--=================== Inserted/Deleted Text ============================-->
+
+<!--
+ ins/del are allowed in block and inline content, but its
+ inappropriate to include block content within an ins element
+ occurring in inline content.
+-->
+<!ELEMENT ins %Flow;>
+<!ATTLIST ins
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!ELEMENT del %Flow;>
+<!ATTLIST del
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!--================== The Anchor Element ================================-->
+
+<!-- content is %Inline; except that anchors shouldn't be nested -->
+
+<!ELEMENT a %a.content;>
+<!ATTLIST a
+ %attrs;
+ %focus;
+ charset %Charset; #IMPLIED
+ type %ContentType; #IMPLIED
+ name NMTOKEN #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ >
+
+<!--===================== Inline Elements ================================-->
+
+<!ELEMENT span %Inline;> <!-- generic language/style container -->
+<!ATTLIST span
+ %attrs;
+ >
+
+<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
+<!ATTLIST bdo
+ %coreattrs;
+ %events;
+ lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #REQUIRED
+ >
+
+<!ELEMENT br EMPTY> <!-- forced line break -->
+<!ATTLIST br
+ %coreattrs;
+ >
+
+<!ELEMENT em %Inline;> <!-- emphasis -->
+<!ATTLIST em %attrs;>
+
+<!ELEMENT strong %Inline;> <!-- strong emphasis -->
+<!ATTLIST strong %attrs;>
+
+<!ELEMENT dfn %Inline;> <!-- definitional -->
+<!ATTLIST dfn %attrs;>
+
+<!ELEMENT code %Inline;> <!-- program code -->
+<!ATTLIST code %attrs;>
+
+<!ELEMENT samp %Inline;> <!-- sample -->
+<!ATTLIST samp %attrs;>
+
+<!ELEMENT kbd %Inline;> <!-- something user would type -->
+<!ATTLIST kbd %attrs;>
+
+<!ELEMENT var %Inline;> <!-- variable -->
+<!ATTLIST var %attrs;>
+
+<!ELEMENT cite %Inline;> <!-- citation -->
+<!ATTLIST cite %attrs;>
+
+<!ELEMENT abbr %Inline;> <!-- abbreviation -->
+<!ATTLIST abbr %attrs;>
+
+<!ELEMENT acronym %Inline;> <!-- acronym -->
+<!ATTLIST acronym %attrs;>
+
+<!ELEMENT q %Inline;> <!-- inlined quote -->
+<!ATTLIST q
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!ELEMENT sub %Inline;> <!-- subscript -->
+<!ATTLIST sub %attrs;>
+
+<!ELEMENT sup %Inline;> <!-- superscript -->
+<!ATTLIST sup %attrs;>
+
+<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
+<!ATTLIST tt %attrs;>
+
+<!ELEMENT i %Inline;> <!-- italic font -->
+<!ATTLIST i %attrs;>
+
+<!ELEMENT b %Inline;> <!-- bold font -->
+<!ATTLIST b %attrs;>
+
+<!ELEMENT big %Inline;> <!-- bigger font -->
+<!ATTLIST big %attrs;>
+
+<!ELEMENT small %Inline;> <!-- smaller font -->
+<!ATTLIST small %attrs;>
+
+<!--==================== Object ======================================-->
+<!--
+ object is used to embed objects as part of HTML pages.
+ param elements should precede other content. Parameters
+ can also be expressed as attribute/value pairs on the
+ object element itself when brevity is desired.
+-->
+
+<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
+<!ATTLIST object
+ %attrs;
+ declare (declare) #IMPLIED
+ classid %URI; #IMPLIED
+ codebase %URI; #IMPLIED
+ data %URI; #IMPLIED
+ type %ContentType; #IMPLIED
+ codetype %ContentType; #IMPLIED
+ archive %UriList; #IMPLIED
+ standby %Text; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ tabindex %Number; #IMPLIED
+ >
+
+<!--
+ param is used to supply a named property value.
+ In XML it would seem natural to follow RDF and support an
+ abbreviated syntax where the param elements are replaced
+ by attribute value pairs on the object start tag.
+-->
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+ id ID #IMPLIED
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ valuetype (data|ref|object) "data"
+ type %ContentType; #IMPLIED
+ >
+
+<!--=================== Images ===========================================-->
+
+<!--
+ To avoid accessibility problems for people who aren't
+ able to see the image, you should provide a text
+ description using the alt and longdesc attributes.
+ In addition, avoid the use of server-side image maps.
+ Note that in this DTD there is no name attribute. That
+ is only available in the transitional and frameset DTD.
+-->
+
+<!ELEMENT img EMPTY>
+<!ATTLIST img
+ %attrs;
+ src %URI; #REQUIRED
+ alt %Text; #REQUIRED
+ longdesc %URI; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ ismap (ismap) #IMPLIED
+ >
+
+<!-- usemap points to a map element which may be in this document
+ or an external document, although the latter is not widely supported -->
+
+<!--================== Client-side image maps ============================-->
+
+<!-- These can be placed in the same document or grouped in a
+ separate document although this isn't yet widely supported -->
+
+<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
+<!ATTLIST map
+ %i18n;
+ %events;
+ id ID #REQUIRED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED
+ name NMTOKEN #IMPLIED
+ >
+
+<!ELEMENT area EMPTY>
+<!ATTLIST area
+ %attrs;
+ %focus;
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ href %URI; #IMPLIED
+ nohref (nohref) #IMPLIED
+ alt %Text; #REQUIRED
+ >
+
+<!--================ Forms ===============================================-->
+<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
+
+<!ATTLIST form
+ %attrs;
+ action %URI; #REQUIRED
+ method (get|post) "get"
+ enctype %ContentType; "application/x-www-form-urlencoded"
+ onsubmit %Script; #IMPLIED
+ onreset %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ accept-charset %Charsets; #IMPLIED
+ >
+
+<!--
+ Each label must not contain more than ONE field
+ Label elements shouldn't be nested.
+-->
+<!ELEMENT label %Inline;>
+<!ATTLIST label
+ %attrs;
+ for IDREF #IMPLIED
+ accesskey %Character; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ >
+
+<!ENTITY % InputType
+ "(text | password | checkbox |
+ radio | submit | reset |
+ file | hidden | image | button)"
+ >
+
+<!-- the name attribute is required for all but submit & reset -->
+
+<!ELEMENT input EMPTY> <!-- form control -->
+<!ATTLIST input
+ %attrs;
+ %focus;
+ type %InputType; "text"
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ checked (checked) #IMPLIED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ size CDATA #IMPLIED
+ maxlength %Number; #IMPLIED
+ src %URI; #IMPLIED
+ alt CDATA #IMPLIED
+ usemap %URI; #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ >
+
+<!ELEMENT select (optgroup|option)+> <!-- option selector -->
+<!ATTLIST select
+ %attrs;
+ name CDATA #IMPLIED
+ size %Number; #IMPLIED
+ multiple (multiple) #IMPLIED
+ disabled (disabled) #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!ELEMENT optgroup (option)+> <!-- option group -->
+<!ATTLIST optgroup
+ %attrs;
+ disabled (disabled) #IMPLIED
+ label %Text; #REQUIRED
+ >
+
+<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
+<!ATTLIST option
+ %attrs;
+ selected (selected) #IMPLIED
+ disabled (disabled) #IMPLIED
+ label %Text; #IMPLIED
+ value CDATA #IMPLIED
+ >
+
+<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
+<!ATTLIST textarea
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ rows %Number; #REQUIRED
+ cols %Number; #REQUIRED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!--
+ The fieldset element is used to group form fields.
+ Only one legend element should occur in the content
+ and if present should only be preceded by whitespace.
+-->
+<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
+<!ATTLIST fieldset
+ %attrs;
+ >
+
+<!ELEMENT legend %Inline;> <!-- fieldset label -->
+<!ATTLIST legend
+ %attrs;
+ accesskey %Character; #IMPLIED
+ >
+
+<!--
+ Content is %Flow; excluding a, form and form controls
+-->
+<!ELEMENT button %button.content;> <!-- push button -->
+<!ATTLIST button
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ type (button|submit|reset) "submit"
+ disabled (disabled) #IMPLIED
+ >
+
+<!--======================= Tables =======================================-->
+
+<!-- Derived from IETF HTML table standard, see [RFC1942] -->
+
+<!--
+ The border attribute sets the thickness of the frame around the
+ table. The default units are screen pixels.
+
+ The frame attribute specifies which parts of the frame around
+ the table should be rendered. The values are not the same as
+ CALS to avoid a name clash with the valign attribute.
+-->
+<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
+
+<!--
+ The rules attribute defines which rules to draw between cells:
+
+ If rules is absent then assume:
+ "none" if border is absent or border="0" otherwise "all"
+-->
+
+<!ENTITY % TRules "(none | groups | rows | cols | all)">
+
+<!-- horizontal alignment attributes for cell contents
+
+ char alignment char, e.g. char=':'
+ charoff offset for alignment char
+-->
+<!ENTITY % cellhalign
+ "align (left|center|right|justify|char) #IMPLIED
+ char %Character; #IMPLIED
+ charoff %Length; #IMPLIED"
+ >
+
+<!-- vertical alignment attributes for cell contents -->
+<!ENTITY % cellvalign
+ "valign (top|middle|bottom|baseline) #IMPLIED"
+ >
+
+<!ELEMENT table
+ (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
+<!ELEMENT caption %Inline;>
+<!ELEMENT thead (tr)+>
+<!ELEMENT tfoot (tr)+>
+<!ELEMENT tbody (tr)+>
+<!ELEMENT colgroup (col)*>
+<!ELEMENT col EMPTY>
+<!ELEMENT tr (th|td)+>
+<!ELEMENT th %Flow;>
+<!ELEMENT td %Flow;>
+
+<!ATTLIST table
+ %attrs;
+ summary %Text; #IMPLIED
+ width %Length; #IMPLIED
+ border %Pixels; #IMPLIED
+ frame %TFrame; #IMPLIED
+ rules %TRules; #IMPLIED
+ cellspacing %Length; #IMPLIED
+ cellpadding %Length; #IMPLIED
+ >
+
+<!ATTLIST caption
+ %attrs;
+ >
+
+<!--
+colgroup groups a set of col elements. It allows you to group
+several semantically related columns together.
+-->
+<!ATTLIST colgroup
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ col elements define the alignment properties for cells in
+ one or more columns.
+
+ The width attribute specifies the width of the columns, e.g.
+
+ width=64 width in screen pixels
+ width=0.5* relative width of 0.5
+
+ The span attribute causes the attributes of one
+ col element to apply to more than one column.
+-->
+<!ATTLIST col
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ Use thead to duplicate headers when breaking table
+ across page boundaries, or for static headers when
+ tbody sections are rendered in scrolling panel.
+
+ Use tfoot to duplicate footers when breaking table
+ across page boundaries, or for static footers when
+ tbody sections are rendered in scrolling panel.
+
+ Use multiple tbody sections when rules are needed
+ between groups of table rows.
+-->
+<!ATTLIST thead
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tfoot
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tbody
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tr
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+
+<!-- Scope is simpler than headers attribute for common tables -->
+<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
+
+<!-- th is for headers, td for data and for cells acting as both -->
+
+<!ATTLIST th
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST td
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ >
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-transitional.dtd b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-transitional.dtd
new file mode 100644
index 0000000000..628f27ac50
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml1-transitional.dtd
@@ -0,0 +1,1201 @@
+<!--
+ Extensible HTML version 1.0 Transitional DTD
+
+ This is the same as HTML 4 Transitional except for
+ changes due to the differences between XML and SGML.
+
+ Namespace = http://www.w3.org/1999/xhtml
+
+ For further information, see: http://www.w3.org/TR/xhtml1
+
+ Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
+ All Rights Reserved.
+
+ This DTD module is identified by the PUBLIC and SYSTEM identifiers:
+
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
+
+ $Revision: 1.2 $
+ $Date: 2002/08/01 18:37:55 $
+
+-->
+
+<!--================ Character mnemonic entities =========================-->
+
+<!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "xhtml-lat1.ent">
+%HTMLlat1;
+
+<!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "xhtml-symbol.ent">
+%HTMLsymbol;
+
+<!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "xhtml-special.ent">
+%HTMLspecial;
+
+<!--================== Imported Names ====================================-->
+
+<!ENTITY % ContentType "CDATA">
+ <!-- media type, as per [RFC2045] -->
+
+<!ENTITY % ContentTypes "CDATA">
+ <!-- comma-separated list of media types, as per [RFC2045] -->
+
+<!ENTITY % Charset "CDATA">
+ <!-- a character encoding, as per [RFC2045] -->
+
+<!ENTITY % Charsets "CDATA">
+ <!-- a space separated list of character encodings, as per [RFC2045] -->
+
+<!ENTITY % LanguageCode "NMTOKEN">
+ <!-- a language code, as per [RFC3066] -->
+
+<!ENTITY % Character "CDATA">
+ <!-- a single character, as per section 2.2 of [XML] -->
+
+<!ENTITY % Number "CDATA">
+ <!-- one or more digits -->
+
+<!ENTITY % LinkTypes "CDATA">
+ <!-- space-separated list of link types -->
+
+<!ENTITY % MediaDesc "CDATA">
+ <!-- single or comma-separated list of media descriptors -->
+
+<!ENTITY % URI "CDATA">
+ <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+ <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % Datetime "CDATA">
+ <!-- date and time information. ISO date format -->
+
+<!ENTITY % Script "CDATA">
+ <!-- script expression -->
+
+<!ENTITY % StyleSheet "CDATA">
+ <!-- style sheet data -->
+
+<!ENTITY % Text "CDATA">
+ <!-- used for titles etc. -->
+
+<!ENTITY % FrameTarget "NMTOKEN">
+ <!-- render in this frame -->
+
+<!ENTITY % Length "CDATA">
+ <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % MultiLength "CDATA">
+ <!-- pixel, percentage, or relative -->
+
+<!ENTITY % Pixels "CDATA">
+ <!-- integer representing length in pixels -->
+
+<!-- these are used for image maps -->
+
+<!ENTITY % Shape "(rect|circle|poly|default)">
+
+<!ENTITY % Coords "CDATA">
+ <!-- comma separated list of lengths -->
+
+<!-- used for object, applet, img, input and iframe -->
+<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
+
+<!-- a color using sRGB: #RRGGBB as Hex values -->
+<!ENTITY % Color "CDATA">
+
+<!-- There are also 16 widely known color names with their sRGB values:
+
+ Black = #000000 Green = #008000
+ Silver = #C0C0C0 Lime = #00FF00
+ Gray = #808080 Olive = #808000
+ White = #FFFFFF Yellow = #FFFF00
+ Maroon = #800000 Navy = #000080
+ Red = #FF0000 Blue = #0000FF
+ Purple = #800080 Teal = #008080
+ Fuchsia= #FF00FF Aqua = #00FFFF
+-->
+
+<!--=================== Generic Attributes ===============================-->
+
+<!-- core attributes common to most elements
+ id document-wide unique id
+ class space separated list of classes
+ style associated style info
+ title advisory title/amplification
+-->
+<!ENTITY % coreattrs
+ "id ID #IMPLIED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED"
+ >
+
+<!-- internationalization attributes
+ lang language code (backwards compatible)
+ xml:lang language code (as per XML 1.0 spec)
+ dir direction for weak/neutral text
+-->
+<!ENTITY % i18n
+ "lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #IMPLIED"
+ >
+
+<!-- attributes for common UI events
+ onclick a pointer button was clicked
+ ondblclick a pointer button was double clicked
+ onmousedown a pointer button was pressed down
+ onmouseup a pointer button was released
+ onmousemove a pointer was moved onto the element
+ onmouseout a pointer was moved away from the element
+ onkeypress a key was pressed and released
+ onkeydown a key was pressed down
+ onkeyup a key was released
+-->
+<!ENTITY % events
+ "onclick %Script; #IMPLIED
+ ondblclick %Script; #IMPLIED
+ onmousedown %Script; #IMPLIED
+ onmouseup %Script; #IMPLIED
+ onmouseover %Script; #IMPLIED
+ onmousemove %Script; #IMPLIED
+ onmouseout %Script; #IMPLIED
+ onkeypress %Script; #IMPLIED
+ onkeydown %Script; #IMPLIED
+ onkeyup %Script; #IMPLIED"
+ >
+
+<!-- attributes for elements that can get the focus
+ accesskey accessibility key character
+ tabindex position in tabbing order
+ onfocus the element got the focus
+ onblur the element lost the focus
+-->
+<!ENTITY % focus
+ "accesskey %Character; #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED"
+ >
+
+<!ENTITY % attrs "%coreattrs; %i18n; %events;">
+
+<!-- text alignment for p, div, h1-h6. The default is
+ align="left" for ltr headings, "right" for rtl -->
+
+<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">
+
+<!--=================== Text Elements ====================================-->
+
+<!ENTITY % special.extra
+ "object | applet | img | map | iframe">
+
+<!ENTITY % special.basic
+ "br | span | bdo">
+
+<!ENTITY % special
+ "%special.basic; | %special.extra;">
+
+<!ENTITY % fontstyle.extra "big | small | font | basefont">
+
+<!ENTITY % fontstyle.basic "tt | i | b | u
+ | s | strike ">
+
+<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;">
+
+<!ENTITY % phrase.extra "sub | sup">
+<!ENTITY % phrase.basic "em | strong | dfn | code | q |
+ samp | kbd | var | cite | abbr | acronym">
+
+<!ENTITY % phrase "%phrase.basic; | %phrase.extra;">
+
+<!ENTITY % inline.forms "input | select | textarea | label | button">
+
+<!-- these can occur at block or inline level -->
+<!ENTITY % misc.inline "ins | del | script">
+
+<!-- these can only occur at block level -->
+<!ENTITY % misc "noscript | %misc.inline;">
+
+<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
+
+<!-- %Inline; covers inline or "text-level" elements -->
+<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
+
+<!--================== Block level elements ==============================-->
+
+<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
+<!ENTITY % lists "ul | ol | dl | menu | dir">
+<!ENTITY % blocktext "pre | hr | blockquote | address | center | noframes">
+
+<!ENTITY % block
+ "p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table">
+
+<!-- %Flow; mixes block and inline and is used for list items etc. -->
+<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
+
+<!--================== Content models for exclusions =====================-->
+
+<!-- a elements use %Inline; excluding a -->
+
+<!ENTITY % a.content
+ "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
+
+<!-- pre uses %Inline excluding img, object, applet, big, small,
+ font, or basefont -->
+
+<!ENTITY % pre.content
+ "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; |
+ %inline.forms; | %misc.inline;)*">
+
+<!-- form uses %Flow; excluding form -->
+
+<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*">
+
+<!-- button uses %Flow; but excludes a, form, form controls, iframe -->
+
+<!ENTITY % button.content
+ "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
+ table | br | span | bdo | object | applet | img | map |
+ %fontstyle; | %phrase; | %misc;)*">
+
+<!--================ Document Structure ==================================-->
+
+<!-- the namespace URI designates the document profile -->
+
+<!ELEMENT html (head, body)>
+<!ATTLIST html
+ %i18n;
+ id ID #IMPLIED
+ xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
+ >
+
+<!--================ Document Head =======================================-->
+
+<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*">
+
+<!-- content model is %head.misc; combined with a single
+ title and an optional base element in any order -->
+
+<!ELEMENT head (%head.misc;,
+ ((title, %head.misc;, (base, %head.misc;)?) |
+ (base, %head.misc;, (title, %head.misc;))))>
+
+<!ATTLIST head
+ %i18n;
+ id ID #IMPLIED
+ profile %URI; #IMPLIED
+ >
+
+<!-- The title element is not considered part of the flow of text.
+ It should be displayed, for example as the page header or
+ window title. Exactly one title is required per document.
+ -->
+<!ELEMENT title (#PCDATA)>
+<!ATTLIST title
+ %i18n;
+ id ID #IMPLIED
+ >
+
+<!-- document base URI -->
+
+<!ELEMENT base EMPTY>
+<!ATTLIST base
+ id ID #IMPLIED
+ href %URI; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!-- generic metainformation -->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+ %i18n;
+ id ID #IMPLIED
+ http-equiv CDATA #IMPLIED
+ name CDATA #IMPLIED
+ content CDATA #REQUIRED
+ scheme CDATA #IMPLIED
+ >
+
+<!--
+ Relationship values can be used in principle:
+
+ a) for document specific toolbars/menus when used
+ with the link element in document head e.g.
+ start, contents, previous, next, index, end, help
+ b) to link to a separate style sheet (rel="stylesheet")
+ c) to make a link to a script (rel="script")
+ d) by stylesheets to control how collections of
+ html nodes are rendered into printed documents
+ e) to make a link to a printable version of this document
+ e.g. a PostScript or PDF version (rel="alternate" media="print")
+-->
+
+<!ELEMENT link EMPTY>
+<!ATTLIST link
+ %attrs;
+ charset %Charset; #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ type %ContentType; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ media %MediaDesc; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!-- style info, which may include CDATA sections -->
+<!ELEMENT style (#PCDATA)>
+<!ATTLIST style
+ %i18n;
+ id ID #IMPLIED
+ type %ContentType; #REQUIRED
+ media %MediaDesc; #IMPLIED
+ title %Text; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- script statements, which may include CDATA sections -->
+<!ELEMENT script (#PCDATA)>
+<!ATTLIST script
+ id ID #IMPLIED
+ charset %Charset; #IMPLIED
+ type %ContentType; #REQUIRED
+ language CDATA #IMPLIED
+ src %URI; #IMPLIED
+ defer (defer) #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- alternate content container for non script-based rendering -->
+
+<!ELEMENT noscript %Flow;>
+<!ATTLIST noscript
+ %attrs;
+ >
+
+<!--======================= Frames =======================================-->
+
+<!-- inline subwindow -->
+
+<!ELEMENT iframe %Flow;>
+<!ATTLIST iframe
+ %coreattrs;
+ longdesc %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ src %URI; #IMPLIED
+ frameborder (1|0) "1"
+ marginwidth %Pixels; #IMPLIED
+ marginheight %Pixels; #IMPLIED
+ scrolling (yes|no|auto) "auto"
+ align %ImgAlign; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ >
+
+<!-- alternate content container for non frame-based rendering -->
+
+<!ELEMENT noframes %Flow;>
+<!ATTLIST noframes
+ %attrs;
+ >
+
+<!--=================== Document Body ====================================-->
+
+<!ELEMENT body %Flow;>
+<!ATTLIST body
+ %attrs;
+ onload %Script; #IMPLIED
+ onunload %Script; #IMPLIED
+ background %URI; #IMPLIED
+ bgcolor %Color; #IMPLIED
+ text %Color; #IMPLIED
+ link %Color; #IMPLIED
+ vlink %Color; #IMPLIED
+ alink %Color; #IMPLIED
+ >
+
+<!ELEMENT div %Flow;> <!-- generic language/style container -->
+<!ATTLIST div
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Paragraphs =======================================-->
+
+<!ELEMENT p %Inline;>
+<!ATTLIST p
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Headings =========================================-->
+
+<!--
+ There are six levels of headings from h1 (the most important)
+ to h6 (the least important).
+-->
+
+<!ELEMENT h1 %Inline;>
+<!ATTLIST h1
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h2 %Inline;>
+<!ATTLIST h2
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h3 %Inline;>
+<!ATTLIST h3
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h4 %Inline;>
+<!ATTLIST h4
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h5 %Inline;>
+<!ATTLIST h5
+ %attrs;
+ %TextAlign;
+ >
+
+<!ELEMENT h6 %Inline;>
+<!ATTLIST h6
+ %attrs;
+ %TextAlign;
+ >
+
+<!--=================== Lists ============================================-->
+
+<!-- Unordered list bullet styles -->
+
+<!ENTITY % ULStyle "(disc|square|circle)">
+
+<!-- Unordered list -->
+
+<!ELEMENT ul (li)+>
+<!ATTLIST ul
+ %attrs;
+ type %ULStyle; #IMPLIED
+ compact (compact) #IMPLIED
+ >
+
+<!-- Ordered list numbering style
+
+ 1 arabic numbers 1, 2, 3, ...
+ a lower alpha a, b, c, ...
+ A upper alpha A, B, C, ...
+ i lower roman i, ii, iii, ...
+ I upper roman I, II, III, ...
+
+ The style is applied to the sequence number which by default
+ is reset to 1 for the first list item in an ordered list.
+-->
+<!ENTITY % OLStyle "CDATA">
+
+<!-- Ordered (numbered) list -->
+
+<!ELEMENT ol (li)+>
+<!ATTLIST ol
+ %attrs;
+ type %OLStyle; #IMPLIED
+ compact (compact) #IMPLIED
+ start %Number; #IMPLIED
+ >
+
+<!-- single column list (DEPRECATED) -->
+<!ELEMENT menu (li)+>
+<!ATTLIST menu
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!-- multiple column list (DEPRECATED) -->
+<!ELEMENT dir (li)+>
+<!ATTLIST dir
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" -->
+<!ENTITY % LIStyle "CDATA">
+
+<!-- list item -->
+
+<!ELEMENT li %Flow;>
+<!ATTLIST li
+ %attrs;
+ type %LIStyle; #IMPLIED
+ value %Number; #IMPLIED
+ >
+
+<!-- definition lists - dt for term, dd for its definition -->
+
+<!ELEMENT dl (dt|dd)+>
+<!ATTLIST dl
+ %attrs;
+ compact (compact) #IMPLIED
+ >
+
+<!ELEMENT dt %Inline;>
+<!ATTLIST dt
+ %attrs;
+ >
+
+<!ELEMENT dd %Flow;>
+<!ATTLIST dd
+ %attrs;
+ >
+
+<!--=================== Address ==========================================-->
+
+<!-- information on author -->
+
+<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*>
+<!ATTLIST address
+ %attrs;
+ >
+
+<!--=================== Horizontal Rule ==================================-->
+
+<!ELEMENT hr EMPTY>
+<!ATTLIST hr
+ %attrs;
+ align (left|center|right) #IMPLIED
+ noshade (noshade) #IMPLIED
+ size %Pixels; #IMPLIED
+ width %Length; #IMPLIED
+ >
+
+<!--=================== Preformatted Text ================================-->
+
+<!-- content is %Inline; excluding
+ "img|object|applet|big|small|sub|sup|font|basefont" -->
+
+<!ELEMENT pre %pre.content;>
+<!ATTLIST pre
+ %attrs;
+ width %Number; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!--=================== Block-like Quotes ================================-->
+
+<!ELEMENT blockquote %Flow;>
+<!ATTLIST blockquote
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!--=================== Text alignment ===================================-->
+
+<!-- center content -->
+<!ELEMENT center %Flow;>
+<!ATTLIST center
+ %attrs;
+ >
+
+<!--=================== Inserted/Deleted Text ============================-->
+
+<!--
+ ins/del are allowed in block and inline content, but its
+ inappropriate to include block content within an ins element
+ occurring in inline content.
+-->
+<!ELEMENT ins %Flow;>
+<!ATTLIST ins
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!ELEMENT del %Flow;>
+<!ATTLIST del
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!--================== The Anchor Element ================================-->
+
+<!-- content is %Inline; except that anchors shouldn't be nested -->
+
+<!ELEMENT a %a.content;>
+<!ATTLIST a
+ %attrs;
+ %focus;
+ charset %Charset; #IMPLIED
+ type %ContentType; #IMPLIED
+ name NMTOKEN #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--===================== Inline Elements ================================-->
+
+<!ELEMENT span %Inline;> <!-- generic language/style container -->
+<!ATTLIST span
+ %attrs;
+ >
+
+<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
+<!ATTLIST bdo
+ %coreattrs;
+ %events;
+ lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #REQUIRED
+ >
+
+<!ELEMENT br EMPTY> <!-- forced line break -->
+<!ATTLIST br
+ %coreattrs;
+ clear (left|all|right|none) "none"
+ >
+
+<!ELEMENT em %Inline;> <!-- emphasis -->
+<!ATTLIST em %attrs;>
+
+<!ELEMENT strong %Inline;> <!-- strong emphasis -->
+<!ATTLIST strong %attrs;>
+
+<!ELEMENT dfn %Inline;> <!-- definitional -->
+<!ATTLIST dfn %attrs;>
+
+<!ELEMENT code %Inline;> <!-- program code -->
+<!ATTLIST code %attrs;>
+
+<!ELEMENT samp %Inline;> <!-- sample -->
+<!ATTLIST samp %attrs;>
+
+<!ELEMENT kbd %Inline;> <!-- something user would type -->
+<!ATTLIST kbd %attrs;>
+
+<!ELEMENT var %Inline;> <!-- variable -->
+<!ATTLIST var %attrs;>
+
+<!ELEMENT cite %Inline;> <!-- citation -->
+<!ATTLIST cite %attrs;>
+
+<!ELEMENT abbr %Inline;> <!-- abbreviation -->
+<!ATTLIST abbr %attrs;>
+
+<!ELEMENT acronym %Inline;> <!-- acronym -->
+<!ATTLIST acronym %attrs;>
+
+<!ELEMENT q %Inline;> <!-- inlined quote -->
+<!ATTLIST q
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!ELEMENT sub %Inline;> <!-- subscript -->
+<!ATTLIST sub %attrs;>
+
+<!ELEMENT sup %Inline;> <!-- superscript -->
+<!ATTLIST sup %attrs;>
+
+<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
+<!ATTLIST tt %attrs;>
+
+<!ELEMENT i %Inline;> <!-- italic font -->
+<!ATTLIST i %attrs;>
+
+<!ELEMENT b %Inline;> <!-- bold font -->
+<!ATTLIST b %attrs;>
+
+<!ELEMENT big %Inline;> <!-- bigger font -->
+<!ATTLIST big %attrs;>
+
+<!ELEMENT small %Inline;> <!-- smaller font -->
+<!ATTLIST small %attrs;>
+
+<!ELEMENT u %Inline;> <!-- underline -->
+<!ATTLIST u %attrs;>
+
+<!ELEMENT s %Inline;> <!-- strike-through -->
+<!ATTLIST s %attrs;>
+
+<!ELEMENT strike %Inline;> <!-- strike-through -->
+<!ATTLIST strike %attrs;>
+
+<!ELEMENT basefont EMPTY> <!-- base font size -->
+<!ATTLIST basefont
+ id ID #IMPLIED
+ size CDATA #REQUIRED
+ color %Color; #IMPLIED
+ face CDATA #IMPLIED
+ >
+
+<!ELEMENT font %Inline;> <!-- local change to font -->
+<!ATTLIST font
+ %coreattrs;
+ %i18n;
+ size CDATA #IMPLIED
+ color %Color; #IMPLIED
+ face CDATA #IMPLIED
+ >
+
+<!--==================== Object ======================================-->
+<!--
+ object is used to embed objects as part of HTML pages.
+ param elements should precede other content. Parameters
+ can also be expressed as attribute/value pairs on the
+ object element itself when brevity is desired.
+-->
+
+<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
+<!ATTLIST object
+ %attrs;
+ declare (declare) #IMPLIED
+ classid %URI; #IMPLIED
+ codebase %URI; #IMPLIED
+ data %URI; #IMPLIED
+ type %ContentType; #IMPLIED
+ codetype %ContentType; #IMPLIED
+ archive %UriList; #IMPLIED
+ standby %Text; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ tabindex %Number; #IMPLIED
+ align %ImgAlign; #IMPLIED
+ border %Pixels; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!--
+ param is used to supply a named property value.
+ In XML it would seem natural to follow RDF and support an
+ abbreviated syntax where the param elements are replaced
+ by attribute value pairs on the object start tag.
+-->
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+ id ID #IMPLIED
+ name CDATA #REQUIRED
+ value CDATA #IMPLIED
+ valuetype (data|ref|object) "data"
+ type %ContentType; #IMPLIED
+ >
+
+<!--=================== Java applet ==================================-->
+<!--
+ One of code or object attributes must be present.
+ Place param elements before other content.
+-->
+<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*>
+<!ATTLIST applet
+ %coreattrs;
+ codebase %URI; #IMPLIED
+ archive CDATA #IMPLIED
+ code CDATA #IMPLIED
+ object CDATA #IMPLIED
+ alt %Text; #IMPLIED
+ name NMTOKEN #IMPLIED
+ width %Length; #REQUIRED
+ height %Length; #REQUIRED
+ align %ImgAlign; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!--=================== Images ===========================================-->
+
+<!--
+ To avoid accessibility problems for people who aren't
+ able to see the image, you should provide a text
+ description using the alt and longdesc attributes.
+ In addition, avoid the use of server-side image maps.
+-->
+
+<!ELEMENT img EMPTY>
+<!ATTLIST img
+ %attrs;
+ src %URI; #REQUIRED
+ alt %Text; #REQUIRED
+ name NMTOKEN #IMPLIED
+ longdesc %URI; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ ismap (ismap) #IMPLIED
+ align %ImgAlign; #IMPLIED
+ border %Length; #IMPLIED
+ hspace %Pixels; #IMPLIED
+ vspace %Pixels; #IMPLIED
+ >
+
+<!-- usemap points to a map element which may be in this document
+ or an external document, although the latter is not widely supported -->
+
+<!--================== Client-side image maps ============================-->
+
+<!-- These can be placed in the same document or grouped in a
+ separate document although this isn't yet widely supported -->
+
+<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
+<!ATTLIST map
+ %i18n;
+ %events;
+ id ID #REQUIRED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED
+ name CDATA #IMPLIED
+ >
+
+<!ELEMENT area EMPTY>
+<!ATTLIST area
+ %attrs;
+ %focus;
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ href %URI; #IMPLIED
+ nohref (nohref) #IMPLIED
+ alt %Text; #REQUIRED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--================ Forms ===============================================-->
+
+<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
+
+<!ATTLIST form
+ %attrs;
+ action %URI; #REQUIRED
+ method (get|post) "get"
+ name NMTOKEN #IMPLIED
+ enctype %ContentType; "application/x-www-form-urlencoded"
+ onsubmit %Script; #IMPLIED
+ onreset %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ accept-charset %Charsets; #IMPLIED
+ target %FrameTarget; #IMPLIED
+ >
+
+<!--
+ Each label must not contain more than ONE field
+ Label elements shouldn't be nested.
+-->
+<!ELEMENT label %Inline;>
+<!ATTLIST label
+ %attrs;
+ for IDREF #IMPLIED
+ accesskey %Character; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ >
+
+<!ENTITY % InputType
+ "(text | password | checkbox |
+ radio | submit | reset |
+ file | hidden | image | button)"
+ >
+
+<!-- the name attribute is required for all but submit & reset -->
+
+<!ELEMENT input EMPTY> <!-- form control -->
+<!ATTLIST input
+ %attrs;
+ %focus;
+ type %InputType; "text"
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ checked (checked) #IMPLIED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ size CDATA #IMPLIED
+ maxlength %Number; #IMPLIED
+ src %URI; #IMPLIED
+ alt CDATA #IMPLIED
+ usemap %URI; #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ align %ImgAlign; #IMPLIED
+ >
+
+<!ELEMENT select (optgroup|option)+> <!-- option selector -->
+<!ATTLIST select
+ %attrs;
+ name CDATA #IMPLIED
+ size %Number; #IMPLIED
+ multiple (multiple) #IMPLIED
+ disabled (disabled) #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!ELEMENT optgroup (option)+> <!-- option group -->
+<!ATTLIST optgroup
+ %attrs;
+ disabled (disabled) #IMPLIED
+ label %Text; #REQUIRED
+ >
+
+<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
+<!ATTLIST option
+ %attrs;
+ selected (selected) #IMPLIED
+ disabled (disabled) #IMPLIED
+ label %Text; #IMPLIED
+ value CDATA #IMPLIED
+ >
+
+<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
+<!ATTLIST textarea
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ rows %Number; #REQUIRED
+ cols %Number; #REQUIRED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!--
+ The fieldset element is used to group form fields.
+ Only one legend element should occur in the content
+ and if present should only be preceded by whitespace.
+-->
+<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
+<!ATTLIST fieldset
+ %attrs;
+ >
+
+<!ENTITY % LAlign "(top|bottom|left|right)">
+
+<!ELEMENT legend %Inline;> <!-- fieldset label -->
+<!ATTLIST legend
+ %attrs;
+ accesskey %Character; #IMPLIED
+ align %LAlign; #IMPLIED
+ >
+
+<!--
+ Content is %Flow; excluding a, form, form controls, iframe
+-->
+<!ELEMENT button %button.content;> <!-- push button -->
+<!ATTLIST button
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ type (button|submit|reset) "submit"
+ disabled (disabled) #IMPLIED
+ >
+
+<!-- single-line text input control (DEPRECATED) -->
+<!ELEMENT isindex EMPTY>
+<!ATTLIST isindex
+ %coreattrs;
+ %i18n;
+ prompt %Text; #IMPLIED
+ >
+
+<!--======================= Tables =======================================-->
+
+<!-- Derived from IETF HTML table standard, see [RFC1942] -->
+
+<!--
+ The border attribute sets the thickness of the frame around the
+ table. The default units are screen pixels.
+
+ The frame attribute specifies which parts of the frame around
+ the table should be rendered. The values are not the same as
+ CALS to avoid a name clash with the valign attribute.
+-->
+<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
+
+<!--
+ The rules attribute defines which rules to draw between cells:
+
+ If rules is absent then assume:
+ "none" if border is absent or border="0" otherwise "all"
+-->
+
+<!ENTITY % TRules "(none | groups | rows | cols | all)">
+
+<!-- horizontal placement of table relative to document -->
+<!ENTITY % TAlign "(left|center|right)">
+
+<!-- horizontal alignment attributes for cell contents
+
+ char alignment char, e.g. char=':'
+ charoff offset for alignment char
+-->
+<!ENTITY % cellhalign
+ "align (left|center|right|justify|char) #IMPLIED
+ char %Character; #IMPLIED
+ charoff %Length; #IMPLIED"
+ >
+
+<!-- vertical alignment attributes for cell contents -->
+<!ENTITY % cellvalign
+ "valign (top|middle|bottom|baseline) #IMPLIED"
+ >
+
+<!ELEMENT table
+ (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
+<!ELEMENT caption %Inline;>
+<!ELEMENT thead (tr)+>
+<!ELEMENT tfoot (tr)+>
+<!ELEMENT tbody (tr)+>
+<!ELEMENT colgroup (col)*>
+<!ELEMENT col EMPTY>
+<!ELEMENT tr (th|td)+>
+<!ELEMENT th %Flow;>
+<!ELEMENT td %Flow;>
+
+<!ATTLIST table
+ %attrs;
+ summary %Text; #IMPLIED
+ width %Length; #IMPLIED
+ border %Pixels; #IMPLIED
+ frame %TFrame; #IMPLIED
+ rules %TRules; #IMPLIED
+ cellspacing %Length; #IMPLIED
+ cellpadding %Length; #IMPLIED
+ align %TAlign; #IMPLIED
+ bgcolor %Color; #IMPLIED
+ >
+
+<!ENTITY % CAlign "(top|bottom|left|right)">
+
+<!ATTLIST caption
+ %attrs;
+ align %CAlign; #IMPLIED
+ >
+
+<!--
+colgroup groups a set of col elements. It allows you to group
+several semantically related columns together.
+-->
+<!ATTLIST colgroup
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ col elements define the alignment properties for cells in
+ one or more columns.
+
+ The width attribute specifies the width of the columns, e.g.
+
+ width=64 width in screen pixels
+ width=0.5* relative width of 0.5
+
+ The span attribute causes the attributes of one
+ col element to apply to more than one column.
+-->
+<!ATTLIST col
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ Use thead to duplicate headers when breaking table
+ across page boundaries, or for static headers when
+ tbody sections are rendered in scrolling panel.
+
+ Use tfoot to duplicate footers when breaking table
+ across page boundaries, or for static footers when
+ tbody sections are rendered in scrolling panel.
+
+ Use multiple tbody sections when rules are needed
+ between groups of table rows.
+-->
+<!ATTLIST thead
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tfoot
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tbody
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tr
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ bgcolor %Color; #IMPLIED
+ >
+
+<!-- Scope is simpler than headers attribute for common tables -->
+<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
+
+<!-- th is for headers, td for data and for cells acting as both -->
+
+<!ATTLIST th
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ nowrap (nowrap) #IMPLIED
+ bgcolor %Color; #IMPLIED
+ width %Length; #IMPLIED
+ height %Length; #IMPLIED
+ >
+
+<!ATTLIST td
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ nowrap (nowrap) #IMPLIED
+ bgcolor %Color; #IMPLIED
+ width %Length; #IMPLIED
+ height %Length; #IMPLIED
+ >
+
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml11.dtd b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml11.dtd
new file mode 100644
index 0000000000..2a999b5b37
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/catalog/xhtml11.dtd
@@ -0,0 +1,294 @@
+<!-- ....................................................................... -->
+<!-- XHTML 1.1 DTD ........................................................ -->
+<!-- file: xhtml11.dtd
+-->
+
+<!-- XHTML 1.1 DTD
+
+ This is XHTML, a reformulation of HTML as a modular XML application.
+
+ The Extensible HyperText Markup Language (XHTML)
+ Copyright 1998-2001 World Wide Web Consortium
+ (Massachusetts Institute of Technology, Institut National de
+ Recherche en Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ Permission to use, copy, modify and distribute the XHTML DTD and its
+ accompanying documentation for any purpose and without fee is hereby
+ granted in perpetuity, provided that the above copyright notice and
+ this paragraph appear in all copies. The copyright holders make no
+ representation about the suitability of the DTD for any purpose.
+
+ It is provided "as is" without expressed or implied warranty.
+
+ Author: Murray M. Altheim <altheim@eng.sun.com>
+ Revision: $Id: xhtml11.dtd,v 1.21 2001/05/29 16:37:01 ahby Exp $
+
+-->
+<!-- This is the driver file for version 1.1 of the XHTML DTD.
+
+ Please use this formal public identifier to identify it:
+
+ "-//W3C//DTD XHTML 1.1//EN"
+-->
+<!ENTITY % XHTML.version "-//W3C//DTD XHTML 1.1//EN" >
+
+<!-- Use this URI to identify the default namespace:
+
+ "http://www.w3.org/1999/xhtml"
+
+ See the Qualified Names module for information
+ on the use of namespace prefixes in the DTD.
+-->
+<!ENTITY % NS.prefixed "IGNORE" >
+<!ENTITY % XHTML.prefix "" >
+
+<!-- Reserved for use with the XLink namespace:
+-->
+<!ENTITY % XLINK.xmlns "" >
+<!ENTITY % XLINK.xmlns.attrib "" >
+
+<!-- For example, if you are using XHTML 1.1 directly, use the FPI
+ in the DOCTYPE declaration, with the xmlns attribute on the
+ document element to identify the default namespace:
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml"
+ xml:lang="en">
+ ...
+ </html>
+
+ Revisions:
+ (none)
+-->
+
+<!-- reserved for future use with document profiles -->
+<!ENTITY % XHTML.profile "" >
+
+<!-- Bidirectional Text features
+ This feature-test entity is used to declare elements
+ and attributes used for bidirectional text support.
+-->
+<!ENTITY % XHTML.bidi "INCLUDE" >
+
+<?doc type="doctype" role="title" { XHTML 1.1 } ?>
+
+<!-- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
+
+<!-- Pre-Framework Redeclaration placeholder .................... -->
+<!-- this serves as a location to insert markup declarations
+ into the DTD prior to the framework declarations.
+-->
+<!ENTITY % xhtml-prefw-redecl.module "IGNORE" >
+<![%xhtml-prefw-redecl.module;[
+%xhtml-prefw-redecl.mod;
+<!-- end of xhtml-prefw-redecl.module -->]]>
+
+<!ENTITY % xhtml-events.module "INCLUDE" >
+
+<!-- Inline Style Module ........................................ -->
+<!ENTITY % xhtml-inlstyle.module "INCLUDE" >
+<![%xhtml-inlstyle.module;[
+<!ENTITY % xhtml-inlstyle.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Inline Style 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-inlstyle-1.mod" >
+%xhtml-inlstyle.mod;]]>
+
+<!-- declare Document Model module instantiated in framework
+-->
+<!ENTITY % xhtml-model.mod
+ PUBLIC "-//W3C//ENTITIES XHTML 1.1 Document Model 1.0//EN"
+ "xhtml11-model-1.mod" >
+
+<!-- Modular Framework Module (required) ......................... -->
+<!ENTITY % xhtml-framework.module "INCLUDE" >
+<![%xhtml-framework.module;[
+<!ENTITY % xhtml-framework.mod
+ PUBLIC "-//W3C//ENTITIES XHTML Modular Framework 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-framework-1.mod" >
+%xhtml-framework.mod;]]>
+
+<!-- Post-Framework Redeclaration placeholder ................... -->
+<!-- this serves as a location to insert markup declarations
+ into the DTD following the framework declarations.
+-->
+<!ENTITY % xhtml-postfw-redecl.module "IGNORE" >
+<![%xhtml-postfw-redecl.module;[
+%xhtml-postfw-redecl.mod;
+<!-- end of xhtml-postfw-redecl.module -->]]>
+
+<!-- Text Module (Required) ..................................... -->
+<!ENTITY % xhtml-text.module "INCLUDE" >
+<![%xhtml-text.module;[
+<!ENTITY % xhtml-text.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Text 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-text-1.mod" >
+%xhtml-text.mod;]]>
+
+<!-- Hypertext Module (required) ................................. -->
+<!ENTITY % xhtml-hypertext.module "INCLUDE" >
+<![%xhtml-hypertext.module;[
+<!ENTITY % xhtml-hypertext.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Hypertext 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-hypertext-1.mod" >
+%xhtml-hypertext.mod;]]>
+
+<!-- Lists Module (required) .................................... -->
+<!ENTITY % xhtml-list.module "INCLUDE" >
+<![%xhtml-list.module;[
+<!ENTITY % xhtml-list.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Lists 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-list-1.mod" >
+%xhtml-list.mod;]]>
+
+<!-- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
+
+<!-- Edit Module ................................................ -->
+<!ENTITY % xhtml-edit.module "INCLUDE" >
+<![%xhtml-edit.module;[
+<!ENTITY % xhtml-edit.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Editing Elements 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-edit-1.mod" >
+%xhtml-edit.mod;]]>
+
+<!-- BIDI Override Module ....................................... -->
+<!ENTITY % xhtml-bdo.module "%XHTML.bidi;" >
+<![%xhtml-bdo.module;[
+<!ENTITY % xhtml-bdo.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML BIDI Override Element 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-bdo-1.mod" >
+%xhtml-bdo.mod;]]>
+
+<!-- Ruby Module ................................................ -->
+<!ENTITY % Ruby.common.attlists "INCLUDE" >
+<!ENTITY % Ruby.common.attrib "%Common.attrib;" >
+<!ENTITY % xhtml-ruby.module "INCLUDE" >
+<![%xhtml-ruby.module;[
+<!ENTITY % xhtml-ruby.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Ruby 1.0//EN"
+ "http://www.w3.org/TR/ruby/xhtml-ruby-1.mod" >
+%xhtml-ruby.mod;]]>
+
+<!-- Presentation Module ........................................ -->
+<!ENTITY % xhtml-pres.module "INCLUDE" >
+<![%xhtml-pres.module;[
+<!ENTITY % xhtml-pres.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Presentation 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-pres-1.mod" >
+%xhtml-pres.mod;]]>
+
+<!-- Link Element Module ........................................ -->
+<!ENTITY % xhtml-link.module "INCLUDE" >
+<![%xhtml-link.module;[
+<!ENTITY % xhtml-link.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Link Element 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-link-1.mod" >
+%xhtml-link.mod;]]>
+
+<!-- Document Metainformation Module ............................ -->
+<!ENTITY % xhtml-meta.module "INCLUDE" >
+<![%xhtml-meta.module;[
+<!ENTITY % xhtml-meta.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Metainformation 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-meta-1.mod" >
+%xhtml-meta.mod;]]>
+
+<!-- Base Element Module ........................................ -->
+<!ENTITY % xhtml-base.module "INCLUDE" >
+<![%xhtml-base.module;[
+<!ENTITY % xhtml-base.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Base Element 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-base-1.mod" >
+%xhtml-base.mod;]]>
+
+<!-- Scripting Module ........................................... -->
+<!ENTITY % xhtml-script.module "INCLUDE" >
+<![%xhtml-script.module;[
+<!ENTITY % xhtml-script.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Scripting 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-script-1.mod" >
+%xhtml-script.mod;]]>
+
+<!-- Style Sheets Module ......................................... -->
+<!ENTITY % xhtml-style.module "INCLUDE" >
+<![%xhtml-style.module;[
+<!ENTITY % xhtml-style.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Style Sheets 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-style-1.mod" >
+%xhtml-style.mod;]]>
+
+<!-- Image Module ............................................... -->
+<!ENTITY % xhtml-image.module "INCLUDE" >
+<![%xhtml-image.module;[
+<!ENTITY % xhtml-image.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Images 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-image-1.mod" >
+%xhtml-image.mod;]]>
+
+<!-- Client-side Image Map Module ............................... -->
+<!ENTITY % xhtml-csismap.module "INCLUDE" >
+<![%xhtml-csismap.module;[
+<!ENTITY % xhtml-csismap.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Client-side Image Maps 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-csismap-1.mod" >
+%xhtml-csismap.mod;]]>
+
+<!-- Server-side Image Map Module ............................... -->
+<!ENTITY % xhtml-ssismap.module "INCLUDE" >
+<![%xhtml-ssismap.module;[
+<!ENTITY % xhtml-ssismap.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Server-side Image Maps 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-ssismap-1.mod" >
+%xhtml-ssismap.mod;]]>
+
+<!-- Param Element Module ....................................... -->
+<!ENTITY % xhtml-param.module "INCLUDE" >
+<![%xhtml-param.module;[
+<!ENTITY % xhtml-param.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Param Element 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-param-1.mod" >
+%xhtml-param.mod;]]>
+
+<!-- Embedded Object Module ..................................... -->
+<!ENTITY % xhtml-object.module "INCLUDE" >
+<![%xhtml-object.module;[
+<!ENTITY % xhtml-object.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Embedded Object 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-object-1.mod" >
+%xhtml-object.mod;]]>
+
+<!-- Tables Module ............................................... -->
+<!ENTITY % xhtml-table.module "INCLUDE" >
+<![%xhtml-table.module;[
+<!ENTITY % xhtml-table.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Tables 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-table-1.mod" >
+%xhtml-table.mod;]]>
+
+<!-- Forms Module ............................................... -->
+<!ENTITY % xhtml-form.module "INCLUDE" >
+<![%xhtml-form.module;[
+<!ENTITY % xhtml-form.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Forms 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-form-1.mod" >
+%xhtml-form.mod;]]>
+
+<!-- Legacy Markup ............................................... -->
+<!ENTITY % xhtml-legacy.module "IGNORE" >
+<![%xhtml-legacy.module;[
+<!ENTITY % xhtml-legacy.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Legacy Markup 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-legacy-1.mod" >
+%xhtml-legacy.mod;]]>
+
+<!-- Document Structure Module (required) ....................... -->
+<!ENTITY % xhtml-struct.module "INCLUDE" >
+<![%xhtml-struct.module;[
+<!ENTITY % xhtml-struct.mod
+ PUBLIC "-//W3C//ELEMENTS XHTML Document Structure 1.0//EN"
+ "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-struct-1.mod" >
+%xhtml-struct.mod;]]>
+
+<!-- end of XHTML 1.1 DTD ................................................. -->
+<!-- ....................................................................... -->
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/chapter-toc.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/chapter-toc.tmpl
new file mode 100644
index 0000000000..e1e8bc275d
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/chapter-toc.tmpl
@@ -0,0 +1,46 @@
+[%# variables in this template
+ indexext [string, e.g. '.html']
+ suitetitle [string]
+ specroot [uri string]
+ formatdir [dir name string]
+ chapters [list of struct]
+ .numstr [string, e.g. '6.1.13']
+ .title [string]
+ .testcount [number]
+%]
+[% IF isXML %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+[% ELSE %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+[% END %]
+ <head>
+ <title>[% suitetitle %]</title>
+ <style type="text/css">
+ @import "http://www.w3.org/StyleSheets/TR/base.css";
+ @import "[% IF formatdir %]../[% END %]indices.css";
+ </style>
+ </head>
+<body>
+ <h1>[% suitetitle %] By Chapter</h1>
+
+ <p>This index contains both
+ <a href="http://wiki.csswg.org/test/selftest">self-describing tests</a>
+ and reftests.
+ A separate <a href="reftest-toc[% indexext%]">alphabetical reftest index</a>
+ is provided for tests in <a href="http://wiki.csswg.org/test/reftest">reftest
+ format</a> along with the <a href="reftest.list">reftest manifest</a>.</p>
+
+ <table>
+[% FOREACH chapter IN chapters %]
+ <tbody id="s[% chapter.numstr %]">
+ <tr><th><a href="chapter-[% chapter.numstr %][% indexext %]">
+ [% (chapter.numstr.match('^\d')) ? 'Chapter' : 'Appendix' +%] [%+ chapter.numstr +%] -
+ [%+ chapter.title +%]</a></th>
+ <td>([% chapter.testcount +%] Tests)</td></tr>
+ </tbody>
+[% END %]
+ </table>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/implementation-report-TEMPLATE.data.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/implementation-report-TEMPLATE.data.tmpl
new file mode 100644
index 0000000000..0231f23ba4
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/implementation-report-TEMPLATE.data.tmpl
@@ -0,0 +1,21 @@
+# UA version OS version
+# UA string (if applicable)
+# http://test.csswg.org/suites/[% suite %]/DATESTAMP/
+# See http://wiki.csswg.org/test/implementation-report for instructions
+testname revision result comment
+[% FOREACH test IN tests.sort(name) %]
+[% FOREACH format IN formats %]
+[% IF formatInfo.$format.report %]
+[% SET skipFormat = 0 %]
+[% FOREACH flag IN test.flags %]
+ [% SET skipFormat = 1 IF flag == formatInfo.$format.filter %]
+[% END %]
+[% UNLESS skipFormat +%]
+[%+ formatInfo.$format.path +%]/[% test.name +%].[% formatInfo.$format.ext +%] [%+ test.revision +%] ?
+[% END %]
+[% END %]
+[% END %]
+[% END %]
+[% FOREACH test IN addtests.sort() +%]
+[%+ test +%] [%+ test.revision +%] ?
+[% END %]
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.content.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.content.tmpl
new file mode 100644
index 0000000000..e32d8fe567
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.content.tmpl
@@ -0,0 +1,195 @@
+[% PROCESS "suitedata.tmpl" %]
+[% IF official %]
+ <h1>[% suites.$suite.title %]</h1>
+[% ELSE %]
+ <h1>Unofficial [% suites.$suite.title %]</h1>
+[% END %]
+ <dt>Test Coordinator:</dt>
+ <dd>[% suites.$suite.owner %]</dd>
+
+ <p>This is a <strong>[% statusNames.${suites.$suite.status}.title or "ERROR: $suite" %]</strong>
+ version of the [% suites.$suite.title %].</p>
+
+[% IF suites.$suite.harness != '' %]
+ <p>You can provide test data or review the testing results for this test suite:</p>
+ <dt><a href="http://test.csswg.org/harness/suite/[% suites.$suite.harness %]">Enter Data</a></dt>
+ <dt><a href="http://test.csswg.org/harness/review/[% suites.$suite.harness %]">Review Results</a></dt>
+[% END %]
+
+
+[% IF devel %]
+ <p>This build exists to aid in test suite development and contains unreviewed
+ tests. <strong>The pass/fail results of these tests are not reliable
+ indications of conformance.</strong>
+[% ELSE %]
+ <p>Some tests in the test suite may contain errors.
+[% END %]
+ Please check the latest version of the
+ <a href="[% suites.$suite.specroot %]">[% suites.$suite.spec %] specification</a>
+ <strong>and its errata</strong>
+ before assuming a failure is due to an implementation bug and
+ not a test suite bug.</p>
+
+[% UNLESS official %]
+ <p>You can find the <a href="[% suites.$suite.officialUrl %]">official
+ build</a> of the [% suites.$suite.title %] on W3C's web site.</p>
+[% END %]
+
+ <p>[% IF suites.$suite.status != 'fin' && suites.$suite.status != 'rc' %]
+ In time we hope to correct all errors and extend this test suite to
+ cover all of [% suites.$suite.spec %]. Your help is welcome in this effort.
+ [% END %]
+ The appropriate mailing list for submitting tests and bug reports is
+ <a href="http://lists.w3.org/Archives/Public/public-css-testsuite/">public-css-testsuite@w3.org</a>.</p>
+ <p>
+ To report bugs or feedback about a specific test file,
+ search for the filename (without extension) in
+ <a href="https://github.com/web-platform-tests/wpt/issues">web-platform-tests issues</a>,
+ and file a new issue if necessary with suggested label "wg-css".
+ More information on the contribution process and test guidelines is
+ available on the <a href="http://wiki.csswg.org/test">wiki
+ page</a>.</p>
+
+ <p>Tests are currently available in these formats:</p>
+
+ <dl>
+[% FOREACH format IN formats %]
+ [% IF format == 'html4' %]
+ <dt><a href="html4/toc.htm">HTML 4.01</a></dt>
+ <dd>HTML 4.01 tests sent as <code>text/html</code></dd>
+ [% END %]
+ [% IF format == 'html5' %]
+ <dt><a href="html/toc.htm">HTML 5</a></dt>
+ <dd>HTML 5 tests sent as <code>text/html</code></dd>
+ [% END %]
+ [% IF format == 'xhtml1' %]
+ <dt><a href="xhtml1/toc.xht">XHTML 1.1</a></dt>
+ <dd>XHTML 1.1 tests sent as <code>application/xhtml+xml</code></dd>
+ [% END %]
+ [% IF format == 'xhtml1print' %]
+ <dt><a href="xhtml1print/toc.xht">XHTML 1.1 for Printers</a></dt>
+ <dd>XHTML 1.1 tests with all images converted from PNG to JPEG
+ and formatted with headers and footers to ease testing of
+ embedded printer software. This is not a canonical format,
+ and some tests may fail due to the format conversion that
+ would otherwise pass in the above XHTML 1.1 format.</dd>
+ </dl>
+ [% END %]
+[% END %]
+
+[% IF suite == 'css2.1' %]
+ <p>Additional tests, that do not fit in any of those formats,
+ are located separately:</p>
+
+ <dl>
+ <dt><a href="other/">Other Formats</a></dt>
+ <dd>Tests that do not fit in the above formats because they
+ test a combination of CSS and a particular document language's
+ features and/or error recovery.</dd>
+ </dl>
+[% END %]
+
+ <p>Unless the test instructions explicitly indicate otherwise,
+ any occurrence of red in a test indicates test failure.</p>
+
+[% IF suite == 'css2.1' %]
+ <p>Note that <em>many</em> of the tests require the
+ <a href="http://www.w3.org/Style/CSS/Test/Fonts/Ahem/">Ahem font to be installed</a>.
+ These tests are marked with the 'ahem' flag in their metadata.
+ Without the Ahem font installed, these tests are of no value.</p>
+ <p>Some of the font-related tests also require
+ <a href="http://www.w3.org/Style/CSS/Test/Fonts/">special fonts</a>.
+ These tests are marked with the 'font' flag in their metadata.</p>
+
+[% END %]
+<h2 id="implement">Implementation Reports</h2>
+ <p>An <a href="implementation-report-TEMPLATE.data">implementation report template</a>
+ is available to help with creating implementation reports. See also the
+ <a href="http://lists.w3.org/Archives/Public/public-css-testsuite/2010Aug/0020.html">explanation</a>
+ of its format.</p>
+
+<h2 id="common">Common Assumptions</h2>
+
+ <p>Most of the test suite makes the following assumptions:</p>
+ <ul>
+ <li>The X/HTML <code>div</code> element is assigned <code>display: block;</code>
+ and no other property declaration.</li>
+ <li>The X/HTML <code>span</code> element is assigned <code>display: inline;</code>
+ and no other property declaration.</li>
+ <li>The X/HTML <code>p</code> element is assigned <code>display: block;</code></li>
+ <li>The X/HTML <code>li</code> element is assigned <code>display: list-item;</code></li>
+ <li>The X/HTML table elements <code>table</code>, <code>tbody</code>,
+ <code>tr</code>, and <code>td</code> are assigned the <code>display</code>
+ values <code>table</code>, <code>table-row-group</code>,
+ <code>table-row</code>, and <code>table-cell</code>, respectively.</li>
+ <li>The device can display the sixteen color values associated with the color
+ keywords <code>black</code>, <code>white</code>, <code>gray</code>,
+ <code>silver</code>, <code>red</code>, <code>green</code>, <code>blue</code>,
+ <code>purple</code>, <code>yellow</code>, <code>orange</code>, <code>teal</code>,
+ <code>fuchsia</code>, <code>maroon</code>, <code>navy</code>, <code>aqua</code>,
+ and <code>lime</code> as distinct colors.</li>
+ <li>The UA is set to print background colors and, if it supports graphics,
+ background images.</li>
+ <li>The UA implements reasonable page-breaking behavior; e.g., it is assumed
+ that UAs will not break at every opportunity, but only near the end of
+ a page unless a page break is forced.</li>
+ <li>The UA implements reasonable line-breaking behavior; e.g., it is assumed
+ that spaces between alphanumeric characters provide line breaking
+ opportunities and that UAs will not break at every opportunity, but only
+ near the end of a line unless a line break is forced.</li>
+ </ul>
+
+<h2 id="uncommon">Uncommon Assumptions</h2>
+
+ <p>In addition, some of the tests make one or more of the following
+ assumptions:</p>
+
+ <ul>
+ <li>The device is a full-color device.</li>
+ <li>The device has a viewport width of at least 640px (approx).</li>
+ <li>The resolution of the device is 96 CSS pixels per inch.</li>
+ <li>The UA imposes no minimum font size.</li>
+ <li>The 'medium' font-size computes to 16px.</li>
+ <li>The initial value of 'color' is black.</li>
+ <li>The canvas background is white.</li>
+ <li>The user stylesheet is empty (except where indicated by the tests).</li>
+ <li>The device is interactive and uses scroll bars.</li>
+ </ul>
+
+ <p>The tests that need these assumptions to be true have not yet been
+ marked, but it is likely that we will add a way to identify these
+ tests in due course. Tests should avoid relying on these assumptions
+ unless necessary.</p>
+
+<h2>License</h2>
+
+[% IF official %]
+ <p>This test suite is licensed under both the
+ <a href="http://www.w3.org/Consortium/Legal/2008/04-testsuite-license">W3C
+ Test Suite License</a> and the <a href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license">W3C
+ 3-clause BSD License</a>. See W3C Legal's <a href="http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright">explanation
+ of the licenses</a>.</p>
+[% ELSE %]
+ <p>These tests are licensed under the <a href="LICENSE-BSD">BSD 3-clause
+ License</a>. You may modify and distribute them under those terms. Aside
+ from their titles, documentation, and location they are identical to the
+ official tests of the same date. However, only the
+ <a href="http://www.w3.org/Style/Test/[% suite %]/current/">official % suites.$suite.title %]
+ </a> may be used as the basis for CSS conformance
+ claims.</p>
+[% END %]
+
+<h2>Acknowledgements</h2>
+
+ <p>Many thanks to the following for their contributions:</p>
+ <ul>
+[%- FOREACH person = contributors.keys.sort %]
+ [% IF not person.match('^CSS1') %]
+ <li>[% person %]</li>
+ [% END %]
+[%- END %]
+ </ul>
+[% IF suite == 'css2.1' %]
+ <p>...and all the <a href="http://www.w3.org/Style/CSS/Test/CSS1/current/tsack.html">contributors
+ to the CSS1 test suite</a>.</p>
+[% END %]
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.htm.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.htm.tmpl
new file mode 100644
index 0000000000..c29ed4a3c7
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.htm.tmpl
@@ -0,0 +1,20 @@
+[% PROCESS "suitedata.tmpl" %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html lang="en">
+ <head>
+[% IF official %]
+ <title>[% suites.$suite.title %]</title>
+[% ELSE %]
+ <title>Unofficial [% suites.$suite.title %]</title>
+[% END %]
+ <style type="text/css">
+ @import "http://www.w3.org/StyleSheets/TR/base.css";
+ @import "indices.css";
+ </style>
+ </head>
+ <body>
+
+[% INCLUDE "index.content.tmpl" %]
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.xht.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.xht.tmpl
new file mode 100644
index 0000000000..b355544cfa
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/index.xht.tmpl
@@ -0,0 +1,20 @@
+[% PROCESS "suitedata.tmpl" %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+ <head>
+[% IF official %]
+ <title>[% suites.$suite.title %]</title>
+[% ELSE %]
+ <title>Unofficial [% suites.$suite.title %]</title>
+[% END %]
+ <style type="text/css">
+ @import "http://www.w3.org/StyleSheets/TR/base.css";
+ @import "indices.css";
+ </style>
+ </head>
+ <body>
+
+[% INCLUDE index.content.tmpl %]
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/indices.css b/testing/web-platform/tests/css/tools/w3ctestlib/templates/indices.css
new file mode 100644
index 0000000000..7bc70eeef9
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/indices.css
@@ -0,0 +1,96 @@
+/* CSS for CSS Conformance Test Indices */
+/* Written by fantasai */
+
+/* Test Tables */
+
+ table {
+ border-collapse: collapse;
+ }
+
+ thead {
+ border-bottom: 0.2em solid;
+ }
+
+ tbody {
+ border: thin solid;
+ border-style: solid none;
+ }
+
+ tbody.ch {
+ border-top: 0.2em solid;
+ }
+ tbody.ch th {
+ font-weight: bold;
+ }
+
+ tbody th {
+ border-bottom: silver dotted thin;
+ background: #EEE;
+ color: black;
+ font-weight: normal;
+ font-style: italic;
+ }
+ tbody th :link {
+ color: gray;
+ background: transparent;
+ }
+ tbody th :visited {
+ color: #333;
+ background: transparent;
+ }
+
+ th, td {
+ padding: 0.2em;
+ text-align: left;
+ vertical-align: baseline;
+ }
+
+ td {
+ font-size: 0.9em;
+ }
+
+ /* flags */
+ td abbr {
+ border: solid thin gray;
+ padding: 0 0.1em;
+ cursor: help;
+ }
+ td abbr:hover {
+ background: #ffa;
+ color: black;
+ }
+
+
+ tr:hover {
+ background: #F9F9F9;
+ color: navy;
+ }
+
+ th a,
+ td a {
+ text-decoration: none;
+ }
+ th a:hover,
+ td a:hover,
+ th a:focus,
+ td a:focus {
+ text-decoration: underline;
+ }
+
+ td a {
+ display: block;
+ padding-left: 2em;
+ text-indent: -1em;
+ }
+ .refs {
+ font-weight: bold;
+ font-size: larger;
+ }
+ .assert, .assert > li {
+ list-style-type: none;
+ font-style: italic;
+ color: gray;
+ margin: 0;
+ padding: 0;
+ text-indent: 0;
+ }
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest-toc.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest-toc.tmpl
new file mode 100644
index 0000000000..91894235a4
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest-toc.tmpl
@@ -0,0 +1,74 @@
+[%# variables in this template
+ isXML [bool]
+ extmap [ExtensionMap object]
+ suitetitle [string]
+ specroot [URI of spec]
+ formatdir [string]
+ chaptitle [string]
+ chapdir [string]
+ testcount [number]
+ sections [list of struct]
+ .id [string - section number or id]
+ .uri [URI of section]
+ .tests [list of struct]
+ .asserts [list of strings]
+ .flags [list of token strings]
+ .links [list of uri strings]
+ .name [string]
+%]
+[% PROCESS suitedata.tmpl %]
+[% IF isXML %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+[% formatMismatchFlag = 'HTMLonly' %]
+[% ELSE %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+[% formatMismatchFlag = 'nonHTML' %]
+[% END %]
+ <head>
+ <title>[% suitetitle %] Reftest Index</title>
+ <style type="text/css">
+ @import "http://www.w3.org/StyleSheets/TR/base.css";
+ @import "[% IF formatdir %]../[% END %]indices.css";
+ </style>
+ </head>
+
+ <body>
+
+ <h1>[% suitetitle %] Reftest Index</h1>
+ <table width="100%">
+ <col id="test-column">[% IF isXML %]</col>[% END %]
+ <col id="ref-column">[% IF isXML %]</col>[% END %]
+ <col id="flags-column">[% IF isXML %]</col>[% END %]
+ <thead>
+ <tr>
+ <th>Test</th>
+ <th>Reference</th>
+ <th>Flags</th>
+ </tr>
+ </thead>
+[% FOREACH entry IN tests.sort('name') %]
+ [% IF entry.references and not entry.flags.contains(formatMismatchFlag) %]
+ <tbody id="[% entry.name %]" class="[% entry.flags.join(' ') %]">
+ [% FOREACH refList IN entry.references %]
+ [% IF loop.first %]
+ <tr>
+ <td rowspan="[% loop.size %]" title="[% entry.title | collapse | html %]">
+ <a href="[% extmap.translate(entry.file) %]">[% entry.name %]</a></td>
+ <td>[% FOREACH ref IN refList %]<a href="[% extmap.translate(ref.relpath) %]">[% refCompMap.${ref.type} %]</a> [% END %]</td>
+ <td rowspan="[% entry.references.size %]">[% FOREACH flag IN entry.flags %][% IF flag != 'nonHTML' and flag != 'HTMLonly' %]<abbr class="[% flag %]" title="[% flagInfo.$flag.title %]">[% flagInfo.$flag.abbr %]</abbr>[% END %][% END %]</td>
+ </tr>
+ [% ELSE %]
+ <tr>
+ <td><a href="[% extmap.translate(ref.relpath) %]">[% refCompMap.${ref.type} %]</a></td>
+ </tr>
+ [% END %]
+ [% END %]
+ </tbody>
+ [% END %]
+[% END %]
+ </table>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest.tmpl
new file mode 100644
index 0000000000..14b9bb6595
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/reftest.tmpl
@@ -0,0 +1,7 @@
+[% FOR entry IN tests.sort('name') %]
+[% IF not entry.flags.contains(formatMismatchFlag) %]
+[% FOREACH refList IN entry.references %]
+[%+ extmap.translate(entry.file) %] [% FOREACH ref IN refList %] [%+ ref.type %] [%+ extmap.translate(ref.relpath) %][% END %]
+[% END %]
+[% END %]
+[% END %]
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/suitedata.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/suitedata.tmpl
new file mode 100644
index 0000000000..6aae9f2ea8
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/suitedata.tmpl
@@ -0,0 +1,23 @@
+[% refCompMap =
+ { '==' => '=',
+ '!=' => '&#x2260;'
+ }
+%]
+[% statusNames = {
+ 'dev' => {
+ 'title' => 'Development',
+ 'link' => 'http://www.w3.org/Style/CSS/Test/#phase-pa' },
+ 'alpha' => {
+ 'title' => 'Alpha',
+ 'link' => 'http://www.w3.org/Style/CSS/Test/#phase-alpha' },
+ 'beta' => {
+ 'title' => 'Beta',
+ 'link' => 'http://www.w3.org/Style/CSS/Test/#phase-beta' },
+ 'rc' => {
+ 'title' => 'Release Candidate',
+ 'link' => 'http://www.w3.org/Style/CSS/Test/#phase-rc' },
+ 'final' => {
+ 'title' => 'Final',
+ 'link' => 'http://www.w3.org/Style/CSS/Test/#phase-fin' },
+ }
+%]
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/test-toc.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/test-toc.tmpl
new file mode 100644
index 0000000000..ff9ffbc1b8
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/test-toc.tmpl
@@ -0,0 +1,97 @@
+[%# variables in this template
+ isXML [bool]
+ extmap [ExtensionMap object]
+ suitetitle [string]
+ specroot [URI of spec]
+ formatdir [string]
+ chaptitle [string]
+ chapdir [string]
+ testcount [number]
+ sections [list of struct]
+ .id [string - section number or id]
+ .uri [URI of section]
+ .tests [list of struct]
+ .asserts [list of strings]
+ .flags [list of token strings]
+ .links [list of uri strings]
+ .name [string]
+%]
+[% PROCESS suitedata.tmpl %]
+[% IF isXML %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+[% formatMismatchFlag = 'HTMLonly' %]
+[% ELSE %]
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+[% formatMismatchFlag = 'nonHTML' %]
+[% END %]
+ <head>
+ <title>[% chaptertitle %] - [% suitetitle %]</title>
+ <style type="text/css">
+ @import "http://www.w3.org/StyleSheets/TR/base.css";
+ @import "[% IF formatdir %]../[% END %]indices.css";
+ </style>
+ </head>
+
+ <body>
+
+ <h1>[% suitetitle %]</h1>
+[% IF chaptertitle %]
+ <h2>[% chaptertitle %] ([% testcount %] tests)</h2>
+[% END %]
+ <table width="100%">
+ <col id="test-column">[% IF isXML %]</col>[% END %]
+ <col id="refs-column">[% IF isXML %]</col>[% END %]
+ <col id="flags-column">[% IF isXML %]</col>[% END %]
+ <col id="info-column">[% IF isXML %]</col>[% END %]
+ <thead>
+ <tr>
+ <th>Test</th>
+ <th><abbr title="Rendering References">Refs</abbr></th>
+ <th>Flags</th>
+ <th>Info</th>
+ </tr>
+ </thead>
+[% FOREACH section IN sections %]
+ <tbody id="s[% section.numstr %]">
+ [% IF section.title %]
+ <tr><th colspan="4" scope="rowgroup">
+ <a href="#s[% section.numstr %]">+</a>
+ <a href="[% section.uri %]">[% section.numstr +%] [%+ section.title %]</a></th></tr>
+ [% END %]
+ <!-- [% section.tests.size %] tests -->
+ [% FOREACH entry IN section.tests.sort('name') %]
+ [% FOREACH flag IN entry.flags %]
+ [% SET skip = 1 IF flag == formatMismatchFlag %]
+ [% END %]
+ [% UNLESS skip %]
+ [% primary = (entry.links.0 == section.uri) or (entry.links.0 == section.uri.replace(specroot, draftroot)) %]
+ <tr id="[% entry.name %]-[% section.numstr %]" class="
+ [% 'primary' IF primary %]
+ [% ' ' IF primary and entry.flags.size > 0 %]
+ [% entry.flags.join(' ') %]">
+ <td>[% '<strong>' IF primary %]
+ <a href="[% extmap.translate(entry.file) %]">[% entry.name%]</a>
+ [% '</strong>' IF primary %]</td>
+ <td>[% FOREACH refList IN entry.references %][% FOREACH ref IN refList %]<a href="[% extmap.translate(ref.relpath) %]">[% refCompMap.${ref.type} %]</a> [%+ END %][%+ END %]</td>
+ <td>[% FOREACH flag IN entry.flags %][% IF flag != 'nonHTML' and flag != 'HTMLonly' %]<abbr class="[% flag %]" title="[% flagInfo.$flag.title %]">[% flagInfo.$flag.abbr %]</abbr>[% END %][% END %]</td>
+ <td>[% entry.title | collapse | html %]
+ [% IF entry.asserts.size > 0 %]
+ <ul class="assert">
+ [% FOREACH assertion IN entry.asserts %]
+ <li>[% assertion | collapse | html %]</li>
+ [% END %]
+ </ul>
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ [% skip = 0 %]
+ [% END %]
+ </tbody>
+[% END %]
+ </table>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/tools/w3ctestlib/templates/testinfo.data.tmpl b/testing/web-platform/tests/css/tools/w3ctestlib/templates/testinfo.data.tmpl
new file mode 100644
index 0000000000..d06a2a906c
--- /dev/null
+++ b/testing/web-platform/tests/css/tools/w3ctestlib/templates/testinfo.data.tmpl
@@ -0,0 +1,16 @@
+id references title flags links revision credits assertion
+[% FOREACH test IN tests.sort('name') %]
+[%+ test.file.replace('\.[a-z]+$', '') +%]
+[%- FOREACH refList IN test.references -%][%- FOREACH ref IN refList -%]
+[%- '!' IF ref.type == '!=' %][% extmap.translate(ref.relpath) %][% ',' IF not loop.last() -%]
+[%- END +%][% ';' IF not loop.last() -%]
+[%- END +%]
+[%- test.title FILTER collapse +%]
+[%- test.flags.join(',') +%]
+[%- test.links.join(',') +%]
+[%- test.revision +%]
+[%- FOREACH credit IN test.credits -%]
+`[% credit.0 %]`<[% credit.1 %]>[% ',' IF not loop.last() -%]
+[%- END +%]
+[%- test.asserts.join(' ') FILTER collapse +%]
+[% END %]