true, 'mo' => true, 'mn' => true, 'ms' => true, 'mtext' => true, 'annotation-xml' => true ]; private static $svgBreakers = [ 'foreignObject' => true, 'desc' => true, 'title' => true ]; /** * If you compile every predicate of the form "an X element in Y scope" in * the HTML 5 spec, you discover that every element name X corresponds to * at most one such scope Y. This is useful because it means when we see * a new element, we need to add it to at most one scope cache. * * This is a list of such statements in the spec, and the scope they relate * to. All formatting elements are included as SCOPE_DEFAULT since the AAA * involves pulling an item out of the AFE list and checking if it is in * scope. */ static private $predicateMap = [ 'a' => self::SCOPE_DEFAULT, 'address' => self::SCOPE_DEFAULT, 'applet' => self::SCOPE_DEFAULT, 'article' => self::SCOPE_DEFAULT, 'aside' => self::SCOPE_DEFAULT, 'b' => self::SCOPE_DEFAULT, 'big' => self::SCOPE_DEFAULT, 'blockquote' => self::SCOPE_DEFAULT, 'body' => self::SCOPE_DEFAULT, 'button' => self::SCOPE_DEFAULT, 'caption' => self::SCOPE_TABLE, 'center' => self::SCOPE_DEFAULT, 'code' => self::SCOPE_DEFAULT, 'dd' => self::SCOPE_DEFAULT, 'details' => self::SCOPE_DEFAULT, 'dialog' => self::SCOPE_DEFAULT, 'dir' => self::SCOPE_DEFAULT, 'div' => self::SCOPE_DEFAULT, 'dl' => self::SCOPE_DEFAULT, 'dt' => self::SCOPE_DEFAULT, 'em' => self::SCOPE_DEFAULT, 'fieldset' => self::SCOPE_DEFAULT, 'figcaption' => self::SCOPE_DEFAULT, 'figure' => self::SCOPE_DEFAULT, 'font' => self::SCOPE_DEFAULT, 'footer' => self::SCOPE_DEFAULT, 'form' => self::SCOPE_DEFAULT, 'h1' => self::SCOPE_DEFAULT, 'h2' => self::SCOPE_DEFAULT, 'h3' => self::SCOPE_DEFAULT, 'h4' => self::SCOPE_DEFAULT, 'h5' => self::SCOPE_DEFAULT, 'h6' => self::SCOPE_DEFAULT, 'header' => self::SCOPE_DEFAULT, 'hgroup' => self::SCOPE_DEFAULT, 'i' => self::SCOPE_DEFAULT, 'li' => self::SCOPE_LIST, 'listing' => self::SCOPE_DEFAULT, 'main' => self::SCOPE_DEFAULT, 'marquee' => self::SCOPE_DEFAULT, 'menu' => self::SCOPE_DEFAULT, 'nav' => self::SCOPE_DEFAULT, 'nobr' => self::SCOPE_DEFAULT, 'object' => self::SCOPE_DEFAULT, 'ol' => self::SCOPE_DEFAULT, 'p' => self::SCOPE_BUTTON, 'pre' => self::SCOPE_DEFAULT, 'ruby' => self::SCOPE_DEFAULT, 's' => self::SCOPE_DEFAULT, 'section' => self::SCOPE_DEFAULT, 'select' => self::SCOPE_SELECT, 'small' => self::SCOPE_DEFAULT, 'strike' => self::SCOPE_DEFAULT, 'strong' => self::SCOPE_DEFAULT, 'summary' => self::SCOPE_DEFAULT, 'table' => self::SCOPE_TABLE, 'tbody' => self::SCOPE_TABLE, 'td' => self::SCOPE_TABLE, 'tfoot' => self::SCOPE_TABLE, 'th' => self::SCOPE_TABLE, 'thead' => self::SCOPE_TABLE, 'tr' => self::SCOPE_TABLE, 'tt' => self::SCOPE_DEFAULT, 'u' => self::SCOPE_DEFAULT, 'ul' => self::SCOPE_DEFAULT, ]; /** * The stack of open elements */ private $elements = []; /** * A cache of the elements which are currently in a given scope. * The first key is the scope ID, the second key is the element name, and the * value is the first Element in a singly-linked list of Element objects, * linked by $element->nextScope. * * @todo Benchmark time and memory compared to an array stack instead of an * SLL. The SLL here is maybe not quite so well justified as some other * SLLs in RemexHtml. * * @var Element[int][string] */ private $scopes = [ self::SCOPE_DEFAULT => [], self::SCOPE_LIST => [], self::SCOPE_BUTTON => [], self::SCOPE_TABLE => [], self::SCOPE_SELECT => [] ]; /** * This is the part of the scope cache which stores scope lists for objects * which are not currently in scope. The first key is the scope ID, the * second key is the stack index, the third key is the element name. * * @var Element[int][int][string] */ private $scopeStacks = [ self::SCOPE_DEFAULT => [], self::SCOPE_LIST => [], self::SCOPE_BUTTON => [], self::SCOPE_TABLE => [], self::SCOPE_SELECT => [] ]; /** * The number of