Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.59% covered (success)
92.59%
25 / 27
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Element
92.59% covered (success)
92.59%
25 / 27
60.00% covered (warning)
60.00%
3 / 5
14.08
0.00% covered (danger)
0.00%
0 / 1
 __construct
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
4.01
 isMathmlTextIntegration
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isHtmlIntegration
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
5.05
 getNoahKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getDebugTag
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Wikimedia\RemexHtml\TreeBuilder;
4
5use Wikimedia\RemexHtml\HTMLData;
6use Wikimedia\RemexHtml\PropGuard;
7use Wikimedia\RemexHtml\Tokenizer\Attributes;
8
9/**
10 * Storage for all the state that TreeBuilder needs to associate with each
11 * element. These objects should be freed once they fall out of TreeBuilder's
12 * data structures (the stack etc.).
13 *
14 * These objects are also used to communicate information about elements with
15 * downstream clients.
16 */
17class Element implements FormattingElement {
18    use PropGuard;
19
20    /**
21     * The namespace. This will be the HTML namespace for elements that are not
22     * in foreign content, even if there is a prefix.
23     * @var string
24     */
25    public $namespace;
26
27    /**
28     * The tag name, usually exactly as it appeared in the source document.
29     * This is not strictly a local name, since it still contains a colon for
30     * prefixed elements. In foreign content, it is effectively a local name.
31     * It is suitable for use as a serialized tag name.
32     * @var string
33     */
34    public $name;
35
36    /**
37     * This is an internal designation of the type of the element, which is
38     * equal to the tag name when the element is in the HTML namespace, and is
39     * some other string when the element is not in the HTML namespace.
40     * @var string
41     */
42    public $htmlName;
43
44    /**
45     * @var Attributes
46     */
47    public $attrs;
48
49    /**
50     * This is true if the element was created by the TreeBuilder either as a
51     * fragment context node, or as a synthetic <html> element to be used as
52     * the top-level element in fragment parsing.
53     * @var bool
54     */
55    public $isVirtual;
56
57    /**
58     * Internal to CachingStack. A link in the scope list.
59     */
60    public $nextEltInScope;
61
62    /**
63     * Internal to CachingStack and SimpleStack. The current stack index, or
64     * null if the element is not in the stack.
65     */
66    public $stackIndex;
67
68    /**
69     * Internal to ActiveFormattingElements.
70     */
71    public $prevAFE;
72
73    /**
74     * Internal to ActiveFormattingElements.
75     */
76    public $nextAFE;
77
78    /**
79     * Internal to ActiveFormattingElements.
80     */
81    public $nextNoah;
82
83    /**
84     * The cache for getNoahKey()
85     */
86    private $noahKey;
87
88    /**
89     * This member variable can be written to by the TreeHandler, to store any
90     * state associated with the element (such as a DOM node). It is not used
91     * by TreeBuilder.
92     */
93    public $userData;
94
95    /**
96     * A unique ID which identifies the element
97     * @var int
98     */
99    public $uid;
100
101    /**
102     * The next unique ID to be used
103     *
104     * @var int
105     */
106    private static $nextUid = 1;
107
108    /**
109     * The element types in the MathML namespace which are MathML text
110     * integration points.
111     * @var array<string,bool>
112     */
113    private static $mathmlIntegration = [
114        'mi' => true,
115        'mo' => true,
116        'mn' => true,
117        'ms' => true,
118        'mtext' => true
119    ];
120
121    /**
122     * The element types in the SVG namespace which are SVG text integration
123     * points.
124     * @var array<string,bool>
125     */
126    private static $svgHtmlIntegration = [
127        'foreignObject' => true,
128        'desc' => true,
129        'title' => true
130    ];
131
132    /**
133     * Constructor.
134     *
135     * @param string $namespace
136     * @param string $name
137     * @param Attributes $attrs
138     */
139    public function __construct( $namespace, $name, Attributes $attrs ) {
140        $this->namespace = $namespace;
141        $this->name = $name;
142        if ( $namespace === HTMLData::NS_HTML ) {
143            $this->htmlName = $name;
144        } elseif ( $namespace === HTMLData::NS_MATHML ) {
145            $this->htmlName = "mathml $name";
146        } elseif ( $namespace === HTMLData::NS_SVG ) {
147            $this->htmlName = "svg $name";
148        } else {
149            $this->htmlName = "$namespace $name";
150        }
151        $this->attrs = $attrs;
152        $this->uid = self::$nextUid++;
153    }
154
155    /**
156     * Is the element a MathML text integration point?
157     *
158     * @return bool
159     */
160    public function isMathmlTextIntegration() {
161        return $this->namespace === HTMLData::NS_MATHML
162            && isset( self::$mathmlIntegration[$this->name] );
163    }
164
165    /**
166     * Is the element an HTML integration point?
167     * @return bool
168     */
169    public function isHtmlIntegration() {
170        if ( $this->namespace === HTMLData::NS_MATHML ) {
171            if ( isset( $this->attrs['encoding'] ) ) {
172                $encoding = strtolower( $this->attrs['encoding'] );
173                return $encoding === 'text/html' || $encoding === 'application/xhtml+xml';
174            } else {
175                return false;
176            }
177        } elseif ( $this->namespace === HTMLData::NS_SVG ) {
178            return isset( self::$svgHtmlIntegration[$this->name] );
179        } else {
180            return false;
181        }
182    }
183
184    /**
185     * Get a string key for the Noah's Ark algorithm
186     *
187     * @return string
188     */
189    public function getNoahKey() {
190        if ( $this->noahKey === null ) {
191            $attrs = $this->attrs->getValues();
192            ksort( $attrs );
193            $this->noahKey = serialize( [ $this->htmlName, $attrs ] );
194        }
195        return $this->noahKey;
196    }
197
198    /**
199     * Get a string identifying the element, for use in debugging.
200     * @return string
201     */
202    public function getDebugTag() {
203        return $this->htmlName . '#' . $this->uid;
204    }
205}