ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
HTML5TreeConstructer Class Reference
+ Collaboration diagram for HTML5TreeConstructer:

Public Member Functions

 __construct ()
 
 emitToken ($token)
 
 save ()
 
 __construct ()
 
 emitToken ($token)
 
 save ()
 

Data Fields

 $stack = array()
 
const INIT_PHASE = 0
 
const ROOT_PHASE = 1
 
const MAIN_PHASE = 2
 
const END_PHASE = 3
 
const BEFOR_HEAD = 0
 
const IN_HEAD = 1
 
const AFTER_HEAD = 2
 
const IN_BODY = 3
 
const IN_TABLE = 4
 
const IN_CAPTION = 5
 
const IN_CGROUP = 6
 
const IN_TBODY = 7
 
const IN_ROW = 8
 
const IN_CELL = 9
 
const IN_SELECT = 10
 
const AFTER_BODY = 11
 
const IN_FRAME = 12
 
const AFTR_FRAME = 13
 
const SPECIAL = 0
 
const SCOPING = 1
 
const FORMATTING = 2
 
const PHRASING = 3
 
const MARKER = 0
 

Private Member Functions

 initPhase ($token)
 
 rootElementPhase ($token)
 
 mainPhase ($token)
 
 beforeHead ($token)
 
 inHead ($token)
 
 afterHead ($token)
 
 inBody ($token)
 
 inTable ($token)
 
 inCaption ($token)
 
 inColumnGroup ($token)
 
 inTableBody ($token)
 
 inRow ($token)
 
 inCell ($token)
 
 inSelect ($token)
 
 afterBody ($token)
 
 inFrameset ($token)
 
 afterFrameset ($token)
 
 trailingEndPhase ($token)
 
 insertElement ($token, $append=true, $check=false)
 
 insertText ($data)
 
 insertComment ($data)
 
 appendToRealParent ($node)
 
 elementInScope ($el, $table=false)
 
 reconstructActiveFormattingElements ()
 
 clearTheActiveFormattingElementsUpToTheLastMarker ()
 
 generateImpliedEndTags ($exclude=array())
 
 getElementCategory ($node)
 
 clearStackToTableContext ($elements)
 
 resetInsertionMode ()
 
 closeCell ()
 
 initPhase ($token)
 
 rootElementPhase ($token)
 
 mainPhase ($token)
 
 beforeHead ($token)
 
 inHead ($token)
 
 afterHead ($token)
 
 inBody ($token)
 
 inTable ($token)
 
 inCaption ($token)
 
 inColumnGroup ($token)
 
 inTableBody ($token)
 
 inRow ($token)
 
 inCell ($token)
 
 inSelect ($token)
 
 afterBody ($token)
 
 inFrameset ($token)
 
 afterFrameset ($token)
 
 trailingEndPhase ($token)
 
 insertElement ($token, $append=true)
 
 insertText ($data)
 
 insertComment ($data)
 
 appendToRealParent ($node)
 
 elementInScope ($el, $table=false)
 
 reconstructActiveFormattingElements ()
 
 clearTheActiveFormattingElementsUpToTheLastMarker ()
 
 generateImpliedEndTags (array $exclude=array())
 
 getElementCategory ($name)
 
 clearStackToTableContext ($elements)
 
 resetInsertionMode ()
 
 closeCell ()
 

Private Attributes

 $phase
 
 $mode
 
 $dom
 
 $foster_parent = null
 
 $a_formatting = array()
 
 $head_pointer = null
 
 $form_pointer = null
 
 $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th')
 
 $formatting
 
 $special
 

Detailed Description

Definition at line 1577 of file PH5P.php.

Constructor & Destructor Documentation

◆ __construct() [1/2]

HTML5TreeConstructer::__construct ( )

Definition at line 1700 of file PH5P.php.

1701 {
1702 $this->phase = self::INIT_PHASE;
1703 $this->mode = self::BEFOR_HEAD;
1704 $this->dom = new DOMDocument;
1705
1706 $this->dom->encoding = 'UTF-8';
1707 $this->dom->preserveWhiteSpace = true;
1708 $this->dom->substituteEntities = true;
1709 $this->dom->strictErrorChecking = false;
1710 }

References BEFOR_HEAD, and INIT_PHASE.

◆ __construct() [2/2]

HTML5TreeConstructer::__construct ( )

Definition at line 1195 of file PH5P.php.

1196 {
1197 $this->phase = self::INIT_PHASE;
1198 $this->mode = self::BEFOR_HEAD;
1199 $this->dom = new DOMDocument;
1200
1201 $this->dom->encoding = 'UTF-8';
1202 $this->dom->preserveWhiteSpace = true;
1203 $this->dom->substituteEntities = true;
1204 $this->dom->strictErrorChecking = false;
1205 }

References BEFOR_HEAD, and INIT_PHASE.

Member Function Documentation

◆ afterBody() [1/2]

HTML5TreeConstructer::afterBody (   $token)
private

Definition at line 4202 of file PH5P.php.

4203 {
4204 /* Handle the token as follows: */
4205
4206 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
4207 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
4208 or U+0020 SPACE */
4209 if ($token['type'] === HTML5::CHARACTR &&
4210 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
4211 ) {
4212 /* Process the token as it would be processed if the insertion mode
4213 was "in body". */
4214 $this->inBody($token);
4215
4216 /* A comment token */
4217 } elseif ($token['type'] === HTML5::COMMENT) {
4218 /* Append a Comment node to the first element in the stack of open
4219 elements (the html element), with the data attribute set to the
4220 data given in the comment token. */
4221 $comment = $this->dom->createComment($token['data']);
4222 $this->stack[0]->appendChild($comment);
4223
4224 /* An end tag with the tag name "html" */
4225 } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') {
4226 /* If the parser was originally created in order to handle the
4227 setting of an element's innerHTML attribute, this is a parse error;
4228 ignore the token. (The element will be an html element in this
4229 case.) (innerHTML case) */
4230
4231 /* Otherwise, switch to the trailing end phase. */
4232 $this->phase = self::END_PHASE;
4233
4234 /* Anything else */
4235 } else {
4236 /* Parse error. Set the insertion mode to "in body" and reprocess
4237 the token. */
4238 $this->mode = self::IN_BODY;
4239 return $this->inBody($token);
4240 }
4241 }
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:458
const COMMENT
Definition: PH5P.php:457
const ENDTAG
Definition: PH5P.php:456

References $comment, HTML5\CHARACTR, HTML5\COMMENT, END_PHASE, HTML5\ENDTAG, IN_BODY, and inBody().

Referenced by inBody(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ afterBody() [2/2]

HTML5TreeConstructer::afterBody (   $token)
private

Definition at line 3340 of file PH5P.php.

3341 {
3342 /* Handle the token as follows: */
3343
3344 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3345 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3346 or U+0020 SPACE */
3347 if($token['type'] === HTML5::CHARACTR &&
3348 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3349 /* Process the token as it would be processed if the insertion mode
3350 was "in body". */
3351 $this->inBody($token);
3352
3353 /* A comment token */
3354 } elseif($token['type'] === HTML5::COMMENT) {
3355 /* Append a Comment node to the first element in the stack of open
3356 elements (the html element), with the data attribute set to the
3357 data given in the comment token. */
3358 $comment = $this->dom->createComment($token['data']);
3359 $this->stack[0]->appendChild($comment);
3360
3361 /* An end tag with the tag name "html" */
3362 } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') {
3363 /* If the parser was originally created in order to handle the
3364 setting of an element's innerHTML attribute, this is a parse error;
3365 ignore the token. (The element will be an html element in this
3366 case.) (innerHTML case) */
3367
3368 /* Otherwise, switch to the trailing end phase. */
3369 $this->phase = self::END_PHASE;
3370
3371 /* Anything else */
3372 } else {
3373 /* Parse error. Set the insertion mode to "in body" and reprocess
3374 the token. */
3375 $this->mode = self::IN_BODY;
3376 return $this->inBody($token);
3377 }
3378 }

References $comment, HTML5\CHARACTR, HTML5\COMMENT, END_PHASE, HTML5\ENDTAG, IN_BODY, and inBody().

+ Here is the call graph for this function:

◆ afterFrameset() [1/2]

HTML5TreeConstructer::afterFrameset (   $token)
private

Definition at line 4312 of file PH5P.php.

4313 {
4314 /* Handle the token as follows: */
4315
4316 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
4317 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
4318 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
4319 if ($token['type'] === HTML5::CHARACTR &&
4320 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
4321 ) {
4322 /* Append the character to the current node. */
4323 $this->insertText($token['data']);
4324
4325 /* A comment token */
4326 } elseif ($token['type'] === HTML5::COMMENT) {
4327 /* Append a Comment node to the current node with the data
4328 attribute set to the data given in the comment token. */
4329 $this->insertComment($token['data']);
4330
4331 /* An end tag with the tag name "html" */
4332 } elseif ($token['name'] === 'html' &&
4333 $token['type'] === HTML5::ENDTAG
4334 ) {
4335 /* Switch to the trailing end phase. */
4336 $this->phase = self::END_PHASE;
4337
4338 /* A start tag with the tag name "noframes" */
4339 } elseif ($token['name'] === 'noframes' &&
4340 $token['type'] === HTML5::STARTTAG
4341 ) {
4342 /* Process the token as if the insertion mode had been "in body". */
4343 $this->inBody($token);
4344
4345 /* Anything else */
4346 } else {
4347 /* Parse error. Ignore the token. */
4348 }
4349 }
insertComment($data)
Definition: PH5P.php:4429
const STARTTAG
Definition: PH5P.php:455

References HTML5\CHARACTR, HTML5\COMMENT, END_PHASE, HTML5\ENDTAG, inBody(), insertComment(), insertText(), and HTML5\STARTTAG.

Referenced by mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ afterFrameset() [2/2]

HTML5TreeConstructer::afterFrameset (   $token)
private

Definition at line 3444 of file PH5P.php.

3445 {
3446 /* Handle the token as follows: */
3447
3448 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3449 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3450 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3451 if($token['type'] === HTML5::CHARACTR &&
3452 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3453 /* Append the character to the current node. */
3454 $this->insertText($token['data']);
3455
3456 /* A comment token */
3457 } elseif($token['type'] === HTML5::COMMENT) {
3458 /* Append a Comment node to the current node with the data
3459 attribute set to the data given in the comment token. */
3460 $this->insertComment($token['data']);
3461
3462 /* An end tag with the tag name "html" */
3463 } elseif($token['name'] === 'html' &&
3464 $token['type'] === HTML5::ENDTAG) {
3465 /* Switch to the trailing end phase. */
3466 $this->phase = self::END_PHASE;
3467
3468 /* A start tag with the tag name "noframes" */
3469 } elseif($token['name'] === 'noframes' &&
3470 $token['type'] === HTML5::STARTTAG) {
3471 /* Process the token as if the insertion mode had been "in body". */
3472 $this->inBody($token);
3473
3474 /* Anything else */
3475 } else {
3476 /* Parse error. Ignore the token. */
3477 }
3478 }

References HTML5\CHARACTR, HTML5\COMMENT, END_PHASE, HTML5\ENDTAG, inBody(), insertComment(), insertText(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ afterHead() [1/2]

HTML5TreeConstructer::afterHead (   $token)
private

Definition at line 2113 of file PH5P.php.

2114 {
2115 /* Handle the token as follows: */
2116
2117 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2118 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2119 or U+0020 SPACE */
2120 if ($token['type'] === HTML5::CHARACTR &&
2121 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
2122 ) {
2123 /* Append the character to the current node. */
2124 $this->insertText($token['data']);
2125
2126 /* A comment token */
2127 } elseif ($token['type'] === HTML5::COMMENT) {
2128 /* Append a Comment node to the current node with the data attribute
2129 set to the data given in the comment token. */
2130 $this->insertComment($token['data']);
2131
2132 /* A start tag token with the tag name "body" */
2133 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') {
2134 /* Insert a body element for the token. */
2135 $this->insertElement($token);
2136
2137 /* Change the insertion mode to "in body". */
2138 $this->mode = self::IN_BODY;
2139
2140 /* A start tag token with the tag name "frameset" */
2141 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') {
2142 /* Insert a frameset element for the token. */
2143 $this->insertElement($token);
2144
2145 /* Change the insertion mode to "in frameset". */
2146 $this->mode = self::IN_FRAME;
2147
2148 /* A start tag token whose tag name is one of: "base", "link", "meta",
2149 "script", "style", "title" */
2150 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
2151 $token['name'],
2152 array('base', 'link', 'meta', 'script', 'style', 'title')
2153 )
2154 ) {
2155 /* Parse error. Switch the insertion mode back to "in head" and
2156 reprocess the token. */
2157 $this->mode = self::IN_HEAD;
2158 return $this->inHead($token);
2159
2160 /* Anything else */
2161 } else {
2162 /* Act as if a start tag token with the tag name "body" and no
2163 attributes had been seen, and then reprocess the current token. */
2164 $this->afterHead(
2165 array(
2166 'name' => 'body',
2167 'type' => HTML5::STARTTAG,
2168 'attr' => array()
2169 )
2170 );
2171
2172 return $this->inBody($token);
2173 }
2174 }
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:4394
afterHead($token)
Definition: PH5P.php:2113

References afterHead(), HTML5\CHARACTR, HTML5\COMMENT, IN_BODY, IN_FRAME, IN_HEAD, inBody(), inHead(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

Referenced by afterHead(), inHead(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ afterHead() [2/2]

HTML5TreeConstructer::afterHead (   $token)
private

Definition at line 1548 of file PH5P.php.

1549 {
1550 /* Handle the token as follows: */
1551
1552 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1553 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1554 or U+0020 SPACE */
1555 if($token['type'] === HTML5::CHARACTR &&
1556 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1557 /* Append the character to the current node. */
1558 $this->insertText($token['data']);
1559
1560 /* A comment token */
1561 } elseif($token['type'] === HTML5::COMMENT) {
1562 /* Append a Comment node to the current node with the data attribute
1563 set to the data given in the comment token. */
1564 $this->insertComment($token['data']);
1565
1566 /* A start tag token with the tag name "body" */
1567 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') {
1568 /* Insert a body element for the token. */
1569 $this->insertElement($token);
1570
1571 /* Change the insertion mode to "in body". */
1572 $this->mode = self::IN_BODY;
1573
1574 /* A start tag token with the tag name "frameset" */
1575 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') {
1576 /* Insert a frameset element for the token. */
1577 $this->insertElement($token);
1578
1579 /* Change the insertion mode to "in frameset". */
1580 $this->mode = self::IN_FRAME;
1581
1582 /* A start tag token whose tag name is one of: "base", "link", "meta",
1583 "script", "style", "title" */
1584 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
1585 array('base', 'link', 'meta', 'script', 'style', 'title'))) {
1586 /* Parse error. Switch the insertion mode back to "in head" and
1587 reprocess the token. */
1588 $this->mode = self::IN_HEAD;
1589 return $this->inHead($token);
1590
1591 /* Anything else */
1592 } else {
1593 /* Act as if a start tag token with the tag name "body" and no
1594 attributes had been seen, and then reprocess the current token. */
1595 $this->afterHead(array(
1596 'name' => 'body',
1597 'type' => HTML5::STARTTAG,
1598 'attr' => array()
1599 ));
1600
1601 return $this->inBody($token);
1602 }
1603 }

References afterHead(), HTML5\CHARACTR, HTML5\COMMENT, IN_BODY, IN_FRAME, IN_HEAD, inBody(), inHead(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ appendToRealParent() [1/2]

HTML5TreeConstructer::appendToRealParent (   $node)
private

Definition at line 4435 of file PH5P.php.

4436 {
4437 if ($this->foster_parent === null) {
4438 end($this->stack)->appendChild($node);
4439
4440 } elseif ($this->foster_parent !== null) {
4441 /* If the foster parent element is the parent element of the
4442 last table element in the stack of open elements, then the new
4443 node must be inserted immediately before the last table element
4444 in the stack of open elements in the foster parent element;
4445 otherwise, the new node must be appended to the foster parent
4446 element. */
4447 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
4448 if ($this->stack[$n]->nodeName === 'table' &&
4449 $this->stack[$n]->parentNode !== null
4450 ) {
4451 $table = $this->stack[$n];
4452 break;
4453 }
4454 }
4455
4456 if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) {
4457 $this->foster_parent->insertBefore($node, $table);
4458 } else {
4459 $this->foster_parent->appendChild($node);
4460 }
4461
4462 $this->foster_parent = null;
4463 }
4464 }
$n
Definition: RandomTest.php:85
if(empty($password)) $table
Definition: pwgen.php:24

References $n, and $table.

Referenced by insertComment(), insertElement(), and insertText().

+ Here is the caller graph for this function:

◆ appendToRealParent() [2/2]

HTML5TreeConstructer::appendToRealParent (   $node)
private

Definition at line 3549 of file PH5P.php.

3550 {
3551 if($this->foster_parent === null) {
3552 end($this->stack)->appendChild($node);
3553
3554 } elseif($this->foster_parent !== null) {
3555 /* If the foster parent element is the parent element of the
3556 last table element in the stack of open elements, then the new
3557 node must be inserted immediately before the last table element
3558 in the stack of open elements in the foster parent element;
3559 otherwise, the new node must be appended to the foster parent
3560 element. */
3561 for($n = count($this->stack) - 1; $n >= 0; $n--) {
3562 if($this->stack[$n]->nodeName === 'table' &&
3563 $this->stack[$n]->parentNode !== null) {
3564 $table = $this->stack[$n];
3565 break;
3566 }
3567 }
3568
3569 if(isset($table) && $this->foster_parent->isSameNode($table->parentNode))
3570 $this->foster_parent->insertBefore($node, $table);
3571 else
3572 $this->foster_parent->appendChild($node);
3573
3574 $this->foster_parent = null;
3575 }
3576 }

References $n, and $table.

◆ beforeHead() [1/2]

HTML5TreeConstructer::beforeHead (   $token)
private

Definition at line 1917 of file PH5P.php.

1918 {
1919 /* Handle the token as follows: */
1920
1921 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1922 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1923 or U+0020 SPACE */
1924 if ($token['type'] === HTML5::CHARACTR &&
1925 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
1926 ) {
1927 /* Append the character to the current node. */
1928 $this->insertText($token['data']);
1929
1930 /* A comment token */
1931 } elseif ($token['type'] === HTML5::COMMENT) {
1932 /* Append a Comment node to the current node with the data attribute
1933 set to the data given in the comment token. */
1934 $this->insertComment($token['data']);
1935
1936 /* A start tag token with the tag name "head" */
1937 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') {
1938 /* Create an element for the token, append the new element to the
1939 current node and push it onto the stack of open elements. */
1940 $element = $this->insertElement($token);
1941
1942 /* Set the head element pointer to this new element node. */
1943 $this->head_pointer = $element;
1944
1945 /* Change the insertion mode to "in head". */
1946 $this->mode = self::IN_HEAD;
1947
1948 /* A start tag token whose tag name is one of: "base", "link", "meta",
1949 "script", "style", "title". Or an end tag with the tag name "html".
1950 Or a character token that is not one of U+0009 CHARACTER TABULATION,
1951 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1952 or U+0020 SPACE. Or any other start tag token */
1953 } elseif ($token['type'] === HTML5::STARTTAG ||
1954 ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') ||
1955 ($token['type'] === HTML5::CHARACTR && !preg_match(
1956 '/^[\t\n\x0b\x0c ]$/',
1957 $token['data']
1958 ))
1959 ) {
1960 /* Act as if a start tag token with the tag name "head" and no
1961 attributes had been seen, then reprocess the current token. */
1962 $this->beforeHead(
1963 array(
1964 'name' => 'head',
1965 'type' => HTML5::STARTTAG,
1966 'attr' => array()
1967 )
1968 );
1969
1970 return $this->inHead($token);
1971
1972 /* Any other end tag */
1973 } elseif ($token['type'] === HTML5::ENDTAG) {
1974 /* Parse error. Ignore the token. */
1975 }
1976 }
beforeHead($token)
Definition: PH5P.php:1917

References beforeHead(), HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, IN_HEAD, inHead(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

Referenced by beforeHead(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ beforeHead() [2/2]

HTML5TreeConstructer::beforeHead (   $token)
private

Definition at line 1368 of file PH5P.php.

1369 {
1370 /* Handle the token as follows: */
1371
1372 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1373 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1374 or U+0020 SPACE */
1375 if($token['type'] === HTML5::CHARACTR &&
1376 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1377 /* Append the character to the current node. */
1378 $this->insertText($token['data']);
1379
1380 /* A comment token */
1381 } elseif($token['type'] === HTML5::COMMENT) {
1382 /* Append a Comment node to the current node with the data attribute
1383 set to the data given in the comment token. */
1384 $this->insertComment($token['data']);
1385
1386 /* A start tag token with the tag name "head" */
1387 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') {
1388 /* Create an element for the token, append the new element to the
1389 current node and push it onto the stack of open elements. */
1390 $element = $this->insertElement($token);
1391
1392 /* Set the head element pointer to this new element node. */
1393 $this->head_pointer = $element;
1394
1395 /* Change the insertion mode to "in head". */
1396 $this->mode = self::IN_HEAD;
1397
1398 /* A start tag token whose tag name is one of: "base", "link", "meta",
1399 "script", "style", "title". Or an end tag with the tag name "html".
1400 Or a character token that is not one of U+0009 CHARACTER TABULATION,
1401 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1402 or U+0020 SPACE. Or any other start tag token */
1403 } elseif($token['type'] === HTML5::STARTTAG ||
1404 ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') ||
1405 ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/',
1406 $token['data']))) {
1407 /* Act as if a start tag token with the tag name "head" and no
1408 attributes had been seen, then reprocess the current token. */
1409 $this->beforeHead(array(
1410 'name' => 'head',
1411 'type' => HTML5::STARTTAG,
1412 'attr' => array()
1413 ));
1414
1415 return $this->inHead($token);
1416
1417 /* Any other end tag */
1418 } elseif($token['type'] === HTML5::ENDTAG) {
1419 /* Parse error. Ignore the token. */
1420 }
1421 }

References beforeHead(), HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, IN_HEAD, inHead(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ clearStackToTableContext() [1/2]

HTML5TreeConstructer::clearStackToTableContext (   $elements)
private

Definition at line 4649 of file PH5P.php.

4650 {
4651 /* When the steps above require the UA to clear the stack back to a
4652 table context, it means that the UA must, while the current node is not
4653 a table element or an html element, pop elements from the stack of open
4654 elements. If this causes any elements to be popped from the stack, then
4655 this is a parse error. */
4656 while (true) {
4657 $node = end($this->stack)->nodeName;
4658
4659 if (in_array($node, $elements)) {
4660 break;
4661 } else {
4662 array_pop($this->stack);
4663 }
4664 }
4665 }

Referenced by inRow(), inTable(), and inTableBody().

+ Here is the caller graph for this function:

◆ clearStackToTableContext() [2/2]

HTML5TreeConstructer::clearStackToTableContext (   $elements)
private

Definition at line 3752 of file PH5P.php.

3753 {
3754 /* When the steps above require the UA to clear the stack back to a
3755 table context, it means that the UA must, while the current node is not
3756 a table element or an html element, pop elements from the stack of open
3757 elements. If this causes any elements to be popped from the stack, then
3758 this is a parse error. */
3759 while(true) {
3760 $node = end($this->stack)->nodeName;
3761
3762 if(in_array($node, $elements)) {
3763 break;
3764 } else {
3765 array_pop($this->stack);
3766 }
3767 }
3768 }

◆ clearTheActiveFormattingElementsUpToTheLastMarker() [1/2]

HTML5TreeConstructer::clearTheActiveFormattingElementsUpToTheLastMarker ( )
private

Definition at line 4598 of file PH5P.php.

4599 {
4600 /* When the steps below require the UA to clear the list of active
4601 formatting elements up to the last marker, the UA must perform the
4602 following steps: */
4603
4604 while (true) {
4605 /* 1. Let entry be the last (most recently added) entry in the list
4606 of active formatting elements. */
4607 $entry = end($this->a_formatting);
4608
4609 /* 2. Remove entry from the list of active formatting elements. */
4610 array_pop($this->a_formatting);
4611
4612 /* 3. If entry was a marker, then stop the algorithm at this point.
4613 The list has been cleared up to the last marker. */
4614 if ($entry === self::MARKER) {
4615 break;
4616 }
4617 }
4618 }

Referenced by inCaption(), and inCell().

+ Here is the caller graph for this function:

◆ clearTheActiveFormattingElementsUpToTheLastMarker() [2/2]

HTML5TreeConstructer::clearTheActiveFormattingElementsUpToTheLastMarker ( )
private

Definition at line 3700 of file PH5P.php.

3701 {
3702 /* When the steps below require the UA to clear the list of active
3703 formatting elements up to the last marker, the UA must perform the
3704 following steps: */
3705
3706 while(true) {
3707 /* 1. Let entry be the last (most recently added) entry in the list
3708 of active formatting elements. */
3709 $entry = end($this->a_formatting);
3710
3711 /* 2. Remove entry from the list of active formatting elements. */
3712 array_pop($this->a_formatting);
3713
3714 /* 3. If entry was a marker, then stop the algorithm at this point.
3715 The list has been cleared up to the last marker. */
3716 if($entry === self::MARKER) {
3717 break;
3718 }
3719 }
3720 }

◆ closeCell() [1/2]

HTML5TreeConstructer::closeCell ( )
private

Definition at line 4766 of file PH5P.php.

4767 {
4768 /* If the stack of open elements has a td or th element in table scope,
4769 then act as if an end tag token with that tag name had been seen. */
4770 foreach (array('td', 'th') as $cell) {
4771 if ($this->elementInScope($cell, true)) {
4772 $this->inCell(
4773 array(
4774 'name' => $cell,
4775 'type' => HTML5::ENDTAG
4776 )
4777 );
4778
4779 break;
4780 }
4781 }
4782 }
elementInScope($el, $table=false)
Definition: PH5P.php:4466

References elementInScope(), HTML5\ENDTAG, and inCell().

Referenced by inCell().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ closeCell() [2/2]

HTML5TreeConstructer::closeCell ( )
private

Definition at line 3869 of file PH5P.php.

3870 {
3871 /* If the stack of open elements has a td or th element in table scope,
3872 then act as if an end tag token with that tag name had been seen. */
3873 foreach(array('td', 'th') as $cell) {
3874 if($this->elementInScope($cell, true)) {
3875 $this->inCell(array(
3876 'name' => $cell,
3877 'type' => HTML5::ENDTAG
3878 ));
3879
3880 break;
3881 }
3882 }
3883 }

References elementInScope(), HTML5\ENDTAG, and inCell().

+ Here is the call graph for this function:

◆ elementInScope() [1/2]

HTML5TreeConstructer::elementInScope (   $el,
  $table = false 
)
private

Definition at line 4466 of file PH5P.php.

4467 {
4468 if (is_array($el)) {
4469 foreach ($el as $element) {
4470 if ($this->elementInScope($element, $table)) {
4471 return true;
4472 }
4473 }
4474
4475 return false;
4476 }
4477
4478 $leng = count($this->stack);
4479
4480 for ($n = 0; $n < $leng; $n++) {
4481 /* 1. Initialise node to be the current node (the bottommost node of
4482 the stack). */
4483 $node = $this->stack[$leng - 1 - $n];
4484
4485 if ($node->tagName === $el) {
4486 /* 2. If node is the target node, terminate in a match state. */
4487 return true;
4488
4489 } elseif ($node->tagName === 'table') {
4490 /* 3. Otherwise, if node is a table element, terminate in a failure
4491 state. */
4492 return false;
4493
4494 } elseif ($table === true && in_array(
4495 $node->tagName,
4496 array(
4497 'caption',
4498 'td',
4499 'th',
4500 'button',
4501 'marquee',
4502 'object'
4503 )
4504 )
4505 ) {
4506 /* 4. Otherwise, if the algorithm is the "has an element in scope"
4507 variant (rather than the "has an element in table scope" variant),
4508 and node is one of the following, terminate in a failure state. */
4509 return false;
4510
4511 } elseif ($node === $node->ownerDocument->documentElement) {
4512 /* 5. Otherwise, if node is an html element (root element), terminate
4513 in a failure state. (This can only happen if the node is the topmost
4514 node of the stack of open elements, and prevents the next step from
4515 being invoked if there are no more elements in the stack.) */
4516 return false;
4517 }
4518
4519 /* Otherwise, set node to the previous entry in the stack of open
4520 elements and return to step 2. (This will never fail, since the loop
4521 will always terminate in the previous step if the top of the stack
4522 is reached.) */
4523 }
4524 }

References $n, $table, and elementInScope().

Referenced by closeCell(), elementInScope(), inBody(), inCaption(), inCell(), inRow(), inSelect(), inTable(), and inTableBody().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ elementInScope() [2/2]

HTML5TreeConstructer::elementInScope (   $el,
  $table = false 
)
private

Definition at line 3578 of file PH5P.php.

3579 {
3580 if(is_array($el)) {
3581 foreach($el as $element) {
3582 if($this->elementInScope($element, $table)) {
3583 return true;
3584 }
3585 }
3586
3587 return false;
3588 }
3589
3590 $leng = count($this->stack);
3591
3592 for($n = 0; $n < $leng; $n++) {
3593 /* 1. Initialise node to be the current node (the bottommost node of
3594 the stack). */
3595 $node = $this->stack[$leng - 1 - $n];
3596
3597 if($node->tagName === $el) {
3598 /* 2. If node is the target node, terminate in a match state. */
3599 return true;
3600
3601 } elseif($node->tagName === 'table') {
3602 /* 3. Otherwise, if node is a table element, terminate in a failure
3603 state. */
3604 return false;
3605
3606 } elseif($table === true && in_array($node->tagName, array('caption', 'td',
3607 'th', 'button', 'marquee', 'object'))) {
3608 /* 4. Otherwise, if the algorithm is the "has an element in scope"
3609 variant (rather than the "has an element in table scope" variant),
3610 and node is one of the following, terminate in a failure state. */
3611 return false;
3612
3613 } elseif($node === $node->ownerDocument->documentElement) {
3614 /* 5. Otherwise, if node is an html element (root element), terminate
3615 in a failure state. (This can only happen if the node is the topmost
3616 node of the stack of open elements, and prevents the next step from
3617 being invoked if there are no more elements in the stack.) */
3618 return false;
3619 }
3620
3621 /* Otherwise, set node to the previous entry in the stack of open
3622 elements and return to step 2. (This will never fail, since the loop
3623 will always terminate in the previous step if the top of the stack
3624 is reached.) */
3625 }
3626 }

References $n, $table, and elementInScope().

+ Here is the call graph for this function:

◆ emitToken() [1/2]

HTML5TreeConstructer::emitToken (   $token)

Definition at line 1713 of file PH5P.php.

1714 {
1715 switch ($this->phase) {
1716 case self::INIT_PHASE:
1717 return $this->initPhase($token);
1718 break;
1719 case self::ROOT_PHASE:
1720 return $this->rootElementPhase($token);
1721 break;
1722 case self::MAIN_PHASE:
1723 return $this->mainPhase($token);
1724 break;
1725 case self::END_PHASE :
1726 return $this->trailingEndPhase($token);
1727 break;
1728 }
1729 }
rootElementPhase($token)
Definition: PH5P.php:1786
mainPhase($token)
Definition: PH5P.php:1836
trailingEndPhase($token)
Definition: PH5P.php:4351
initPhase($token)
Definition: PH5P.php:1731

References END_PHASE, INIT_PHASE, initPhase(), MAIN_PHASE, mainPhase(), ROOT_PHASE, rootElementPhase(), and trailingEndPhase().

Referenced by inBody().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ emitToken() [2/2]

HTML5TreeConstructer::emitToken (   $token)

Definition at line 1208 of file PH5P.php.

1209 {
1210 switch($this->phase) {
1211 case self::INIT_PHASE: return $this->initPhase($token); break;
1212 case self::ROOT_PHASE: return $this->rootElementPhase($token); break;
1213 case self::MAIN_PHASE: return $this->mainPhase($token); break;
1214 case self::END_PHASE : return $this->trailingEndPhase($token); break;
1215 }
1216 }

References END_PHASE, INIT_PHASE, initPhase(), MAIN_PHASE, mainPhase(), ROOT_PHASE, rootElementPhase(), and trailingEndPhase().

+ Here is the call graph for this function:

◆ generateImpliedEndTags() [1/2]

HTML5TreeConstructer::generateImpliedEndTags (   $exclude = array())
private

Definition at line 4620 of file PH5P.php.

4621 {
4622 /* When the steps below require the UA to generate implied end tags,
4623 then, if the current node is a dd element, a dt element, an li element,
4624 a p element, a td element, a th element, or a tr element, the UA must
4625 act as if an end tag with the respective tag name had been seen and
4626 then generate implied end tags again. */
4627 $node = end($this->stack);
4628 $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
4629
4630 while (in_array(end($this->stack)->nodeName, $elements)) {
4631 array_pop($this->stack);
4632 }
4633 }
if(! $in) $exclude

References $exclude.

Referenced by inBody(), inCaption(), inCell(), inTable(), and mainPhase().

+ Here is the caller graph for this function:

◆ generateImpliedEndTags() [2/2]

HTML5TreeConstructer::generateImpliedEndTags ( array  $exclude = array())
private

Definition at line 3722 of file PH5P.php.

3723 {
3724 /* When the steps below require the UA to generate implied end tags,
3725 then, if the current node is a dd element, a dt element, an li element,
3726 a p element, a td element, a th element, or a tr element, the UA must
3727 act as if an end tag with the respective tag name had been seen and
3728 then generate implied end tags again. */
3729 $node = end($this->stack);
3730 $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
3731
3732 while(in_array(end($this->stack)->nodeName, $elements)) {
3733 array_pop($this->stack);
3734 }
3735 }

References $exclude.

◆ getElementCategory() [1/2]

HTML5TreeConstructer::getElementCategory (   $name)
private

Definition at line 3737 of file PH5P.php.

3738 {
3739 if(in_array($name, $this->special))
3740 return self::SPECIAL;
3741
3742 elseif(in_array($name, $this->scoping))
3743 return self::SCOPING;
3744
3745 elseif(in_array($name, $this->formatting))
3746 return self::FORMATTING;
3747
3748 else
3749 return self::PHRASING;
3750 }
if($format !==null) $name
Definition: metadata.php:146

References $name, FORMATTING, PHRASING, SCOPING, and SPECIAL.

◆ getElementCategory() [2/2]

HTML5TreeConstructer::getElementCategory (   $node)
private

Definition at line 4635 of file PH5P.php.

4636 {
4637 $name = $node->tagName;
4638 if (in_array($name, $this->special)) {
4639 return self::SPECIAL;
4640 } elseif (in_array($name, $this->scoping)) {
4641 return self::SCOPING;
4642 } elseif (in_array($name, $this->formatting)) {
4643 return self::FORMATTING;
4644 } else {
4645 return self::PHRASING;
4646 }
4647 }

References $name, FORMATTING, PHRASING, SCOPING, and SPECIAL.

Referenced by inBody().

+ Here is the caller graph for this function:

◆ inBody() [1/2]

HTML5TreeConstructer::inBody (   $token)
private

Definition at line 2176 of file PH5P.php.

2177 {
2178 /* Handle the token as follows: */
2179
2180 switch ($token['type']) {
2181 /* A character token */
2182 case HTML5::CHARACTR:
2183 /* Reconstruct the active formatting elements, if any. */
2185
2186 /* Append the token's character to the current node. */
2187 $this->insertText($token['data']);
2188 break;
2189
2190 /* A comment token */
2191 case HTML5::COMMENT:
2192 /* Append a Comment node to the current node with the data
2193 attribute set to the data given in the comment token. */
2194 $this->insertComment($token['data']);
2195 break;
2196
2197 case HTML5::STARTTAG:
2198 switch ($token['name']) {
2199 /* A start tag token whose tag name is one of: "script",
2200 "style" */
2201 case 'script':
2202 case 'style':
2203 /* Process the token as if the insertion mode had been "in
2204 head". */
2205 return $this->inHead($token);
2206 break;
2207
2208 /* A start tag token whose tag name is one of: "base", "link",
2209 "meta", "title" */
2210 case 'base':
2211 case 'link':
2212 case 'meta':
2213 case 'title':
2214 /* Parse error. Process the token as if the insertion mode
2215 had been "in head". */
2216 return $this->inHead($token);
2217 break;
2218
2219 /* A start tag token with the tag name "body" */
2220 case 'body':
2221 /* Parse error. If the second element on the stack of open
2222 elements is not a body element, or, if the stack of open
2223 elements has only one node on it, then ignore the token.
2224 (innerHTML case) */
2225 if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') {
2226 // Ignore
2227
2228 /* Otherwise, for each attribute on the token, check to see
2229 if the attribute is already present on the body element (the
2230 second element) on the stack of open elements. If it is not,
2231 add the attribute and its corresponding value to that
2232 element. */
2233 } else {
2234 foreach ($token['attr'] as $attr) {
2235 if (!$this->stack[1]->hasAttribute($attr['name'])) {
2236 $this->stack[1]->setAttribute($attr['name'], $attr['value']);
2237 }
2238 }
2239 }
2240 break;
2241
2242 /* A start tag whose tag name is one of: "address",
2243 "blockquote", "center", "dir", "div", "dl", "fieldset",
2244 "listing", "menu", "ol", "p", "ul" */
2245 case 'address':
2246 case 'blockquote':
2247 case 'center':
2248 case 'dir':
2249 case 'div':
2250 case 'dl':
2251 case 'fieldset':
2252 case 'listing':
2253 case 'menu':
2254 case 'ol':
2255 case 'p':
2256 case 'ul':
2257 /* If the stack of open elements has a p element in scope,
2258 then act as if an end tag with the tag name p had been
2259 seen. */
2260 if ($this->elementInScope('p')) {
2261 $this->emitToken(
2262 array(
2263 'name' => 'p',
2264 'type' => HTML5::ENDTAG
2265 )
2266 );
2267 }
2268
2269 /* Insert an HTML element for the token. */
2270 $this->insertElement($token);
2271 break;
2272
2273 /* A start tag whose tag name is "form" */
2274 case 'form':
2275 /* If the form element pointer is not null, ignore the
2276 token with a parse error. */
2277 if ($this->form_pointer !== null) {
2278 // Ignore.
2279
2280 /* Otherwise: */
2281 } else {
2282 /* If the stack of open elements has a p element in
2283 scope, then act as if an end tag with the tag name p
2284 had been seen. */
2285 if ($this->elementInScope('p')) {
2286 $this->emitToken(
2287 array(
2288 'name' => 'p',
2289 'type' => HTML5::ENDTAG
2290 )
2291 );
2292 }
2293
2294 /* Insert an HTML element for the token, and set the
2295 form element pointer to point to the element created. */
2296 $element = $this->insertElement($token);
2297 $this->form_pointer = $element;
2298 }
2299 break;
2300
2301 /* A start tag whose tag name is "li", "dd" or "dt" */
2302 case 'li':
2303 case 'dd':
2304 case 'dt':
2305 /* If the stack of open elements has a p element in scope,
2306 then act as if an end tag with the tag name p had been
2307 seen. */
2308 if ($this->elementInScope('p')) {
2309 $this->emitToken(
2310 array(
2311 'name' => 'p',
2312 'type' => HTML5::ENDTAG
2313 )
2314 );
2315 }
2316
2317 $stack_length = count($this->stack) - 1;
2318
2319 for ($n = $stack_length; 0 <= $n; $n--) {
2320 /* 1. Initialise node to be the current node (the
2321 bottommost node of the stack). */
2322 $stop = false;
2323 $node = $this->stack[$n];
2324 $cat = $this->getElementCategory($node->tagName);
2325
2326 /* 2. If node is an li, dd or dt element, then pop all
2327 the nodes from the current node up to node, including
2328 node, then stop this algorithm. */
2329 if ($token['name'] === $node->tagName || ($token['name'] !== 'li'
2330 && ($node->tagName === 'dd' || $node->tagName === 'dt'))
2331 ) {
2332 for ($x = $stack_length; $x >= $n; $x--) {
2333 array_pop($this->stack);
2334 }
2335
2336 break;
2337 }
2338
2339 /* 3. If node is not in the formatting category, and is
2340 not in the phrasing category, and is not an address or
2341 div element, then stop this algorithm. */
2342 if ($cat !== self::FORMATTING && $cat !== self::PHRASING &&
2343 $node->tagName !== 'address' && $node->tagName !== 'div'
2344 ) {
2345 break;
2346 }
2347 }
2348
2349 /* Finally, insert an HTML element with the same tag
2350 name as the token's. */
2351 $this->insertElement($token);
2352 break;
2353
2354 /* A start tag token whose tag name is "plaintext" */
2355 case 'plaintext':
2356 /* If the stack of open elements has a p element in scope,
2357 then act as if an end tag with the tag name p had been
2358 seen. */
2359 if ($this->elementInScope('p')) {
2360 $this->emitToken(
2361 array(
2362 'name' => 'p',
2363 'type' => HTML5::ENDTAG
2364 )
2365 );
2366 }
2367
2368 /* Insert an HTML element for the token. */
2369 $this->insertElement($token);
2370
2371 return HTML5::PLAINTEXT;
2372 break;
2373
2374 /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
2375 "h5", "h6" */
2376 case 'h1':
2377 case 'h2':
2378 case 'h3':
2379 case 'h4':
2380 case 'h5':
2381 case 'h6':
2382 /* If the stack of open elements has a p element in scope,
2383 then act as if an end tag with the tag name p had been seen. */
2384 if ($this->elementInScope('p')) {
2385 $this->emitToken(
2386 array(
2387 'name' => 'p',
2388 'type' => HTML5::ENDTAG
2389 )
2390 );
2391 }
2392
2393 /* If the stack of open elements has in scope an element whose
2394 tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
2395 this is a parse error; pop elements from the stack until an
2396 element with one of those tag names has been popped from the
2397 stack. */
2398 while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
2399 array_pop($this->stack);
2400 }
2401
2402 /* Insert an HTML element for the token. */
2403 $this->insertElement($token);
2404 break;
2405
2406 /* A start tag whose tag name is "a" */
2407 case 'a':
2408 /* If the list of active formatting elements contains
2409 an element whose tag name is "a" between the end of the
2410 list and the last marker on the list (or the start of
2411 the list if there is no marker on the list), then this
2412 is a parse error; act as if an end tag with the tag name
2413 "a" had been seen, then remove that element from the list
2414 of active formatting elements and the stack of open
2415 elements if the end tag didn't already remove it (it
2416 might not have if the element is not in table scope). */
2417 $leng = count($this->a_formatting);
2418
2419 for ($n = $leng - 1; $n >= 0; $n--) {
2420 if ($this->a_formatting[$n] === self::MARKER) {
2421 break;
2422
2423 } elseif ($this->a_formatting[$n]->nodeName === 'a') {
2424 $this->emitToken(
2425 array(
2426 'name' => 'a',
2427 'type' => HTML5::ENDTAG
2428 )
2429 );
2430 break;
2431 }
2432 }
2433
2434 /* Reconstruct the active formatting elements, if any. */
2436
2437 /* Insert an HTML element for the token. */
2438 $el = $this->insertElement($token);
2439
2440 /* Add that element to the list of active formatting
2441 elements. */
2442 $this->a_formatting[] = $el;
2443 break;
2444
2445 /* A start tag whose tag name is one of: "b", "big", "em", "font",
2446 "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
2447 case 'b':
2448 case 'big':
2449 case 'em':
2450 case 'font':
2451 case 'i':
2452 case 'nobr':
2453 case 's':
2454 case 'small':
2455 case 'strike':
2456 case 'strong':
2457 case 'tt':
2458 case 'u':
2459 /* Reconstruct the active formatting elements, if any. */
2461
2462 /* Insert an HTML element for the token. */
2463 $el = $this->insertElement($token);
2464
2465 /* Add that element to the list of active formatting
2466 elements. */
2467 $this->a_formatting[] = $el;
2468 break;
2469
2470 /* A start tag token whose tag name is "button" */
2471 case 'button':
2472 /* If the stack of open elements has a button element in scope,
2473 then this is a parse error; act as if an end tag with the tag
2474 name "button" had been seen, then reprocess the token. (We don't
2475 do that. Unnecessary.) */
2476 if ($this->elementInScope('button')) {
2477 $this->inBody(
2478 array(
2479 'name' => 'button',
2480 'type' => HTML5::ENDTAG
2481 )
2482 );
2483 }
2484
2485 /* Reconstruct the active formatting elements, if any. */
2487
2488 /* Insert an HTML element for the token. */
2489 $this->insertElement($token);
2490
2491 /* Insert a marker at the end of the list of active
2492 formatting elements. */
2493 $this->a_formatting[] = self::MARKER;
2494 break;
2495
2496 /* A start tag token whose tag name is one of: "marquee", "object" */
2497 case 'marquee':
2498 case 'object':
2499 /* Reconstruct the active formatting elements, if any. */
2501
2502 /* Insert an HTML element for the token. */
2503 $this->insertElement($token);
2504
2505 /* Insert a marker at the end of the list of active
2506 formatting elements. */
2507 $this->a_formatting[] = self::MARKER;
2508 break;
2509
2510 /* A start tag token whose tag name is "xmp" */
2511 case 'xmp':
2512 /* Reconstruct the active formatting elements, if any. */
2514
2515 /* Insert an HTML element for the token. */
2516 $this->insertElement($token);
2517
2518 /* Switch the content model flag to the CDATA state. */
2519 return HTML5::CDATA;
2520 break;
2521
2522 /* A start tag whose tag name is "table" */
2523 case 'table':
2524 /* If the stack of open elements has a p element in scope,
2525 then act as if an end tag with the tag name p had been seen. */
2526 if ($this->elementInScope('p')) {
2527 $this->emitToken(
2528 array(
2529 'name' => 'p',
2530 'type' => HTML5::ENDTAG
2531 )
2532 );
2533 }
2534
2535 /* Insert an HTML element for the token. */
2536 $this->insertElement($token);
2537
2538 /* Change the insertion mode to "in table". */
2539 $this->mode = self::IN_TABLE;
2540 break;
2541
2542 /* A start tag whose tag name is one of: "area", "basefont",
2543 "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
2544 case 'area':
2545 case 'basefont':
2546 case 'bgsound':
2547 case 'br':
2548 case 'embed':
2549 case 'img':
2550 case 'param':
2551 case 'spacer':
2552 case 'wbr':
2553 /* Reconstruct the active formatting elements, if any. */
2555
2556 /* Insert an HTML element for the token. */
2557 $this->insertElement($token);
2558
2559 /* Immediately pop the current node off the stack of open elements. */
2560 array_pop($this->stack);
2561 break;
2562
2563 /* A start tag whose tag name is "hr" */
2564 case 'hr':
2565 /* If the stack of open elements has a p element in scope,
2566 then act as if an end tag with the tag name p had been seen. */
2567 if ($this->elementInScope('p')) {
2568 $this->emitToken(
2569 array(
2570 'name' => 'p',
2571 'type' => HTML5::ENDTAG
2572 )
2573 );
2574 }
2575
2576 /* Insert an HTML element for the token. */
2577 $this->insertElement($token);
2578
2579 /* Immediately pop the current node off the stack of open elements. */
2580 array_pop($this->stack);
2581 break;
2582
2583 /* A start tag whose tag name is "image" */
2584 case 'image':
2585 /* Parse error. Change the token's tag name to "img" and
2586 reprocess it. (Don't ask.) */
2587 $token['name'] = 'img';
2588 return $this->inBody($token);
2589 break;
2590
2591 /* A start tag whose tag name is "input" */
2592 case 'input':
2593 /* Reconstruct the active formatting elements, if any. */
2595
2596 /* Insert an input element for the token. */
2597 $element = $this->insertElement($token, false);
2598
2599 /* If the form element pointer is not null, then associate the
2600 input element with the form element pointed to by the form
2601 element pointer. */
2602 $this->form_pointer !== null
2603 ? $this->form_pointer->appendChild($element)
2604 : end($this->stack)->appendChild($element);
2605
2606 /* Pop that input element off the stack of open elements. */
2607 array_pop($this->stack);
2608 break;
2609
2610 /* A start tag whose tag name is "isindex" */
2611 case 'isindex':
2612 /* Parse error. */
2613 // w/e
2614
2615 /* If the form element pointer is not null,
2616 then ignore the token. */
2617 if ($this->form_pointer === null) {
2618 /* Act as if a start tag token with the tag name "form" had
2619 been seen. */
2620 $this->inBody(
2621 array(
2622 'name' => 'body',
2623 'type' => HTML5::STARTTAG,
2624 'attr' => array()
2625 )
2626 );
2627
2628 /* Act as if a start tag token with the tag name "hr" had
2629 been seen. */
2630 $this->inBody(
2631 array(
2632 'name' => 'hr',
2633 'type' => HTML5::STARTTAG,
2634 'attr' => array()
2635 )
2636 );
2637
2638 /* Act as if a start tag token with the tag name "p" had
2639 been seen. */
2640 $this->inBody(
2641 array(
2642 'name' => 'p',
2643 'type' => HTML5::STARTTAG,
2644 'attr' => array()
2645 )
2646 );
2647
2648 /* Act as if a start tag token with the tag name "label"
2649 had been seen. */
2650 $this->inBody(
2651 array(
2652 'name' => 'label',
2653 'type' => HTML5::STARTTAG,
2654 'attr' => array()
2655 )
2656 );
2657
2658 /* Act as if a stream of character tokens had been seen. */
2659 $this->insertText(
2660 'This is a searchable index. ' .
2661 'Insert your search keywords here: '
2662 );
2663
2664 /* Act as if a start tag token with the tag name "input"
2665 had been seen, with all the attributes from the "isindex"
2666 token, except with the "name" attribute set to the value
2667 "isindex" (ignoring any explicit "name" attribute). */
2668 $attr = $token['attr'];
2669 $attr[] = array('name' => 'name', 'value' => 'isindex');
2670
2671 $this->inBody(
2672 array(
2673 'name' => 'input',
2674 'type' => HTML5::STARTTAG,
2675 'attr' => $attr
2676 )
2677 );
2678
2679 /* Act as if a stream of character tokens had been seen
2680 (see below for what they should say). */
2681 $this->insertText(
2682 'This is a searchable index. ' .
2683 'Insert your search keywords here: '
2684 );
2685
2686 /* Act as if an end tag token with the tag name "label"
2687 had been seen. */
2688 $this->inBody(
2689 array(
2690 'name' => 'label',
2691 'type' => HTML5::ENDTAG
2692 )
2693 );
2694
2695 /* Act as if an end tag token with the tag name "p" had
2696 been seen. */
2697 $this->inBody(
2698 array(
2699 'name' => 'p',
2700 'type' => HTML5::ENDTAG
2701 )
2702 );
2703
2704 /* Act as if a start tag token with the tag name "hr" had
2705 been seen. */
2706 $this->inBody(
2707 array(
2708 'name' => 'hr',
2709 'type' => HTML5::ENDTAG
2710 )
2711 );
2712
2713 /* Act as if an end tag token with the tag name "form" had
2714 been seen. */
2715 $this->inBody(
2716 array(
2717 'name' => 'form',
2718 'type' => HTML5::ENDTAG
2719 )
2720 );
2721 }
2722 break;
2723
2724 /* A start tag whose tag name is "textarea" */
2725 case 'textarea':
2726 $this->insertElement($token);
2727
2728 /* Switch the tokeniser's content model flag to the
2729 RCDATA state. */
2730 return HTML5::RCDATA;
2731 break;
2732
2733 /* A start tag whose tag name is one of: "iframe", "noembed",
2734 "noframes" */
2735 case 'iframe':
2736 case 'noembed':
2737 case 'noframes':
2738 $this->insertElement($token);
2739
2740 /* Switch the tokeniser's content model flag to the CDATA state. */
2741 return HTML5::CDATA;
2742 break;
2743
2744 /* A start tag whose tag name is "select" */
2745 case 'select':
2746 /* Reconstruct the active formatting elements, if any. */
2748
2749 /* Insert an HTML element for the token. */
2750 $this->insertElement($token);
2751
2752 /* Change the insertion mode to "in select". */
2753 $this->mode = self::IN_SELECT;
2754 break;
2755
2756 /* A start or end tag whose tag name is one of: "caption", "col",
2757 "colgroup", "frame", "frameset", "head", "option", "optgroup",
2758 "tbody", "td", "tfoot", "th", "thead", "tr". */
2759 case 'caption':
2760 case 'col':
2761 case 'colgroup':
2762 case 'frame':
2763 case 'frameset':
2764 case 'head':
2765 case 'option':
2766 case 'optgroup':
2767 case 'tbody':
2768 case 'td':
2769 case 'tfoot':
2770 case 'th':
2771 case 'thead':
2772 case 'tr':
2773 // Parse error. Ignore the token.
2774 break;
2775
2776 /* A start or end tag whose tag name is one of: "event-source",
2777 "section", "nav", "article", "aside", "header", "footer",
2778 "datagrid", "command" */
2779 case 'event-source':
2780 case 'section':
2781 case 'nav':
2782 case 'article':
2783 case 'aside':
2784 case 'header':
2785 case 'footer':
2786 case 'datagrid':
2787 case 'command':
2788 // Work in progress!
2789 break;
2790
2791 /* A start tag token not covered by the previous entries */
2792 default:
2793 /* Reconstruct the active formatting elements, if any. */
2795
2796 $this->insertElement($token, true, true);
2797 break;
2798 }
2799 break;
2800
2801 case HTML5::ENDTAG:
2802 switch ($token['name']) {
2803 /* An end tag with the tag name "body" */
2804 case 'body':
2805 /* If the second element in the stack of open elements is
2806 not a body element, this is a parse error. Ignore the token.
2807 (innerHTML case) */
2808 if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') {
2809 // Ignore.
2810
2811 /* If the current node is not the body element, then this
2812 is a parse error. */
2813 } elseif (end($this->stack)->nodeName !== 'body') {
2814 // Parse error.
2815 }
2816
2817 /* Change the insertion mode to "after body". */
2818 $this->mode = self::AFTER_BODY;
2819 break;
2820
2821 /* An end tag with the tag name "html" */
2822 case 'html':
2823 /* Act as if an end tag with tag name "body" had been seen,
2824 then, if that token wasn't ignored, reprocess the current
2825 token. */
2826 $this->inBody(
2827 array(
2828 'name' => 'body',
2829 'type' => HTML5::ENDTAG
2830 )
2831 );
2832
2833 return $this->afterBody($token);
2834 break;
2835
2836 /* An end tag whose tag name is one of: "address", "blockquote",
2837 "center", "dir", "div", "dl", "fieldset", "listing", "menu",
2838 "ol", "pre", "ul" */
2839 case 'address':
2840 case 'blockquote':
2841 case 'center':
2842 case 'dir':
2843 case 'div':
2844 case 'dl':
2845 case 'fieldset':
2846 case 'listing':
2847 case 'menu':
2848 case 'ol':
2849 case 'pre':
2850 case 'ul':
2851 /* If the stack of open elements has an element in scope
2852 with the same tag name as that of the token, then generate
2853 implied end tags. */
2854 if ($this->elementInScope($token['name'])) {
2855 $this->generateImpliedEndTags();
2856
2857 /* Now, if the current node is not an element with
2858 the same tag name as that of the token, then this
2859 is a parse error. */
2860 // w/e
2861
2862 /* If the stack of open elements has an element in
2863 scope with the same tag name as that of the token,
2864 then pop elements from this stack until an element
2865 with that tag name has been popped from the stack. */
2866 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
2867 if ($this->stack[$n]->nodeName === $token['name']) {
2868 $n = -1;
2869 }
2870
2871 array_pop($this->stack);
2872 }
2873 }
2874 break;
2875
2876 /* An end tag whose tag name is "form" */
2877 case 'form':
2878 /* If the stack of open elements has an element in scope
2879 with the same tag name as that of the token, then generate
2880 implied end tags. */
2881 if ($this->elementInScope($token['name'])) {
2882 $this->generateImpliedEndTags();
2883
2884 }
2885
2886 if (end($this->stack)->nodeName !== $token['name']) {
2887 /* Now, if the current node is not an element with the
2888 same tag name as that of the token, then this is a parse
2889 error. */
2890 // w/e
2891
2892 } else {
2893 /* Otherwise, if the current node is an element with
2894 the same tag name as that of the token pop that element
2895 from the stack. */
2896 array_pop($this->stack);
2897 }
2898
2899 /* In any case, set the form element pointer to null. */
2900 $this->form_pointer = null;
2901 break;
2902
2903 /* An end tag whose tag name is "p" */
2904 case 'p':
2905 /* If the stack of open elements has a p element in scope,
2906 then generate implied end tags, except for p elements. */
2907 if ($this->elementInScope('p')) {
2908 $this->generateImpliedEndTags(array('p'));
2909
2910 /* If the current node is not a p element, then this is
2911 a parse error. */
2912 // k
2913
2914 /* If the stack of open elements has a p element in
2915 scope, then pop elements from this stack until the stack
2916 no longer has a p element in scope. */
2917 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
2918 if ($this->elementInScope('p')) {
2919 array_pop($this->stack);
2920
2921 } else {
2922 break;
2923 }
2924 }
2925 }
2926 break;
2927
2928 /* An end tag whose tag name is "dd", "dt", or "li" */
2929 case 'dd':
2930 case 'dt':
2931 case 'li':
2932 /* If the stack of open elements has an element in scope
2933 whose tag name matches the tag name of the token, then
2934 generate implied end tags, except for elements with the
2935 same tag name as the token. */
2936 if ($this->elementInScope($token['name'])) {
2937 $this->generateImpliedEndTags(array($token['name']));
2938
2939 /* If the current node is not an element with the same
2940 tag name as the token, then this is a parse error. */
2941 // w/e
2942
2943 /* If the stack of open elements has an element in scope
2944 whose tag name matches the tag name of the token, then
2945 pop elements from this stack until an element with that
2946 tag name has been popped from the stack. */
2947 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
2948 if ($this->stack[$n]->nodeName === $token['name']) {
2949 $n = -1;
2950 }
2951
2952 array_pop($this->stack);
2953 }
2954 }
2955 break;
2956
2957 /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
2958 "h5", "h6" */
2959 case 'h1':
2960 case 'h2':
2961 case 'h3':
2962 case 'h4':
2963 case 'h5':
2964 case 'h6':
2965 $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
2966
2967 /* If the stack of open elements has in scope an element whose
2968 tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
2969 generate implied end tags. */
2970 if ($this->elementInScope($elements)) {
2971 $this->generateImpliedEndTags();
2972
2973 /* Now, if the current node is not an element with the same
2974 tag name as that of the token, then this is a parse error. */
2975 // w/e
2976
2977 /* If the stack of open elements has in scope an element
2978 whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
2979 "h6", then pop elements from the stack until an element
2980 with one of those tag names has been popped from the stack. */
2981 while ($this->elementInScope($elements)) {
2982 array_pop($this->stack);
2983 }
2984 }
2985 break;
2986
2987 /* An end tag whose tag name is one of: "a", "b", "big", "em",
2988 "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
2989 case 'a':
2990 case 'b':
2991 case 'big':
2992 case 'em':
2993 case 'font':
2994 case 'i':
2995 case 'nobr':
2996 case 's':
2997 case 'small':
2998 case 'strike':
2999 case 'strong':
3000 case 'tt':
3001 case 'u':
3002 /* 1. Let the formatting element be the last element in
3003 the list of active formatting elements that:
3004 * is between the end of the list and the last scope
3005 marker in the list, if any, or the start of the list
3006 otherwise, and
3007 * has the same tag name as the token.
3008 */
3009 while (true) {
3010 for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
3011 if ($this->a_formatting[$a] === self::MARKER) {
3012 break;
3013
3014 } elseif ($this->a_formatting[$a]->tagName === $token['name']) {
3015 $formatting_element = $this->a_formatting[$a];
3016 $in_stack = in_array($formatting_element, $this->stack, true);
3017 $fe_af_pos = $a;
3018 break;
3019 }
3020 }
3021
3022 /* If there is no such node, or, if that node is
3023 also in the stack of open elements but the element
3024 is not in scope, then this is a parse error. Abort
3025 these steps. The token is ignored. */
3026 if (!isset($formatting_element) || ($in_stack &&
3027 !$this->elementInScope($token['name']))
3028 ) {
3029 break;
3030
3031 /* Otherwise, if there is such a node, but that node
3032 is not in the stack of open elements, then this is a
3033 parse error; remove the element from the list, and
3034 abort these steps. */
3035 } elseif (isset($formatting_element) && !$in_stack) {
3036 unset($this->a_formatting[$fe_af_pos]);
3037 $this->a_formatting = array_merge($this->a_formatting);
3038 break;
3039 }
3040
3041 /* 2. Let the furthest block be the topmost node in the
3042 stack of open elements that is lower in the stack
3043 than the formatting element, and is not an element in
3044 the phrasing or formatting categories. There might
3045 not be one. */
3046 $fe_s_pos = array_search($formatting_element, $this->stack, true);
3047 $length = count($this->stack);
3048
3049 for ($s = $fe_s_pos + 1; $s < $length; $s++) {
3050 $category = $this->getElementCategory($this->stack[$s]->nodeName);
3051
3052 if ($category !== self::PHRASING && $category !== self::FORMATTING) {
3053 $furthest_block = $this->stack[$s];
3054 }
3055 }
3056
3057 /* 3. If there is no furthest block, then the UA must
3058 skip the subsequent steps and instead just pop all
3059 the nodes from the bottom of the stack of open
3060 elements, from the current node up to the formatting
3061 element, and remove the formatting element from the
3062 list of active formatting elements. */
3063 if (!isset($furthest_block)) {
3064 for ($n = $length - 1; $n >= $fe_s_pos; $n--) {
3065 array_pop($this->stack);
3066 }
3067
3068 unset($this->a_formatting[$fe_af_pos]);
3069 $this->a_formatting = array_merge($this->a_formatting);
3070 break;
3071 }
3072
3073 /* 4. Let the common ancestor be the element
3074 immediately above the formatting element in the stack
3075 of open elements. */
3076 $common_ancestor = $this->stack[$fe_s_pos - 1];
3077
3078 /* 5. If the furthest block has a parent node, then
3079 remove the furthest block from its parent node. */
3080 if ($furthest_block->parentNode !== null) {
3081 $furthest_block->parentNode->removeChild($furthest_block);
3082 }
3083
3084 /* 6. Let a bookmark note the position of the
3085 formatting element in the list of active formatting
3086 elements relative to the elements on either side
3087 of it in the list. */
3088 $bookmark = $fe_af_pos;
3089
3090 /* 7. Let node and last node be the furthest block.
3091 Follow these steps: */
3092 $node = $furthest_block;
3093 $last_node = $furthest_block;
3094
3095 while (true) {
3096 for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
3097 /* 7.1 Let node be the element immediately
3098 prior to node in the stack of open elements. */
3099 $node = $this->stack[$n];
3100
3101 /* 7.2 If node is not in the list of active
3102 formatting elements, then remove node from
3103 the stack of open elements and then go back
3104 to step 1. */
3105 if (!in_array($node, $this->a_formatting, true)) {
3106 unset($this->stack[$n]);
3107 $this->stack = array_merge($this->stack);
3108
3109 } else {
3110 break;
3111 }
3112 }
3113
3114 /* 7.3 Otherwise, if node is the formatting
3115 element, then go to the next step in the overall
3116 algorithm. */
3117 if ($node === $formatting_element) {
3118 break;
3119
3120 /* 7.4 Otherwise, if last node is the furthest
3121 block, then move the aforementioned bookmark to
3122 be immediately after the node in the list of
3123 active formatting elements. */
3124 } elseif ($last_node === $furthest_block) {
3125 $bookmark = array_search($node, $this->a_formatting, true) + 1;
3126 }
3127
3128 /* 7.5 If node has any children, perform a
3129 shallow clone of node, replace the entry for
3130 node in the list of active formatting elements
3131 with an entry for the clone, replace the entry
3132 for node in the stack of open elements with an
3133 entry for the clone, and let node be the clone. */
3134 if ($node->hasChildNodes()) {
3135 $clone = $node->cloneNode();
3136 $s_pos = array_search($node, $this->stack, true);
3137 $a_pos = array_search($node, $this->a_formatting, true);
3138
3139 $this->stack[$s_pos] = $clone;
3140 $this->a_formatting[$a_pos] = $clone;
3141 $node = $clone;
3142 }
3143
3144 /* 7.6 Insert last node into node, first removing
3145 it from its previous parent node if any. */
3146 if ($last_node->parentNode !== null) {
3147 $last_node->parentNode->removeChild($last_node);
3148 }
3149
3150 $node->appendChild($last_node);
3151
3152 /* 7.7 Let last node be node. */
3153 $last_node = $node;
3154 }
3155
3156 /* 8. Insert whatever last node ended up being in
3157 the previous step into the common ancestor node,
3158 first removing it from its previous parent node if
3159 any. */
3160 if ($last_node->parentNode !== null) {
3161 $last_node->parentNode->removeChild($last_node);
3162 }
3163
3164 $common_ancestor->appendChild($last_node);
3165
3166 /* 9. Perform a shallow clone of the formatting
3167 element. */
3168 $clone = $formatting_element->cloneNode();
3169
3170 /* 10. Take all of the child nodes of the furthest
3171 block and append them to the clone created in the
3172 last step. */
3173 while ($furthest_block->hasChildNodes()) {
3174 $child = $furthest_block->firstChild;
3175 $furthest_block->removeChild($child);
3176 $clone->appendChild($child);
3177 }
3178
3179 /* 11. Append that clone to the furthest block. */
3180 $furthest_block->appendChild($clone);
3181
3182 /* 12. Remove the formatting element from the list
3183 of active formatting elements, and insert the clone
3184 into the list of active formatting elements at the
3185 position of the aforementioned bookmark. */
3186 $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
3187 unset($this->a_formatting[$fe_af_pos]);
3188 $this->a_formatting = array_merge($this->a_formatting);
3189
3190 $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
3191 $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
3192 $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
3193
3194 /* 13. Remove the formatting element from the stack
3195 of open elements, and insert the clone into the stack
3196 of open elements immediately after (i.e. in a more
3197 deeply nested position than) the position of the
3198 furthest block in that stack. */
3199 $fe_s_pos = array_search($formatting_element, $this->stack, true);
3200 $fb_s_pos = array_search($furthest_block, $this->stack, true);
3201 unset($this->stack[$fe_s_pos]);
3202
3203 $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
3204 $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
3205 $this->stack = array_merge($s_part1, array($clone), $s_part2);
3206
3207 /* 14. Jump back to step 1 in this series of steps. */
3208 unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
3209 }
3210 break;
3211
3212 /* An end tag token whose tag name is one of: "button",
3213 "marquee", "object" */
3214 case 'button':
3215 case 'marquee':
3216 case 'object':
3217 /* If the stack of open elements has an element in scope whose
3218 tag name matches the tag name of the token, then generate implied
3219 tags. */
3220 if ($this->elementInScope($token['name'])) {
3221 $this->generateImpliedEndTags();
3222
3223 /* Now, if the current node is not an element with the same
3224 tag name as the token, then this is a parse error. */
3225 // k
3226
3227 /* Now, if the stack of open elements has an element in scope
3228 whose tag name matches the tag name of the token, then pop
3229 elements from the stack until that element has been popped from
3230 the stack, and clear the list of active formatting elements up
3231 to the last marker. */
3232 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
3233 if ($this->stack[$n]->nodeName === $token['name']) {
3234 $n = -1;
3235 }
3236
3237 array_pop($this->stack);
3238 }
3239
3240 $marker = end(array_keys($this->a_formatting, self::MARKER, true));
3241
3242 for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
3243 array_pop($this->a_formatting);
3244 }
3245 }
3246 break;
3247
3248 /* Or an end tag whose tag name is one of: "area", "basefont",
3249 "bgsound", "br", "embed", "hr", "iframe", "image", "img",
3250 "input", "isindex", "noembed", "noframes", "param", "select",
3251 "spacer", "table", "textarea", "wbr" */
3252 case 'area':
3253 case 'basefont':
3254 case 'bgsound':
3255 case 'br':
3256 case 'embed':
3257 case 'hr':
3258 case 'iframe':
3259 case 'image':
3260 case 'img':
3261 case 'input':
3262 case 'isindex':
3263 case 'noembed':
3264 case 'noframes':
3265 case 'param':
3266 case 'select':
3267 case 'spacer':
3268 case 'table':
3269 case 'textarea':
3270 case 'wbr':
3271 // Parse error. Ignore the token.
3272 break;
3273
3274 /* An end tag token not covered by the previous entries */
3275 default:
3276 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
3277 /* Initialise node to be the current node (the bottommost
3278 node of the stack). */
3279 $node = end($this->stack);
3280
3281 /* If node has the same tag name as the end tag token,
3282 then: */
3283 if ($token['name'] === $node->nodeName) {
3284 /* Generate implied end tags. */
3285 $this->generateImpliedEndTags();
3286
3287 /* If the tag name of the end tag token does not
3288 match the tag name of the current node, this is a
3289 parse error. */
3290 // k
3291
3292 /* Pop all the nodes from the current node up to
3293 node, including node, then stop this algorithm. */
3294 for ($x = count($this->stack) - $n; $x >= $n; $x--) {
3295 array_pop($this->stack);
3296 }
3297
3298 } else {
3299 $category = $this->getElementCategory($node);
3300
3301 if ($category !== self::SPECIAL && $category !== self::SCOPING) {
3302 /* Otherwise, if node is in neither the formatting
3303 category nor the phrasing category, then this is a
3304 parse error. Stop this algorithm. The end tag token
3305 is ignored. */
3306 return false;
3307 }
3308 }
3309 }
3310 break;
3311 }
3312 break;
3313 }
3314 }
getElementCategory($node)
Definition: PH5P.php:4635
emitToken($token)
Definition: PH5P.php:1713
afterBody($token)
Definition: PH5P.php:4202
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:4620
reconstructActiveFormattingElements()
Definition: PH5P.php:4526
const CDATA
Definition: PH5P.php:451
const RCDATA
Definition: PH5P.php:450
const PLAINTEXT
Definition: PH5P.php:452
$x
Definition: example_009.php:98
$s
Definition: pwgen.php:45

References $n, $s, $x, AFTER_BODY, afterBody(), HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, elementInScope(), emitToken(), HTML5\ENDTAG, generateImpliedEndTags(), getElementCategory(), IN_SELECT, IN_TABLE, inBody(), inHead(), insertComment(), insertElement(), insertText(), MARKER, HTML5\PLAINTEXT, HTML5\RCDATA, reconstructActiveFormattingElements(), and HTML5\STARTTAG.

Referenced by afterBody(), afterFrameset(), afterHead(), inBody(), inCaption(), inCell(), inFrameset(), inTable(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inBody() [2/2]

HTML5TreeConstructer::inBody (   $token)
private

Definition at line 1605 of file PH5P.php.

1606 {
1607 /* Handle the token as follows: */
1608
1609 switch($token['type']) {
1610 /* A character token */
1611 case HTML5::CHARACTR:
1612 /* Reconstruct the active formatting elements, if any. */
1614
1615 /* Append the token's character to the current node. */
1616 $this->insertText($token['data']);
1617 break;
1618
1619 /* A comment token */
1620 case HTML5::COMMENT:
1621 /* Append a Comment node to the current node with the data
1622 attribute set to the data given in the comment token. */
1623 $this->insertComment($token['data']);
1624 break;
1625
1626 case HTML5::STARTTAG:
1627 switch($token['name']) {
1628 /* A start tag token whose tag name is one of: "script",
1629 "style" */
1630 case 'script': case 'style':
1631 /* Process the token as if the insertion mode had been "in
1632 head". */
1633 return $this->inHead($token);
1634 break;
1635
1636 /* A start tag token whose tag name is one of: "base", "link",
1637 "meta", "title" */
1638 case 'base': case 'link': case 'meta': case 'title':
1639 /* Parse error. Process the token as if the insertion mode
1640 had been "in head". */
1641 return $this->inHead($token);
1642 break;
1643
1644 /* A start tag token with the tag name "body" */
1645 case 'body':
1646 /* Parse error. If the second element on the stack of open
1647 elements is not a body element, or, if the stack of open
1648 elements has only one node on it, then ignore the token.
1649 (innerHTML case) */
1650 if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') {
1651 // Ignore
1652
1653 /* Otherwise, for each attribute on the token, check to see
1654 if the attribute is already present on the body element (the
1655 second element) on the stack of open elements. If it is not,
1656 add the attribute and its corresponding value to that
1657 element. */
1658 } else {
1659 foreach($token['attr'] as $attr) {
1660 if(!$this->stack[1]->hasAttribute($attr['name'])) {
1661 $this->stack[1]->setAttribute($attr['name'], $attr['value']);
1662 }
1663 }
1664 }
1665 break;
1666
1667 /* A start tag whose tag name is one of: "address",
1668 "blockquote", "center", "dir", "div", "dl", "fieldset",
1669 "listing", "menu", "ol", "p", "ul" */
1670 case 'address': case 'blockquote': case 'center': case 'dir':
1671 case 'div': case 'dl': case 'fieldset': case 'listing':
1672 case 'menu': case 'ol': case 'p': case 'ul':
1673 /* If the stack of open elements has a p element in scope,
1674 then act as if an end tag with the tag name p had been
1675 seen. */
1676 if($this->elementInScope('p')) {
1677 $this->emitToken(array(
1678 'name' => 'p',
1679 'type' => HTML5::ENDTAG
1680 ));
1681 }
1682
1683 /* Insert an HTML element for the token. */
1684 $this->insertElement($token);
1685 break;
1686
1687 /* A start tag whose tag name is "form" */
1688 case 'form':
1689 /* If the form element pointer is not null, ignore the
1690 token with a parse error. */
1691 if($this->form_pointer !== null) {
1692 // Ignore.
1693
1694 /* Otherwise: */
1695 } else {
1696 /* If the stack of open elements has a p element in
1697 scope, then act as if an end tag with the tag name p
1698 had been seen. */
1699 if($this->elementInScope('p')) {
1700 $this->emitToken(array(
1701 'name' => 'p',
1702 'type' => HTML5::ENDTAG
1703 ));
1704 }
1705
1706 /* Insert an HTML element for the token, and set the
1707 form element pointer to point to the element created. */
1708 $element = $this->insertElement($token);
1709 $this->form_pointer = $element;
1710 }
1711 break;
1712
1713 /* A start tag whose tag name is "li", "dd" or "dt" */
1714 case 'li': case 'dd': case 'dt':
1715 /* If the stack of open elements has a p element in scope,
1716 then act as if an end tag with the tag name p had been
1717 seen. */
1718 if($this->elementInScope('p')) {
1719 $this->emitToken(array(
1720 'name' => 'p',
1721 'type' => HTML5::ENDTAG
1722 ));
1723 }
1724
1725 $stack_length = count($this->stack) - 1;
1726
1727 for($n = $stack_length; 0 <= $n; $n--) {
1728 /* 1. Initialise node to be the current node (the
1729 bottommost node of the stack). */
1730 $stop = false;
1731 $node = $this->stack[$n];
1732 $cat = $this->getElementCategory($node->tagName);
1733
1734 /* 2. If node is an li, dd or dt element, then pop all
1735 the nodes from the current node up to node, including
1736 node, then stop this algorithm. */
1737 if($token['name'] === $node->tagName || ($token['name'] !== 'li'
1738 && ($node->tagName === 'dd' || $node->tagName === 'dt'))) {
1739 for($x = $stack_length; $x >= $n ; $x--) {
1740 array_pop($this->stack);
1741 }
1742
1743 break;
1744 }
1745
1746 /* 3. If node is not in the formatting category, and is
1747 not in the phrasing category, and is not an address or
1748 div element, then stop this algorithm. */
1749 if($cat !== self::FORMATTING && $cat !== self::PHRASING &&
1750 $node->tagName !== 'address' && $node->tagName !== 'div') {
1751 break;
1752 }
1753 }
1754
1755 /* Finally, insert an HTML element with the same tag
1756 name as the token's. */
1757 $this->insertElement($token);
1758 break;
1759
1760 /* A start tag token whose tag name is "plaintext" */
1761 case 'plaintext':
1762 /* If the stack of open elements has a p element in scope,
1763 then act as if an end tag with the tag name p had been
1764 seen. */
1765 if($this->elementInScope('p')) {
1766 $this->emitToken(array(
1767 'name' => 'p',
1768 'type' => HTML5::ENDTAG
1769 ));
1770 }
1771
1772 /* Insert an HTML element for the token. */
1773 $this->insertElement($token);
1774
1775 return HTML5::PLAINTEXT;
1776 break;
1777
1778 /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
1779 "h5", "h6" */
1780 case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
1781 /* If the stack of open elements has a p element in scope,
1782 then act as if an end tag with the tag name p had been seen. */
1783 if($this->elementInScope('p')) {
1784 $this->emitToken(array(
1785 'name' => 'p',
1786 'type' => HTML5::ENDTAG
1787 ));
1788 }
1789
1790 /* If the stack of open elements has in scope an element whose
1791 tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
1792 this is a parse error; pop elements from the stack until an
1793 element with one of those tag names has been popped from the
1794 stack. */
1795 while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
1796 array_pop($this->stack);
1797 }
1798
1799 /* Insert an HTML element for the token. */
1800 $this->insertElement($token);
1801 break;
1802
1803 /* A start tag whose tag name is "a" */
1804 case 'a':
1805 /* If the list of active formatting elements contains
1806 an element whose tag name is "a" between the end of the
1807 list and the last marker on the list (or the start of
1808 the list if there is no marker on the list), then this
1809 is a parse error; act as if an end tag with the tag name
1810 "a" had been seen, then remove that element from the list
1811 of active formatting elements and the stack of open
1812 elements if the end tag didn't already remove it (it
1813 might not have if the element is not in table scope). */
1814 $leng = count($this->a_formatting);
1815
1816 for($n = $leng - 1; $n >= 0; $n--) {
1817 if($this->a_formatting[$n] === self::MARKER) {
1818 break;
1819
1820 } elseif($this->a_formatting[$n]->nodeName === 'a') {
1821 $this->emitToken(array(
1822 'name' => 'a',
1823 'type' => HTML5::ENDTAG
1824 ));
1825 break;
1826 }
1827 }
1828
1829 /* Reconstruct the active formatting elements, if any. */
1831
1832 /* Insert an HTML element for the token. */
1833 $el = $this->insertElement($token);
1834
1835 /* Add that element to the list of active formatting
1836 elements. */
1837 $this->a_formatting[] = $el;
1838 break;
1839
1840 /* A start tag whose tag name is one of: "b", "big", "em", "font",
1841 "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
1842 case 'b': case 'big': case 'em': case 'font': case 'i':
1843 case 'nobr': case 's': case 'small': case 'strike':
1844 case 'strong': case 'tt': case 'u':
1845 /* Reconstruct the active formatting elements, if any. */
1847
1848 /* Insert an HTML element for the token. */
1849 $el = $this->insertElement($token);
1850
1851 /* Add that element to the list of active formatting
1852 elements. */
1853 $this->a_formatting[] = $el;
1854 break;
1855
1856 /* A start tag token whose tag name is "button" */
1857 case 'button':
1858 /* If the stack of open elements has a button element in scope,
1859 then this is a parse error; act as if an end tag with the tag
1860 name "button" had been seen, then reprocess the token. (We don't
1861 do that. Unnecessary.) */
1862 if($this->elementInScope('button')) {
1863 $this->inBody(array(
1864 'name' => 'button',
1865 'type' => HTML5::ENDTAG
1866 ));
1867 }
1868
1869 /* Reconstruct the active formatting elements, if any. */
1871
1872 /* Insert an HTML element for the token. */
1873 $this->insertElement($token);
1874
1875 /* Insert a marker at the end of the list of active
1876 formatting elements. */
1877 $this->a_formatting[] = self::MARKER;
1878 break;
1879
1880 /* A start tag token whose tag name is one of: "marquee", "object" */
1881 case 'marquee': case 'object':
1882 /* Reconstruct the active formatting elements, if any. */
1884
1885 /* Insert an HTML element for the token. */
1886 $this->insertElement($token);
1887
1888 /* Insert a marker at the end of the list of active
1889 formatting elements. */
1890 $this->a_formatting[] = self::MARKER;
1891 break;
1892
1893 /* A start tag token whose tag name is "xmp" */
1894 case 'xmp':
1895 /* Reconstruct the active formatting elements, if any. */
1897
1898 /* Insert an HTML element for the token. */
1899 $this->insertElement($token);
1900
1901 /* Switch the content model flag to the CDATA state. */
1902 return HTML5::CDATA;
1903 break;
1904
1905 /* A start tag whose tag name is "table" */
1906 case 'table':
1907 /* If the stack of open elements has a p element in scope,
1908 then act as if an end tag with the tag name p had been seen. */
1909 if($this->elementInScope('p')) {
1910 $this->emitToken(array(
1911 'name' => 'p',
1912 'type' => HTML5::ENDTAG
1913 ));
1914 }
1915
1916 /* Insert an HTML element for the token. */
1917 $this->insertElement($token);
1918
1919 /* Change the insertion mode to "in table". */
1920 $this->mode = self::IN_TABLE;
1921 break;
1922
1923 /* A start tag whose tag name is one of: "area", "basefont",
1924 "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
1925 case 'area': case 'basefont': case 'bgsound': case 'br':
1926 case 'embed': case 'img': case 'param': case 'spacer':
1927 case 'wbr':
1928 /* Reconstruct the active formatting elements, if any. */
1930
1931 /* Insert an HTML element for the token. */
1932 $this->insertElement($token);
1933
1934 /* Immediately pop the current node off the stack of open elements. */
1935 array_pop($this->stack);
1936 break;
1937
1938 /* A start tag whose tag name is "hr" */
1939 case 'hr':
1940 /* If the stack of open elements has a p element in scope,
1941 then act as if an end tag with the tag name p had been seen. */
1942 if($this->elementInScope('p')) {
1943 $this->emitToken(array(
1944 'name' => 'p',
1945 'type' => HTML5::ENDTAG
1946 ));
1947 }
1948
1949 /* Insert an HTML element for the token. */
1950 $this->insertElement($token);
1951
1952 /* Immediately pop the current node off the stack of open elements. */
1953 array_pop($this->stack);
1954 break;
1955
1956 /* A start tag whose tag name is "image" */
1957 case 'image':
1958 /* Parse error. Change the token's tag name to "img" and
1959 reprocess it. (Don't ask.) */
1960 $token['name'] = 'img';
1961 return $this->inBody($token);
1962 break;
1963
1964 /* A start tag whose tag name is "input" */
1965 case 'input':
1966 /* Reconstruct the active formatting elements, if any. */
1968
1969 /* Insert an input element for the token. */
1970 $element = $this->insertElement($token, false);
1971
1972 /* If the form element pointer is not null, then associate the
1973 input element with the form element pointed to by the form
1974 element pointer. */
1975 $this->form_pointer !== null
1976 ? $this->form_pointer->appendChild($element)
1977 : end($this->stack)->appendChild($element);
1978
1979 /* Pop that input element off the stack of open elements. */
1980 array_pop($this->stack);
1981 break;
1982
1983 /* A start tag whose tag name is "isindex" */
1984 case 'isindex':
1985 /* Parse error. */
1986 // w/e
1987
1988 /* If the form element pointer is not null,
1989 then ignore the token. */
1990 if($this->form_pointer === null) {
1991 /* Act as if a start tag token with the tag name "form" had
1992 been seen. */
1993 $this->inBody(array(
1994 'name' => 'body',
1995 'type' => HTML5::STARTTAG,
1996 'attr' => array()
1997 ));
1998
1999 /* Act as if a start tag token with the tag name "hr" had
2000 been seen. */
2001 $this->inBody(array(
2002 'name' => 'hr',
2003 'type' => HTML5::STARTTAG,
2004 'attr' => array()
2005 ));
2006
2007 /* Act as if a start tag token with the tag name "p" had
2008 been seen. */
2009 $this->inBody(array(
2010 'name' => 'p',
2011 'type' => HTML5::STARTTAG,
2012 'attr' => array()
2013 ));
2014
2015 /* Act as if a start tag token with the tag name "label"
2016 had been seen. */
2017 $this->inBody(array(
2018 'name' => 'label',
2019 'type' => HTML5::STARTTAG,
2020 'attr' => array()
2021 ));
2022
2023 /* Act as if a stream of character tokens had been seen. */
2024 $this->insertText('This is a searchable index. '.
2025 'Insert your search keywords here: ');
2026
2027 /* Act as if a start tag token with the tag name "input"
2028 had been seen, with all the attributes from the "isindex"
2029 token, except with the "name" attribute set to the value
2030 "isindex" (ignoring any explicit "name" attribute). */
2031 $attr = $token['attr'];
2032 $attr[] = array('name' => 'name', 'value' => 'isindex');
2033
2034 $this->inBody(array(
2035 'name' => 'input',
2036 'type' => HTML5::STARTTAG,
2037 'attr' => $attr
2038 ));
2039
2040 /* Act as if a stream of character tokens had been seen
2041 (see below for what they should say). */
2042 $this->insertText('This is a searchable index. '.
2043 'Insert your search keywords here: ');
2044
2045 /* Act as if an end tag token with the tag name "label"
2046 had been seen. */
2047 $this->inBody(array(
2048 'name' => 'label',
2049 'type' => HTML5::ENDTAG
2050 ));
2051
2052 /* Act as if an end tag token with the tag name "p" had
2053 been seen. */
2054 $this->inBody(array(
2055 'name' => 'p',
2056 'type' => HTML5::ENDTAG
2057 ));
2058
2059 /* Act as if a start tag token with the tag name "hr" had
2060 been seen. */
2061 $this->inBody(array(
2062 'name' => 'hr',
2063 'type' => HTML5::ENDTAG
2064 ));
2065
2066 /* Act as if an end tag token with the tag name "form" had
2067 been seen. */
2068 $this->inBody(array(
2069 'name' => 'form',
2070 'type' => HTML5::ENDTAG
2071 ));
2072 }
2073 break;
2074
2075 /* A start tag whose tag name is "textarea" */
2076 case 'textarea':
2077 $this->insertElement($token);
2078
2079 /* Switch the tokeniser's content model flag to the
2080 RCDATA state. */
2081 return HTML5::RCDATA;
2082 break;
2083
2084 /* A start tag whose tag name is one of: "iframe", "noembed",
2085 "noframes" */
2086 case 'iframe': case 'noembed': case 'noframes':
2087 $this->insertElement($token);
2088
2089 /* Switch the tokeniser's content model flag to the CDATA state. */
2090 return HTML5::CDATA;
2091 break;
2092
2093 /* A start tag whose tag name is "select" */
2094 case 'select':
2095 /* Reconstruct the active formatting elements, if any. */
2097
2098 /* Insert an HTML element for the token. */
2099 $this->insertElement($token);
2100
2101 /* Change the insertion mode to "in select". */
2102 $this->mode = self::IN_SELECT;
2103 break;
2104
2105 /* A start or end tag whose tag name is one of: "caption", "col",
2106 "colgroup", "frame", "frameset", "head", "option", "optgroup",
2107 "tbody", "td", "tfoot", "th", "thead", "tr". */
2108 case 'caption': case 'col': case 'colgroup': case 'frame':
2109 case 'frameset': case 'head': case 'option': case 'optgroup':
2110 case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead':
2111 case 'tr':
2112 // Parse error. Ignore the token.
2113 break;
2114
2115 /* A start or end tag whose tag name is one of: "event-source",
2116 "section", "nav", "article", "aside", "header", "footer",
2117 "datagrid", "command" */
2118 case 'event-source': case 'section': case 'nav': case 'article':
2119 case 'aside': case 'header': case 'footer': case 'datagrid':
2120 case 'command':
2121 // Work in progress!
2122 break;
2123
2124 /* A start tag token not covered by the previous entries */
2125 default:
2126 /* Reconstruct the active formatting elements, if any. */
2128
2129 $this->insertElement($token);
2130 break;
2131 }
2132 break;
2133
2134 case HTML5::ENDTAG:
2135 switch($token['name']) {
2136 /* An end tag with the tag name "body" */
2137 case 'body':
2138 /* If the second element in the stack of open elements is
2139 not a body element, this is a parse error. Ignore the token.
2140 (innerHTML case) */
2141 if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') {
2142 // Ignore.
2143
2144 /* If the current node is not the body element, then this
2145 is a parse error. */
2146 } elseif(end($this->stack)->nodeName !== 'body') {
2147 // Parse error.
2148 }
2149
2150 /* Change the insertion mode to "after body". */
2151 $this->mode = self::AFTER_BODY;
2152 break;
2153
2154 /* An end tag with the tag name "html" */
2155 case 'html':
2156 /* Act as if an end tag with tag name "body" had been seen,
2157 then, if that token wasn't ignored, reprocess the current
2158 token. */
2159 $this->inBody(array(
2160 'name' => 'body',
2161 'type' => HTML5::ENDTAG
2162 ));
2163
2164 return $this->afterBody($token);
2165 break;
2166
2167 /* An end tag whose tag name is one of: "address", "blockquote",
2168 "center", "dir", "div", "dl", "fieldset", "listing", "menu",
2169 "ol", "pre", "ul" */
2170 case 'address': case 'blockquote': case 'center': case 'dir':
2171 case 'div': case 'dl': case 'fieldset': case 'listing':
2172 case 'menu': case 'ol': case 'pre': case 'ul':
2173 /* If the stack of open elements has an element in scope
2174 with the same tag name as that of the token, then generate
2175 implied end tags. */
2176 if($this->elementInScope($token['name'])) {
2177 $this->generateImpliedEndTags();
2178
2179 /* Now, if the current node is not an element with
2180 the same tag name as that of the token, then this
2181 is a parse error. */
2182 // w/e
2183
2184 /* If the stack of open elements has an element in
2185 scope with the same tag name as that of the token,
2186 then pop elements from this stack until an element
2187 with that tag name has been popped from the stack. */
2188 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2189 if($this->stack[$n]->nodeName === $token['name']) {
2190 $n = -1;
2191 }
2192
2193 array_pop($this->stack);
2194 }
2195 }
2196 break;
2197
2198 /* An end tag whose tag name is "form" */
2199 case 'form':
2200 /* If the stack of open elements has an element in scope
2201 with the same tag name as that of the token, then generate
2202 implied end tags. */
2203 if($this->elementInScope($token['name'])) {
2204 $this->generateImpliedEndTags();
2205
2206 }
2207
2208 if(end($this->stack)->nodeName !== $token['name']) {
2209 /* Now, if the current node is not an element with the
2210 same tag name as that of the token, then this is a parse
2211 error. */
2212 // w/e
2213
2214 } else {
2215 /* Otherwise, if the current node is an element with
2216 the same tag name as that of the token pop that element
2217 from the stack. */
2218 array_pop($this->stack);
2219 }
2220
2221 /* In any case, set the form element pointer to null. */
2222 $this->form_pointer = null;
2223 break;
2224
2225 /* An end tag whose tag name is "p" */
2226 case 'p':
2227 /* If the stack of open elements has a p element in scope,
2228 then generate implied end tags, except for p elements. */
2229 if($this->elementInScope('p')) {
2230 $this->generateImpliedEndTags(array('p'));
2231
2232 /* If the current node is not a p element, then this is
2233 a parse error. */
2234 // k
2235
2236 /* If the stack of open elements has a p element in
2237 scope, then pop elements from this stack until the stack
2238 no longer has a p element in scope. */
2239 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2240 if($this->elementInScope('p')) {
2241 array_pop($this->stack);
2242
2243 } else {
2244 break;
2245 }
2246 }
2247 }
2248 break;
2249
2250 /* An end tag whose tag name is "dd", "dt", or "li" */
2251 case 'dd': case 'dt': case 'li':
2252 /* If the stack of open elements has an element in scope
2253 whose tag name matches the tag name of the token, then
2254 generate implied end tags, except for elements with the
2255 same tag name as the token. */
2256 if($this->elementInScope($token['name'])) {
2257 $this->generateImpliedEndTags(array($token['name']));
2258
2259 /* If the current node is not an element with the same
2260 tag name as the token, then this is a parse error. */
2261 // w/e
2262
2263 /* If the stack of open elements has an element in scope
2264 whose tag name matches the tag name of the token, then
2265 pop elements from this stack until an element with that
2266 tag name has been popped from the stack. */
2267 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2268 if($this->stack[$n]->nodeName === $token['name']) {
2269 $n = -1;
2270 }
2271
2272 array_pop($this->stack);
2273 }
2274 }
2275 break;
2276
2277 /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
2278 "h5", "h6" */
2279 case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
2280 $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
2281
2282 /* If the stack of open elements has in scope an element whose
2283 tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
2284 generate implied end tags. */
2285 if($this->elementInScope($elements)) {
2286 $this->generateImpliedEndTags();
2287
2288 /* Now, if the current node is not an element with the same
2289 tag name as that of the token, then this is a parse error. */
2290 // w/e
2291
2292 /* If the stack of open elements has in scope an element
2293 whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
2294 "h6", then pop elements from the stack until an element
2295 with one of those tag names has been popped from the stack. */
2296 while($this->elementInScope($elements)) {
2297 array_pop($this->stack);
2298 }
2299 }
2300 break;
2301
2302 /* An end tag whose tag name is one of: "a", "b", "big", "em",
2303 "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
2304 case 'a': case 'b': case 'big': case 'em': case 'font':
2305 case 'i': case 'nobr': case 's': case 'small': case 'strike':
2306 case 'strong': case 'tt': case 'u':
2307 /* 1. Let the formatting element be the last element in
2308 the list of active formatting elements that:
2309 * is between the end of the list and the last scope
2310 marker in the list, if any, or the start of the list
2311 otherwise, and
2312 * has the same tag name as the token.
2313 */
2314 while(true) {
2315 for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
2316 if($this->a_formatting[$a] === self::MARKER) {
2317 break;
2318
2319 } elseif($this->a_formatting[$a]->tagName === $token['name']) {
2320 $formatting_element = $this->a_formatting[$a];
2321 $in_stack = in_array($formatting_element, $this->stack, true);
2322 $fe_af_pos = $a;
2323 break;
2324 }
2325 }
2326
2327 /* If there is no such node, or, if that node is
2328 also in the stack of open elements but the element
2329 is not in scope, then this is a parse error. Abort
2330 these steps. The token is ignored. */
2331 if(!isset($formatting_element) || ($in_stack &&
2332 !$this->elementInScope($token['name']))) {
2333 break;
2334
2335 /* Otherwise, if there is such a node, but that node
2336 is not in the stack of open elements, then this is a
2337 parse error; remove the element from the list, and
2338 abort these steps. */
2339 } elseif(isset($formatting_element) && !$in_stack) {
2340 unset($this->a_formatting[$fe_af_pos]);
2341 $this->a_formatting = array_merge($this->a_formatting);
2342 break;
2343 }
2344
2345 /* 2. Let the furthest block be the topmost node in the
2346 stack of open elements that is lower in the stack
2347 than the formatting element, and is not an element in
2348 the phrasing or formatting categories. There might
2349 not be one. */
2350 $fe_s_pos = array_search($formatting_element, $this->stack, true);
2351 $length = count($this->stack);
2352
2353 for($s = $fe_s_pos + 1; $s < $length; $s++) {
2354 $category = $this->getElementCategory($this->stack[$s]->nodeName);
2355
2356 if($category !== self::PHRASING && $category !== self::FORMATTING) {
2357 $furthest_block = $this->stack[$s];
2358 }
2359 }
2360
2361 /* 3. If there is no furthest block, then the UA must
2362 skip the subsequent steps and instead just pop all
2363 the nodes from the bottom of the stack of open
2364 elements, from the current node up to the formatting
2365 element, and remove the formatting element from the
2366 list of active formatting elements. */
2367 if(!isset($furthest_block)) {
2368 for($n = $length - 1; $n >= $fe_s_pos; $n--) {
2369 array_pop($this->stack);
2370 }
2371
2372 unset($this->a_formatting[$fe_af_pos]);
2373 $this->a_formatting = array_merge($this->a_formatting);
2374 break;
2375 }
2376
2377 /* 4. Let the common ancestor be the element
2378 immediately above the formatting element in the stack
2379 of open elements. */
2380 $common_ancestor = $this->stack[$fe_s_pos - 1];
2381
2382 /* 5. If the furthest block has a parent node, then
2383 remove the furthest block from its parent node. */
2384 if($furthest_block->parentNode !== null) {
2385 $furthest_block->parentNode->removeChild($furthest_block);
2386 }
2387
2388 /* 6. Let a bookmark note the position of the
2389 formatting element in the list of active formatting
2390 elements relative to the elements on either side
2391 of it in the list. */
2392 $bookmark = $fe_af_pos;
2393
2394 /* 7. Let node and last node be the furthest block.
2395 Follow these steps: */
2396 $node = $furthest_block;
2397 $last_node = $furthest_block;
2398
2399 while(true) {
2400 for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
2401 /* 7.1 Let node be the element immediately
2402 prior to node in the stack of open elements. */
2403 $node = $this->stack[$n];
2404
2405 /* 7.2 If node is not in the list of active
2406 formatting elements, then remove node from
2407 the stack of open elements and then go back
2408 to step 1. */
2409 if(!in_array($node, $this->a_formatting, true)) {
2410 unset($this->stack[$n]);
2411 $this->stack = array_merge($this->stack);
2412
2413 } else {
2414 break;
2415 }
2416 }
2417
2418 /* 7.3 Otherwise, if node is the formatting
2419 element, then go to the next step in the overall
2420 algorithm. */
2421 if($node === $formatting_element) {
2422 break;
2423
2424 /* 7.4 Otherwise, if last node is the furthest
2425 block, then move the aforementioned bookmark to
2426 be immediately after the node in the list of
2427 active formatting elements. */
2428 } elseif($last_node === $furthest_block) {
2429 $bookmark = array_search($node, $this->a_formatting, true) + 1;
2430 }
2431
2432 /* 7.5 If node has any children, perform a
2433 shallow clone of node, replace the entry for
2434 node in the list of active formatting elements
2435 with an entry for the clone, replace the entry
2436 for node in the stack of open elements with an
2437 entry for the clone, and let node be the clone. */
2438 if($node->hasChildNodes()) {
2439 $clone = $node->cloneNode();
2440 $s_pos = array_search($node, $this->stack, true);
2441 $a_pos = array_search($node, $this->a_formatting, true);
2442
2443 $this->stack[$s_pos] = $clone;
2444 $this->a_formatting[$a_pos] = $clone;
2445 $node = $clone;
2446 }
2447
2448 /* 7.6 Insert last node into node, first removing
2449 it from its previous parent node if any. */
2450 if($last_node->parentNode !== null) {
2451 $last_node->parentNode->removeChild($last_node);
2452 }
2453
2454 $node->appendChild($last_node);
2455
2456 /* 7.7 Let last node be node. */
2457 $last_node = $node;
2458 }
2459
2460 /* 8. Insert whatever last node ended up being in
2461 the previous step into the common ancestor node,
2462 first removing it from its previous parent node if
2463 any. */
2464 if($last_node->parentNode !== null) {
2465 $last_node->parentNode->removeChild($last_node);
2466 }
2467
2468 $common_ancestor->appendChild($last_node);
2469
2470 /* 9. Perform a shallow clone of the formatting
2471 element. */
2472 $clone = $formatting_element->cloneNode();
2473
2474 /* 10. Take all of the child nodes of the furthest
2475 block and append them to the clone created in the
2476 last step. */
2477 while($furthest_block->hasChildNodes()) {
2478 $child = $furthest_block->firstChild;
2479 $furthest_block->removeChild($child);
2480 $clone->appendChild($child);
2481 }
2482
2483 /* 11. Append that clone to the furthest block. */
2484 $furthest_block->appendChild($clone);
2485
2486 /* 12. Remove the formatting element from the list
2487 of active formatting elements, and insert the clone
2488 into the list of active formatting elements at the
2489 position of the aforementioned bookmark. */
2490 $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
2491 unset($this->a_formatting[$fe_af_pos]);
2492 $this->a_formatting = array_merge($this->a_formatting);
2493
2494 $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
2495 $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
2496 $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
2497
2498 /* 13. Remove the formatting element from the stack
2499 of open elements, and insert the clone into the stack
2500 of open elements immediately after (i.e. in a more
2501 deeply nested position than) the position of the
2502 furthest block in that stack. */
2503 $fe_s_pos = array_search($formatting_element, $this->stack, true);
2504 $fb_s_pos = array_search($furthest_block, $this->stack, true);
2505 unset($this->stack[$fe_s_pos]);
2506
2507 $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
2508 $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
2509 $this->stack = array_merge($s_part1, array($clone), $s_part2);
2510
2511 /* 14. Jump back to step 1 in this series of steps. */
2512 unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
2513 }
2514 break;
2515
2516 /* An end tag token whose tag name is one of: "button",
2517 "marquee", "object" */
2518 case 'button': case 'marquee': case 'object':
2519 /* If the stack of open elements has an element in scope whose
2520 tag name matches the tag name of the token, then generate implied
2521 tags. */
2522 if($this->elementInScope($token['name'])) {
2523 $this->generateImpliedEndTags();
2524
2525 /* Now, if the current node is not an element with the same
2526 tag name as the token, then this is a parse error. */
2527 // k
2528
2529 /* Now, if the stack of open elements has an element in scope
2530 whose tag name matches the tag name of the token, then pop
2531 elements from the stack until that element has been popped from
2532 the stack, and clear the list of active formatting elements up
2533 to the last marker. */
2534 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2535 if($this->stack[$n]->nodeName === $token['name']) {
2536 $n = -1;
2537 }
2538
2539 array_pop($this->stack);
2540 }
2541
2542 $marker = end(array_keys($this->a_formatting, self::MARKER, true));
2543
2544 for($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
2545 array_pop($this->a_formatting);
2546 }
2547 }
2548 break;
2549
2550 /* Or an end tag whose tag name is one of: "area", "basefont",
2551 "bgsound", "br", "embed", "hr", "iframe", "image", "img",
2552 "input", "isindex", "noembed", "noframes", "param", "select",
2553 "spacer", "table", "textarea", "wbr" */
2554 case 'area': case 'basefont': case 'bgsound': case 'br':
2555 case 'embed': case 'hr': case 'iframe': case 'image':
2556 case 'img': case 'input': case 'isindex': case 'noembed':
2557 case 'noframes': case 'param': case 'select': case 'spacer':
2558 case 'table': case 'textarea': case 'wbr':
2559 // Parse error. Ignore the token.
2560 break;
2561
2562 /* An end tag token not covered by the previous entries */
2563 default:
2564 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2565 /* Initialise node to be the current node (the bottommost
2566 node of the stack). */
2567 $node = end($this->stack);
2568
2569 /* If node has the same tag name as the end tag token,
2570 then: */
2571 if($token['name'] === $node->nodeName) {
2572 /* Generate implied end tags. */
2573 $this->generateImpliedEndTags();
2574
2575 /* If the tag name of the end tag token does not
2576 match the tag name of the current node, this is a
2577 parse error. */
2578 // k
2579
2580 /* Pop all the nodes from the current node up to
2581 node, including node, then stop this algorithm. */
2582 for($x = count($this->stack) - $n; $x >= $n; $x--) {
2583 array_pop($this->stack);
2584 }
2585
2586 } else {
2587 $category = $this->getElementCategory($node);
2588
2589 if($category !== self::SPECIAL && $category !== self::SCOPING) {
2590 /* Otherwise, if node is in neither the formatting
2591 category nor the phrasing category, then this is a
2592 parse error. Stop this algorithm. The end tag token
2593 is ignored. */
2594 return false;
2595 }
2596 }
2597 }
2598 break;
2599 }
2600 break;
2601 }
2602 }

References $n, $s, $x, AFTER_BODY, afterBody(), HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, elementInScope(), emitToken(), HTML5\ENDTAG, generateImpliedEndTags(), getElementCategory(), IN_SELECT, IN_TABLE, inBody(), inHead(), insertComment(), insertElement(), insertText(), MARKER, HTML5\PLAINTEXT, HTML5\RCDATA, reconstructActiveFormattingElements(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inCaption() [1/2]

HTML5TreeConstructer::inCaption (   $token)
private

Definition at line 3528 of file PH5P.php.

3529 {
3530 /* An end tag whose tag name is "caption" */
3531 if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') {
3532 /* If the stack of open elements does not have an element in table
3533 scope with the same tag name as the token, this is a parse error.
3534 Ignore the token. (innerHTML case) */
3535 if (!$this->elementInScope($token['name'], true)) {
3536 // Ignore
3537
3538 /* Otherwise: */
3539 } else {
3540 /* Generate implied end tags. */
3541 $this->generateImpliedEndTags();
3542
3543 /* Now, if the current node is not a caption element, then this
3544 is a parse error. */
3545 // w/e
3546
3547 /* Pop elements from this stack until a caption element has
3548 been popped from the stack. */
3549 while (true) {
3550 $node = end($this->stack)->nodeName;
3551 array_pop($this->stack);
3552
3553 if ($node === 'caption') {
3554 break;
3555 }
3556 }
3557
3558 /* Clear the list of active formatting elements up to the last
3559 marker. */
3561
3562 /* Switch the insertion mode to "in table". */
3563 $this->mode = self::IN_TABLE;
3564 }
3565
3566 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3567 "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
3568 name is "table" */
3569 } elseif (($token['type'] === HTML5::STARTTAG && in_array(
3570 $token['name'],
3571 array(
3572 'caption',
3573 'col',
3574 'colgroup',
3575 'tbody',
3576 'td',
3577 'tfoot',
3578 'th',
3579 'thead',
3580 'tr'
3581 )
3582 )) || ($token['type'] === HTML5::ENDTAG &&
3583 $token['name'] === 'table')
3584 ) {
3585 /* Parse error. Act as if an end tag with the tag name "caption"
3586 had been seen, then, if that token wasn't ignored, reprocess the
3587 current token. */
3588 $this->inCaption(
3589 array(
3590 'name' => 'caption',
3591 'type' => HTML5::ENDTAG
3592 )
3593 );
3594
3595 return $this->inTable($token);
3596
3597 /* An end tag whose tag name is one of: "body", "col", "colgroup",
3598 "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
3599 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3600 $token['name'],
3601 array(
3602 'body',
3603 'col',
3604 'colgroup',
3605 'html',
3606 'tbody',
3607 'tfoot',
3608 'th',
3609 'thead',
3610 'tr'
3611 )
3612 )
3613 ) {
3614 // Parse error. Ignore the token.
3615
3616 /* Anything else */
3617 } else {
3618 /* Process the token as if the insertion mode was "in body". */
3619 $this->inBody($token);
3620 }
3621 }
inCaption($token)
Definition: PH5P.php:3528
clearTheActiveFormattingElementsUpToTheLastMarker()
Definition: PH5P.php:4598

References clearTheActiveFormattingElementsUpToTheLastMarker(), elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_TABLE, inBody(), inCaption(), inTable(), and HTML5\STARTTAG.

Referenced by inCaption(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inCaption() [2/2]

HTML5TreeConstructer::inCaption (   $token)
private

Definition at line 2782 of file PH5P.php.

2783 {
2784 /* An end tag whose tag name is "caption" */
2785 if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') {
2786 /* If the stack of open elements does not have an element in table
2787 scope with the same tag name as the token, this is a parse error.
2788 Ignore the token. (innerHTML case) */
2789 if(!$this->elementInScope($token['name'], true)) {
2790 // Ignore
2791
2792 /* Otherwise: */
2793 } else {
2794 /* Generate implied end tags. */
2795 $this->generateImpliedEndTags();
2796
2797 /* Now, if the current node is not a caption element, then this
2798 is a parse error. */
2799 // w/e
2800
2801 /* Pop elements from this stack until a caption element has
2802 been popped from the stack. */
2803 while(true) {
2804 $node = end($this->stack)->nodeName;
2805 array_pop($this->stack);
2806
2807 if($node === 'caption') {
2808 break;
2809 }
2810 }
2811
2812 /* Clear the list of active formatting elements up to the last
2813 marker. */
2815
2816 /* Switch the insertion mode to "in table". */
2817 $this->mode = self::IN_TABLE;
2818 }
2819
2820 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2821 "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
2822 name is "table" */
2823 } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2824 array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
2825 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG &&
2826 $token['name'] === 'table')) {
2827 /* Parse error. Act as if an end tag with the tag name "caption"
2828 had been seen, then, if that token wasn't ignored, reprocess the
2829 current token. */
2830 $this->inCaption(array(
2831 'name' => 'caption',
2832 'type' => HTML5::ENDTAG
2833 ));
2834
2835 return $this->inTable($token);
2836
2837 /* An end tag whose tag name is one of: "body", "col", "colgroup",
2838 "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2839 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
2840 array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
2841 'thead', 'tr'))) {
2842 // Parse error. Ignore the token.
2843
2844 /* Anything else */
2845 } else {
2846 /* Process the token as if the insertion mode was "in body". */
2847 $this->inBody($token);
2848 }
2849 }

References clearTheActiveFormattingElementsUpToTheLastMarker(), elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_TABLE, inBody(), inCaption(), inTable(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inCell() [1/2]

HTML5TreeConstructer::inCell (   $token)
private

Definition at line 3882 of file PH5P.php.

3883 {
3884 /* An end tag whose tag name is one of: "td", "th" */
3885 if ($token['type'] === HTML5::ENDTAG &&
3886 ($token['name'] === 'td' || $token['name'] === 'th')
3887 ) {
3888 /* If the stack of open elements does not have an element in table
3889 scope with the same tag name as that of the token, then this is a
3890 parse error and the token must be ignored. */
3891 if (!$this->elementInScope($token['name'], true)) {
3892 // Ignore.
3893
3894 /* Otherwise: */
3895 } else {
3896 /* Generate implied end tags, except for elements with the same
3897 tag name as the token. */
3898 $this->generateImpliedEndTags(array($token['name']));
3899
3900 /* Now, if the current node is not an element with the same tag
3901 name as the token, then this is a parse error. */
3902 // k
3903
3904 /* Pop elements from this stack until an element with the same
3905 tag name as the token has been popped from the stack. */
3906 while (true) {
3907 $node = end($this->stack)->nodeName;
3908 array_pop($this->stack);
3909
3910 if ($node === $token['name']) {
3911 break;
3912 }
3913 }
3914
3915 /* Clear the list of active formatting elements up to the last
3916 marker. */
3918
3919 /* Switch the insertion mode to "in row". (The current node
3920 will be a tr element at this point.) */
3921 $this->mode = self::IN_ROW;
3922 }
3923
3924 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3925 "tbody", "td", "tfoot", "th", "thead", "tr" */
3926 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
3927 $token['name'],
3928 array(
3929 'caption',
3930 'col',
3931 'colgroup',
3932 'tbody',
3933 'td',
3934 'tfoot',
3935 'th',
3936 'thead',
3937 'tr'
3938 )
3939 )
3940 ) {
3941 /* If the stack of open elements does not have a td or th element
3942 in table scope, then this is a parse error; ignore the token.
3943 (innerHTML case) */
3944 if (!$this->elementInScope(array('td', 'th'), true)) {
3945 // Ignore.
3946
3947 /* Otherwise, close the cell (see below) and reprocess the current
3948 token. */
3949 } else {
3950 $this->closeCell();
3951 return $this->inRow($token);
3952 }
3953
3954 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3955 "tbody", "td", "tfoot", "th", "thead", "tr" */
3956 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
3957 $token['name'],
3958 array(
3959 'caption',
3960 'col',
3961 'colgroup',
3962 'tbody',
3963 'td',
3964 'tfoot',
3965 'th',
3966 'thead',
3967 'tr'
3968 )
3969 )
3970 ) {
3971 /* If the stack of open elements does not have a td or th element
3972 in table scope, then this is a parse error; ignore the token.
3973 (innerHTML case) */
3974 if (!$this->elementInScope(array('td', 'th'), true)) {
3975 // Ignore.
3976
3977 /* Otherwise, close the cell (see below) and reprocess the current
3978 token. */
3979 } else {
3980 $this->closeCell();
3981 return $this->inRow($token);
3982 }
3983
3984 /* An end tag whose tag name is one of: "body", "caption", "col",
3985 "colgroup", "html" */
3986 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3987 $token['name'],
3988 array('body', 'caption', 'col', 'colgroup', 'html')
3989 )
3990 ) {
3991 /* Parse error. Ignore the token. */
3992
3993 /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
3994 "thead", "tr" */
3995 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3996 $token['name'],
3997 array('table', 'tbody', 'tfoot', 'thead', 'tr')
3998 )
3999 ) {
4000 /* If the stack of open elements does not have an element in table
4001 scope with the same tag name as that of the token (which can only
4002 happen for "tbody", "tfoot" and "thead", or, in the innerHTML case),
4003 then this is a parse error and the token must be ignored. */
4004 if (!$this->elementInScope($token['name'], true)) {
4005 // Ignore.
4006
4007 /* Otherwise, close the cell (see below) and reprocess the current
4008 token. */
4009 } else {
4010 $this->closeCell();
4011 return $this->inRow($token);
4012 }
4013
4014 /* Anything else */
4015 } else {
4016 /* Process the token as if the insertion mode was "in body". */
4017 $this->inBody($token);
4018 }
4019 }

References clearTheActiveFormattingElementsUpToTheLastMarker(), closeCell(), elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_ROW, inBody(), inRow(), and HTML5\STARTTAG.

Referenced by closeCell(), inRow(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inCell() [2/2]

HTML5TreeConstructer::inCell (   $token)
private

Definition at line 3082 of file PH5P.php.

3083 {
3084 /* An end tag whose tag name is one of: "td", "th" */
3085 if($token['type'] === HTML5::ENDTAG &&
3086 ($token['name'] === 'td' || $token['name'] === 'th')) {
3087 /* If the stack of open elements does not have an element in table
3088 scope with the same tag name as that of the token, then this is a
3089 parse error and the token must be ignored. */
3090 if(!$this->elementInScope($token['name'], true)) {
3091 // Ignore.
3092
3093 /* Otherwise: */
3094 } else {
3095 /* Generate implied end tags, except for elements with the same
3096 tag name as the token. */
3097 $this->generateImpliedEndTags(array($token['name']));
3098
3099 /* Now, if the current node is not an element with the same tag
3100 name as the token, then this is a parse error. */
3101 // k
3102
3103 /* Pop elements from this stack until an element with the same
3104 tag name as the token has been popped from the stack. */
3105 while(true) {
3106 $node = end($this->stack)->nodeName;
3107 array_pop($this->stack);
3108
3109 if($node === $token['name']) {
3110 break;
3111 }
3112 }
3113
3114 /* Clear the list of active formatting elements up to the last
3115 marker. */
3117
3118 /* Switch the insertion mode to "in row". (The current node
3119 will be a tr element at this point.) */
3120 $this->mode = self::IN_ROW;
3121 }
3122
3123 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3124 "tbody", "td", "tfoot", "th", "thead", "tr" */
3125 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3126 array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
3127 'thead', 'tr'))) {
3128 /* If the stack of open elements does not have a td or th element
3129 in table scope, then this is a parse error; ignore the token.
3130 (innerHTML case) */
3131 if(!$this->elementInScope(array('td', 'th'), true)) {
3132 // Ignore.
3133
3134 /* Otherwise, close the cell (see below) and reprocess the current
3135 token. */
3136 } else {
3137 $this->closeCell();
3138 return $this->inRow($token);
3139 }
3140
3141 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3142 "tbody", "td", "tfoot", "th", "thead", "tr" */
3143 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3144 array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
3145 'thead', 'tr'))) {
3146 /* If the stack of open elements does not have a td or th element
3147 in table scope, then this is a parse error; ignore the token.
3148 (innerHTML case) */
3149 if(!$this->elementInScope(array('td', 'th'), true)) {
3150 // Ignore.
3151
3152 /* Otherwise, close the cell (see below) and reprocess the current
3153 token. */
3154 } else {
3155 $this->closeCell();
3156 return $this->inRow($token);
3157 }
3158
3159 /* An end tag whose tag name is one of: "body", "caption", "col",
3160 "colgroup", "html" */
3161 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3162 array('body', 'caption', 'col', 'colgroup', 'html'))) {
3163 /* Parse error. Ignore the token. */
3164
3165 /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
3166 "thead", "tr" */
3167 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3168 array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
3169 /* If the stack of open elements does not have an element in table
3170 scope with the same tag name as that of the token (which can only
3171 happen for "tbody", "tfoot" and "thead", or, in the innerHTML case),
3172 then this is a parse error and the token must be ignored. */
3173 if(!$this->elementInScope($token['name'], true)) {
3174 // Ignore.
3175
3176 /* Otherwise, close the cell (see below) and reprocess the current
3177 token. */
3178 } else {
3179 $this->closeCell();
3180 return $this->inRow($token);
3181 }
3182
3183 /* Anything else */
3184 } else {
3185 /* Process the token as if the insertion mode was "in body". */
3186 $this->inBody($token);
3187 }
3188 }

References clearTheActiveFormattingElementsUpToTheLastMarker(), closeCell(), elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_ROW, inBody(), inRow(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inColumnGroup() [1/2]

HTML5TreeConstructer::inColumnGroup (   $token)
private

Definition at line 3623 of file PH5P.php.

3624 {
3625 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3626 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3627 or U+0020 SPACE */
3628 if ($token['type'] === HTML5::CHARACTR &&
3629 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
3630 ) {
3631 /* Append the character to the current node. */
3632 $text = $this->dom->createTextNode($token['data']);
3633 end($this->stack)->appendChild($text);
3634
3635 /* A comment token */
3636 } elseif ($token['type'] === HTML5::COMMENT) {
3637 /* Append a Comment node to the current node with the data
3638 attribute set to the data given in the comment token. */
3639 $comment = $this->dom->createComment($token['data']);
3640 end($this->stack)->appendChild($comment);
3641
3642 /* A start tag whose tag name is "col" */
3643 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') {
3644 /* Insert a col element for the token. Immediately pop the current
3645 node off the stack of open elements. */
3646 $this->insertElement($token);
3647 array_pop($this->stack);
3648
3649 /* An end tag whose tag name is "colgroup" */
3650 } elseif ($token['type'] === HTML5::ENDTAG &&
3651 $token['name'] === 'colgroup'
3652 ) {
3653 /* If the current node is the root html element, then this is a
3654 parse error, ignore the token. (innerHTML case) */
3655 if (end($this->stack)->nodeName === 'html') {
3656 // Ignore
3657
3658 /* Otherwise, pop the current node (which will be a colgroup
3659 element) from the stack of open elements. Switch the insertion
3660 mode to "in table". */
3661 } else {
3662 array_pop($this->stack);
3663 $this->mode = self::IN_TABLE;
3664 }
3665
3666 /* An end tag whose tag name is "col" */
3667 } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') {
3668 /* Parse error. Ignore the token. */
3669
3670 /* Anything else */
3671 } else {
3672 /* Act as if an end tag with the tag name "colgroup" had been seen,
3673 and then, if that token wasn't ignored, reprocess the current token. */
3674 $this->inColumnGroup(
3675 array(
3676 'name' => 'colgroup',
3677 'type' => HTML5::ENDTAG
3678 )
3679 );
3680
3681 return $this->inTable($token);
3682 }
3683 }
inColumnGroup($token)
Definition: PH5P.php:3623
$text
Definition: errorreport.php:18

References $comment, $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, IN_TABLE, inColumnGroup(), insertElement(), inTable(), and HTML5\STARTTAG.

Referenced by inColumnGroup(), inTable(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inColumnGroup() [2/2]

HTML5TreeConstructer::inColumnGroup (   $token)
private

Definition at line 2851 of file PH5P.php.

2852 {
2853 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2854 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2855 or U+0020 SPACE */
2856 if($token['type'] === HTML5::CHARACTR &&
2857 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
2858 /* Append the character to the current node. */
2859 $text = $this->dom->createTextNode($token['data']);
2860 end($this->stack)->appendChild($text);
2861
2862 /* A comment token */
2863 } elseif($token['type'] === HTML5::COMMENT) {
2864 /* Append a Comment node to the current node with the data
2865 attribute set to the data given in the comment token. */
2866 $comment = $this->dom->createComment($token['data']);
2867 end($this->stack)->appendChild($comment);
2868
2869 /* A start tag whose tag name is "col" */
2870 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') {
2871 /* Insert a col element for the token. Immediately pop the current
2872 node off the stack of open elements. */
2873 $this->insertElement($token);
2874 array_pop($this->stack);
2875
2876 /* An end tag whose tag name is "colgroup" */
2877 } elseif($token['type'] === HTML5::ENDTAG &&
2878 $token['name'] === 'colgroup') {
2879 /* If the current node is the root html element, then this is a
2880 parse error, ignore the token. (innerHTML case) */
2881 if(end($this->stack)->nodeName === 'html') {
2882 // Ignore
2883
2884 /* Otherwise, pop the current node (which will be a colgroup
2885 element) from the stack of open elements. Switch the insertion
2886 mode to "in table". */
2887 } else {
2888 array_pop($this->stack);
2889 $this->mode = self::IN_TABLE;
2890 }
2891
2892 /* An end tag whose tag name is "col" */
2893 } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') {
2894 /* Parse error. Ignore the token. */
2895
2896 /* Anything else */
2897 } else {
2898 /* Act as if an end tag with the tag name "colgroup" had been seen,
2899 and then, if that token wasn't ignored, reprocess the current token. */
2900 $this->inColumnGroup(array(
2901 'name' => 'colgroup',
2902 'type' => HTML5::ENDTAG
2903 ));
2904
2905 return $this->inTable($token);
2906 }
2907 }

References $comment, $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, IN_TABLE, inColumnGroup(), insertElement(), inTable(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inFrameset() [1/2]

HTML5TreeConstructer::inFrameset (   $token)
private

Definition at line 4243 of file PH5P.php.

4244 {
4245 /* Handle the token as follows: */
4246
4247 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
4248 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
4249 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
4250 if ($token['type'] === HTML5::CHARACTR &&
4251 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
4252 ) {
4253 /* Append the character to the current node. */
4254 $this->insertText($token['data']);
4255
4256 /* A comment token */
4257 } elseif ($token['type'] === HTML5::COMMENT) {
4258 /* Append a Comment node to the current node with the data
4259 attribute set to the data given in the comment token. */
4260 $this->insertComment($token['data']);
4261
4262 /* A start tag with the tag name "frameset" */
4263 } elseif ($token['name'] === 'frameset' &&
4264 $token['type'] === HTML5::STARTTAG
4265 ) {
4266 $this->insertElement($token);
4267
4268 /* An end tag with the tag name "frameset" */
4269 } elseif ($token['name'] === 'frameset' &&
4270 $token['type'] === HTML5::ENDTAG
4271 ) {
4272 /* If the current node is the root html element, then this is a
4273 parse error; ignore the token. (innerHTML case) */
4274 if (end($this->stack)->nodeName === 'html') {
4275 // Ignore
4276
4277 } else {
4278 /* Otherwise, pop the current node from the stack of open
4279 elements. */
4280 array_pop($this->stack);
4281
4282 /* If the parser was not originally created in order to handle
4283 the setting of an element's innerHTML attribute (innerHTML case),
4284 and the current node is no longer a frameset element, then change
4285 the insertion mode to "after frameset". */
4286 $this->mode = self::AFTR_FRAME;
4287 }
4288
4289 /* A start tag with the tag name "frame" */
4290 } elseif ($token['name'] === 'frame' &&
4291 $token['type'] === HTML5::STARTTAG
4292 ) {
4293 /* Insert an HTML element for the token. */
4294 $this->insertElement($token);
4295
4296 /* Immediately pop the current node off the stack of open elements. */
4297 array_pop($this->stack);
4298
4299 /* A start tag with the tag name "noframes" */
4300 } elseif ($token['name'] === 'noframes' &&
4301 $token['type'] === HTML5::STARTTAG
4302 ) {
4303 /* Process the token as if the insertion mode had been "in body". */
4304 $this->inBody($token);
4305
4306 /* Anything else */
4307 } else {
4308 /* Parse error. Ignore the token. */
4309 }
4310 }

References AFTR_FRAME, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, inBody(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

Referenced by mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inFrameset() [2/2]

HTML5TreeConstructer::inFrameset (   $token)
private

Definition at line 3380 of file PH5P.php.

3381 {
3382 /* Handle the token as follows: */
3383
3384 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3385 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3386 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3387 if($token['type'] === HTML5::CHARACTR &&
3388 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3389 /* Append the character to the current node. */
3390 $this->insertText($token['data']);
3391
3392 /* A comment token */
3393 } elseif($token['type'] === HTML5::COMMENT) {
3394 /* Append a Comment node to the current node with the data
3395 attribute set to the data given in the comment token. */
3396 $this->insertComment($token['data']);
3397
3398 /* A start tag with the tag name "frameset" */
3399 } elseif($token['name'] === 'frameset' &&
3400 $token['type'] === HTML5::STARTTAG) {
3401 $this->insertElement($token);
3402
3403 /* An end tag with the tag name "frameset" */
3404 } elseif($token['name'] === 'frameset' &&
3405 $token['type'] === HTML5::ENDTAG) {
3406 /* If the current node is the root html element, then this is a
3407 parse error; ignore the token. (innerHTML case) */
3408 if(end($this->stack)->nodeName === 'html') {
3409 // Ignore
3410
3411 } else {
3412 /* Otherwise, pop the current node from the stack of open
3413 elements. */
3414 array_pop($this->stack);
3415
3416 /* If the parser was not originally created in order to handle
3417 the setting of an element's innerHTML attribute (innerHTML case),
3418 and the current node is no longer a frameset element, then change
3419 the insertion mode to "after frameset". */
3420 $this->mode = self::AFTR_FRAME;
3421 }
3422
3423 /* A start tag with the tag name "frame" */
3424 } elseif($token['name'] === 'frame' &&
3425 $token['type'] === HTML5::STARTTAG) {
3426 /* Insert an HTML element for the token. */
3427 $this->insertElement($token);
3428
3429 /* Immediately pop the current node off the stack of open elements. */
3430 array_pop($this->stack);
3431
3432 /* A start tag with the tag name "noframes" */
3433 } elseif($token['name'] === 'noframes' &&
3434 $token['type'] === HTML5::STARTTAG) {
3435 /* Process the token as if the insertion mode had been "in body". */
3436 $this->inBody($token);
3437
3438 /* Anything else */
3439 } else {
3440 /* Parse error. Ignore the token. */
3441 }
3442 }

References AFTR_FRAME, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, inBody(), insertComment(), insertElement(), insertText(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inHead() [1/2]

HTML5TreeConstructer::inHead (   $token)
private

Definition at line 1978 of file PH5P.php.

1979 {
1980 /* Handle the token as follows: */
1981
1982 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1983 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1984 or U+0020 SPACE.
1985
1986 THIS DIFFERS FROM THE SPEC: If the current node is either a title, style
1987 or script element, append the character to the current node regardless
1988 of its content. */
1989 if (($token['type'] === HTML5::CHARACTR &&
1990 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || (
1991 $token['type'] === HTML5::CHARACTR && in_array(
1992 end($this->stack)->nodeName,
1993 array('title', 'style', 'script')
1994 ))
1995 ) {
1996 /* Append the character to the current node. */
1997 $this->insertText($token['data']);
1998
1999 /* A comment token */
2000 } elseif ($token['type'] === HTML5::COMMENT) {
2001 /* Append a Comment node to the current node with the data attribute
2002 set to the data given in the comment token. */
2003 $this->insertComment($token['data']);
2004
2005 } elseif ($token['type'] === HTML5::ENDTAG &&
2006 in_array($token['name'], array('title', 'style', 'script'))
2007 ) {
2008 array_pop($this->stack);
2009 return HTML5::PCDATA;
2010
2011 /* A start tag with the tag name "title" */
2012 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') {
2013 /* Create an element for the token and append the new element to the
2014 node pointed to by the head element pointer, or, if that is null
2015 (innerHTML case), to the current node. */
2016 if ($this->head_pointer !== null) {
2017 $element = $this->insertElement($token, false);
2018 $this->head_pointer->appendChild($element);
2019
2020 } else {
2021 $element = $this->insertElement($token);
2022 }
2023
2024 /* Switch the tokeniser's content model flag to the RCDATA state. */
2025 return HTML5::RCDATA;
2026
2027 /* A start tag with the tag name "style" */
2028 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') {
2029 /* Create an element for the token and append the new element to the
2030 node pointed to by the head element pointer, or, if that is null
2031 (innerHTML case), to the current node. */
2032 if ($this->head_pointer !== null) {
2033 $element = $this->insertElement($token, false);
2034 $this->head_pointer->appendChild($element);
2035
2036 } else {
2037 $this->insertElement($token);
2038 }
2039
2040 /* Switch the tokeniser's content model flag to the CDATA state. */
2041 return HTML5::CDATA;
2042
2043 /* A start tag with the tag name "script" */
2044 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') {
2045 /* Create an element for the token. */
2046 $element = $this->insertElement($token, false);
2047 $this->head_pointer->appendChild($element);
2048
2049 /* Switch the tokeniser's content model flag to the CDATA state. */
2050 return HTML5::CDATA;
2051
2052 /* A start tag with the tag name "base", "link", or "meta" */
2053 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
2054 $token['name'],
2055 array('base', 'link', 'meta')
2056 )
2057 ) {
2058 /* Create an element for the token and append the new element to the
2059 node pointed to by the head element pointer, or, if that is null
2060 (innerHTML case), to the current node. */
2061 if ($this->head_pointer !== null) {
2062 $element = $this->insertElement($token, false);
2063 $this->head_pointer->appendChild($element);
2064 array_pop($this->stack);
2065
2066 } else {
2067 $this->insertElement($token);
2068 }
2069
2070 /* An end tag with the tag name "head" */
2071 } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') {
2072 /* If the current node is a head element, pop the current node off
2073 the stack of open elements. */
2074 if ($this->head_pointer->isSameNode(end($this->stack))) {
2075 array_pop($this->stack);
2076
2077 /* Otherwise, this is a parse error. */
2078 } else {
2079 // k
2080 }
2081
2082 /* Change the insertion mode to "after head". */
2083 $this->mode = self::AFTER_HEAD;
2084
2085 /* A start tag with the tag name "head" or an end tag except "html". */
2086 } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') ||
2087 ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')
2088 ) {
2089 // Parse error. Ignore the token.
2090
2091 /* Anything else */
2092 } else {
2093 /* If the current node is a head element, act as if an end tag
2094 token with the tag name "head" had been seen. */
2095 if ($this->head_pointer->isSameNode(end($this->stack))) {
2096 $this->inHead(
2097 array(
2098 'name' => 'head',
2099 'type' => HTML5::ENDTAG
2100 )
2101 );
2102
2103 /* Otherwise, change the insertion mode to "after head". */
2104 } else {
2105 $this->mode = self::AFTER_HEAD;
2106 }
2107
2108 /* Then, reprocess the current token. */
2109 return $this->afterHead($token);
2110 }
2111 }
const PCDATA
Definition: PH5P.php:449

References AFTER_HEAD, afterHead(), HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, inHead(), insertComment(), insertElement(), insertText(), HTML5\PCDATA, HTML5\RCDATA, and HTML5\STARTTAG.

Referenced by afterHead(), beforeHead(), inBody(), inHead(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inHead() [2/2]

HTML5TreeConstructer::inHead (   $token)
private

Definition at line 1423 of file PH5P.php.

1424 {
1425 /* Handle the token as follows: */
1426
1427 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1428 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1429 or U+0020 SPACE.
1430
1431 THIS DIFFERS FROM THE SPEC: If the current node is either a title, style
1432 or script element, append the character to the current node regardless
1433 of its content. */
1434 if(($token['type'] === HTML5::CHARACTR &&
1435 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || (
1436 $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName,
1437 array('title', 'style', 'script')))) {
1438 /* Append the character to the current node. */
1439 $this->insertText($token['data']);
1440
1441 /* A comment token */
1442 } elseif($token['type'] === HTML5::COMMENT) {
1443 /* Append a Comment node to the current node with the data attribute
1444 set to the data given in the comment token. */
1445 $this->insertComment($token['data']);
1446
1447 } elseif($token['type'] === HTML5::ENDTAG &&
1448 in_array($token['name'], array('title', 'style', 'script'))) {
1449 array_pop($this->stack);
1450 return HTML5::PCDATA;
1451
1452 /* A start tag with the tag name "title" */
1453 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') {
1454 /* Create an element for the token and append the new element to the
1455 node pointed to by the head element pointer, or, if that is null
1456 (innerHTML case), to the current node. */
1457 if($this->head_pointer !== null) {
1458 $element = $this->insertElement($token, false);
1459 $this->head_pointer->appendChild($element);
1460
1461 } else {
1462 $element = $this->insertElement($token);
1463 }
1464
1465 /* Switch the tokeniser's content model flag to the RCDATA state. */
1466 return HTML5::RCDATA;
1467
1468 /* A start tag with the tag name "style" */
1469 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') {
1470 /* Create an element for the token and append the new element to the
1471 node pointed to by the head element pointer, or, if that is null
1472 (innerHTML case), to the current node. */
1473 if($this->head_pointer !== null) {
1474 $element = $this->insertElement($token, false);
1475 $this->head_pointer->appendChild($element);
1476
1477 } else {
1478 $this->insertElement($token);
1479 }
1480
1481 /* Switch the tokeniser's content model flag to the CDATA state. */
1482 return HTML5::CDATA;
1483
1484 /* A start tag with the tag name "script" */
1485 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') {
1486 /* Create an element for the token. */
1487 $element = $this->insertElement($token, false);
1488 $this->head_pointer->appendChild($element);
1489
1490 /* Switch the tokeniser's content model flag to the CDATA state. */
1491 return HTML5::CDATA;
1492
1493 /* A start tag with the tag name "base", "link", or "meta" */
1494 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
1495 array('base', 'link', 'meta'))) {
1496 /* Create an element for the token and append the new element to the
1497 node pointed to by the head element pointer, or, if that is null
1498 (innerHTML case), to the current node. */
1499 if($this->head_pointer !== null) {
1500 $element = $this->insertElement($token, false);
1501 $this->head_pointer->appendChild($element);
1502 array_pop($this->stack);
1503
1504 } else {
1505 $this->insertElement($token);
1506 }
1507
1508 /* An end tag with the tag name "head" */
1509 } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') {
1510 /* If the current node is a head element, pop the current node off
1511 the stack of open elements. */
1512 if($this->head_pointer->isSameNode(end($this->stack))) {
1513 array_pop($this->stack);
1514
1515 /* Otherwise, this is a parse error. */
1516 } else {
1517 // k
1518 }
1519
1520 /* Change the insertion mode to "after head". */
1521 $this->mode = self::AFTER_HEAD;
1522
1523 /* A start tag with the tag name "head" or an end tag except "html". */
1524 } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') ||
1525 ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) {
1526 // Parse error. Ignore the token.
1527
1528 /* Anything else */
1529 } else {
1530 /* If the current node is a head element, act as if an end tag
1531 token with the tag name "head" had been seen. */
1532 if($this->head_pointer->isSameNode(end($this->stack))) {
1533 $this->inHead(array(
1534 'name' => 'head',
1535 'type' => HTML5::ENDTAG
1536 ));
1537
1538 /* Otherwise, change the insertion mode to "after head". */
1539 } else {
1540 $this->mode = self::AFTER_HEAD;
1541 }
1542
1543 /* Then, reprocess the current token. */
1544 return $this->afterHead($token);
1545 }
1546 }

References AFTER_HEAD, afterHead(), HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, inHead(), insertComment(), insertElement(), insertText(), HTML5\PCDATA, HTML5\RCDATA, and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ initPhase() [1/2]

HTML5TreeConstructer::initPhase (   $token)
private

Definition at line 1731 of file PH5P.php.

1732 {
1733 /* Initially, the tree construction stage must handle each token
1734 emitted from the tokenisation stage as follows: */
1735
1736 /* A DOCTYPE token that is marked as being in error
1737 A comment token
1738 A start tag token
1739 An end tag token
1740 A character token that is not one of one of U+0009 CHARACTER TABULATION,
1741 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1742 or U+0020 SPACE
1743 An end-of-file token */
1744 if ((isset($token['error']) && $token['error']) ||
1745 $token['type'] === HTML5::COMMENT ||
1746 $token['type'] === HTML5::STARTTAG ||
1747 $token['type'] === HTML5::ENDTAG ||
1748 $token['type'] === HTML5::EOF ||
1749 ($token['type'] === HTML5::CHARACTR && isset($token['data']) &&
1750 !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))
1751 ) {
1752 /* This specification does not define how to handle this case. In
1753 particular, user agents may ignore the entirety of this specification
1754 altogether for such documents, and instead invoke special parse modes
1755 with a greater emphasis on backwards compatibility. */
1756
1757 $this->phase = self::ROOT_PHASE;
1758 return $this->rootElementPhase($token);
1759
1760 /* A DOCTYPE token marked as being correct */
1761 } elseif (isset($token['error']) && !$token['error']) {
1762 /* Append a DocumentType node to the Document node, with the name
1763 attribute set to the name given in the DOCTYPE token (which will be
1764 "HTML"), and the other attributes specific to DocumentType objects
1765 set to null, empty lists, or the empty string as appropriate. */
1766 $doctype = new DOMDocumentType(null, null, 'HTML');
1767
1768 /* Then, switch to the root element phase of the tree construction
1769 stage. */
1770 $this->phase = self::ROOT_PHASE;
1771
1772 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1773 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1774 or U+0020 SPACE */
1775 } elseif (isset($token['data']) && preg_match(
1776 '/^[\t\n\x0b\x0c ]+$/',
1777 $token['data']
1778 )
1779 ) {
1780 /* Append that character to the Document node. */
1781 $text = $this->dom->createTextNode($token['data']);
1782 $this->dom->appendChild($text);
1783 }
1784 }
const EOF
Definition: PH5P.php:459

References $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, HTML5\EOF, ROOT_PHASE, rootElementPhase(), and HTML5\STARTTAG.

Referenced by emitToken().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ initPhase() [2/2]

HTML5TreeConstructer::initPhase (   $token)
private

Definition at line 1218 of file PH5P.php.

1219 {
1220 /* Initially, the tree construction stage must handle each token
1221 emitted from the tokenisation stage as follows: */
1222
1223 /* A DOCTYPE token that is marked as being in error
1224 A comment token
1225 A start tag token
1226 An end tag token
1227 A character token that is not one of one of U+0009 CHARACTER TABULATION,
1228 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1229 or U+0020 SPACE
1230 An end-of-file token */
1231 if((isset($token['error']) && $token['error']) ||
1232 $token['type'] === HTML5::COMMENT ||
1233 $token['type'] === HTML5::STARTTAG ||
1234 $token['type'] === HTML5::ENDTAG ||
1235 $token['type'] === HTML5::EOF ||
1236 ($token['type'] === HTML5::CHARACTR && isset($token['data']) &&
1237 !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) {
1238 /* This specification does not define how to handle this case. In
1239 particular, user agents may ignore the entirety of this specification
1240 altogether for such documents, and instead invoke special parse modes
1241 with a greater emphasis on backwards compatibility. */
1242
1243 $this->phase = self::ROOT_PHASE;
1244 return $this->rootElementPhase($token);
1245
1246 /* A DOCTYPE token marked as being correct */
1247 } elseif(isset($token['error']) && !$token['error']) {
1248 /* Append a DocumentType node to the Document node, with the name
1249 attribute set to the name given in the DOCTYPE token (which will be
1250 "HTML"), and the other attributes specific to DocumentType objects
1251 set to null, empty lists, or the empty string as appropriate. */
1252 $doctype = new DOMDocumentType(null, null, 'HTML');
1253
1254 /* Then, switch to the root element phase of the tree construction
1255 stage. */
1256 $this->phase = self::ROOT_PHASE;
1257
1258 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1259 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1260 or U+0020 SPACE */
1261 } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/',
1262 $token['data'])) {
1263 /* Append that character to the Document node. */
1264 $text = $this->dom->createTextNode($token['data']);
1265 $this->dom->appendChild($text);
1266 }
1267 }

References $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, HTML5\EOF, ROOT_PHASE, rootElementPhase(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inRow() [1/2]

HTML5TreeConstructer::inRow (   $token)
private

Definition at line 3784 of file PH5P.php.

3785 {
3786 $clear = array('tr', 'html');
3787
3788 /* A start tag whose tag name is one of: "th", "td" */
3789 if ($token['type'] === HTML5::STARTTAG &&
3790 ($token['name'] === 'th' || $token['name'] === 'td')
3791 ) {
3792 /* Clear the stack back to a table row context. */
3793 $this->clearStackToTableContext($clear);
3794
3795 /* Insert an HTML element for the token, then switch the insertion
3796 mode to "in cell". */
3797 $this->insertElement($token);
3798 $this->mode = self::IN_CELL;
3799
3800 /* Insert a marker at the end of the list of active formatting
3801 elements. */
3802 $this->a_formatting[] = self::MARKER;
3803
3804 /* An end tag whose tag name is "tr" */
3805 } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') {
3806 /* If the stack of open elements does not have an element in table
3807 scope with the same tag name as the token, this is a parse error.
3808 Ignore the token. (innerHTML case) */
3809 if (!$this->elementInScope($token['name'], true)) {
3810 // Ignore.
3811
3812 /* Otherwise: */
3813 } else {
3814 /* Clear the stack back to a table row context. */
3815 $this->clearStackToTableContext($clear);
3816
3817 /* Pop the current node (which will be a tr element) from the
3818 stack of open elements. Switch the insertion mode to "in table
3819 body". */
3820 array_pop($this->stack);
3821 $this->mode = self::IN_TBODY;
3822 }
3823
3824 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3825 "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
3826 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
3827 $token['name'],
3828 array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr')
3829 )
3830 ) {
3831 /* Act as if an end tag with the tag name "tr" had been seen, then,
3832 if that token wasn't ignored, reprocess the current token. */
3833 $this->inRow(
3834 array(
3835 'name' => 'tr',
3836 'type' => HTML5::ENDTAG
3837 )
3838 );
3839
3840 return $this->inCell($token);
3841
3842 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
3843 } elseif ($token['type'] === HTML5::ENDTAG &&
3844 in_array($token['name'], array('tbody', 'tfoot', 'thead'))
3845 ) {
3846 /* If the stack of open elements does not have an element in table
3847 scope with the same tag name as the token, this is a parse error.
3848 Ignore the token. */
3849 if (!$this->elementInScope($token['name'], true)) {
3850 // Ignore.
3851
3852 /* Otherwise: */
3853 } else {
3854 /* Otherwise, act as if an end tag with the tag name "tr" had
3855 been seen, then reprocess the current token. */
3856 $this->inRow(
3857 array(
3858 'name' => 'tr',
3859 'type' => HTML5::ENDTAG
3860 )
3861 );
3862
3863 return $this->inCell($token);
3864 }
3865
3866 /* An end tag whose tag name is one of: "body", "caption", "col",
3867 "colgroup", "html", "td", "th" */
3868 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3869 $token['name'],
3870 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr')
3871 )
3872 ) {
3873 /* Parse error. Ignore the token. */
3874
3875 /* Anything else */
3876 } else {
3877 /* Process the token as if the insertion mode was "in table". */
3878 $this->inTable($token);
3879 }
3880 }
clearStackToTableContext($elements)
Definition: PH5P.php:4649

References clearStackToTableContext(), elementInScope(), HTML5\ENDTAG, IN_CELL, IN_TBODY, inCell(), inRow(), insertElement(), inTable(), MARKER, and HTML5\STARTTAG.

Referenced by inCell(), inRow(), inTableBody(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inRow() [2/2]

HTML5TreeConstructer::inRow (   $token)
private

Definition at line 2996 of file PH5P.php.

2997 {
2998 $clear = array('tr', 'html');
2999
3000 /* A start tag whose tag name is one of: "th", "td" */
3001 if($token['type'] === HTML5::STARTTAG &&
3002 ($token['name'] === 'th' || $token['name'] === 'td')) {
3003 /* Clear the stack back to a table row context. */
3004 $this->clearStackToTableContext($clear);
3005
3006 /* Insert an HTML element for the token, then switch the insertion
3007 mode to "in cell". */
3008 $this->insertElement($token);
3009 $this->mode = self::IN_CELL;
3010
3011 /* Insert a marker at the end of the list of active formatting
3012 elements. */
3013 $this->a_formatting[] = self::MARKER;
3014
3015 /* An end tag whose tag name is "tr" */
3016 } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') {
3017 /* If the stack of open elements does not have an element in table
3018 scope with the same tag name as the token, this is a parse error.
3019 Ignore the token. (innerHTML case) */
3020 if(!$this->elementInScope($token['name'], true)) {
3021 // Ignore.
3022
3023 /* Otherwise: */
3024 } else {
3025 /* Clear the stack back to a table row context. */
3026 $this->clearStackToTableContext($clear);
3027
3028 /* Pop the current node (which will be a tr element) from the
3029 stack of open elements. Switch the insertion mode to "in table
3030 body". */
3031 array_pop($this->stack);
3032 $this->mode = self::IN_TBODY;
3033 }
3034
3035 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3036 "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
3037 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3038 array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) {
3039 /* Act as if an end tag with the tag name "tr" had been seen, then,
3040 if that token wasn't ignored, reprocess the current token. */
3041 $this->inRow(array(
3042 'name' => 'tr',
3043 'type' => HTML5::ENDTAG
3044 ));
3045
3046 return $this->inCell($token);
3047
3048 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
3049 } elseif($token['type'] === HTML5::ENDTAG &&
3050 in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
3051 /* If the stack of open elements does not have an element in table
3052 scope with the same tag name as the token, this is a parse error.
3053 Ignore the token. */
3054 if(!$this->elementInScope($token['name'], true)) {
3055 // Ignore.
3056
3057 /* Otherwise: */
3058 } else {
3059 /* Otherwise, act as if an end tag with the tag name "tr" had
3060 been seen, then reprocess the current token. */
3061 $this->inRow(array(
3062 'name' => 'tr',
3063 'type' => HTML5::ENDTAG
3064 ));
3065
3066 return $this->inCell($token);
3067 }
3068
3069 /* An end tag whose tag name is one of: "body", "caption", "col",
3070 "colgroup", "html", "td", "th" */
3071 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3072 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
3073 /* Parse error. Ignore the token. */
3074
3075 /* Anything else */
3076 } else {
3077 /* Process the token as if the insertion mode was "in table". */
3078 $this->inTable($token);
3079 }
3080 }

References clearStackToTableContext(), elementInScope(), HTML5\ENDTAG, IN_CELL, IN_TBODY, inCell(), inRow(), insertElement(), inTable(), MARKER, and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inSelect() [1/2]

HTML5TreeConstructer::inSelect (   $token)
private

Definition at line 4021 of file PH5P.php.

4022 {
4023 /* Handle the token as follows: */
4024
4025 /* A character token */
4026 if ($token['type'] === HTML5::CHARACTR) {
4027 /* Append the token's character to the current node. */
4028 $this->insertText($token['data']);
4029
4030 /* A comment token */
4031 } elseif ($token['type'] === HTML5::COMMENT) {
4032 /* Append a Comment node to the current node with the data
4033 attribute set to the data given in the comment token. */
4034 $this->insertComment($token['data']);
4035
4036 /* A start tag token whose tag name is "option" */
4037 } elseif ($token['type'] === HTML5::STARTTAG &&
4038 $token['name'] === 'option'
4039 ) {
4040 /* If the current node is an option element, act as if an end tag
4041 with the tag name "option" had been seen. */
4042 if (end($this->stack)->nodeName === 'option') {
4043 $this->inSelect(
4044 array(
4045 'name' => 'option',
4046 'type' => HTML5::ENDTAG
4047 )
4048 );
4049 }
4050
4051 /* Insert an HTML element for the token. */
4052 $this->insertElement($token);
4053
4054 /* A start tag token whose tag name is "optgroup" */
4055 } elseif ($token['type'] === HTML5::STARTTAG &&
4056 $token['name'] === 'optgroup'
4057 ) {
4058 /* If the current node is an option element, act as if an end tag
4059 with the tag name "option" had been seen. */
4060 if (end($this->stack)->nodeName === 'option') {
4061 $this->inSelect(
4062 array(
4063 'name' => 'option',
4064 'type' => HTML5::ENDTAG
4065 )
4066 );
4067 }
4068
4069 /* If the current node is an optgroup element, act as if an end tag
4070 with the tag name "optgroup" had been seen. */
4071 if (end($this->stack)->nodeName === 'optgroup') {
4072 $this->inSelect(
4073 array(
4074 'name' => 'optgroup',
4075 'type' => HTML5::ENDTAG
4076 )
4077 );
4078 }
4079
4080 /* Insert an HTML element for the token. */
4081 $this->insertElement($token);
4082
4083 /* An end tag token whose tag name is "optgroup" */
4084 } elseif ($token['type'] === HTML5::ENDTAG &&
4085 $token['name'] === 'optgroup'
4086 ) {
4087 /* First, if the current node is an option element, and the node
4088 immediately before it in the stack of open elements is an optgroup
4089 element, then act as if an end tag with the tag name "option" had
4090 been seen. */
4091 $elements_in_stack = count($this->stack);
4092
4093 if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' &&
4094 $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup'
4095 ) {
4096 $this->inSelect(
4097 array(
4098 'name' => 'option',
4099 'type' => HTML5::ENDTAG
4100 )
4101 );
4102 }
4103
4104 /* If the current node is an optgroup element, then pop that node
4105 from the stack of open elements. Otherwise, this is a parse error,
4106 ignore the token. */
4107 if ($this->stack[$elements_in_stack - 1] === 'optgroup') {
4108 array_pop($this->stack);
4109 }
4110
4111 /* An end tag token whose tag name is "option" */
4112 } elseif ($token['type'] === HTML5::ENDTAG &&
4113 $token['name'] === 'option'
4114 ) {
4115 /* If the current node is an option element, then pop that node
4116 from the stack of open elements. Otherwise, this is a parse error,
4117 ignore the token. */
4118 if (end($this->stack)->nodeName === 'option') {
4119 array_pop($this->stack);
4120 }
4121
4122 /* An end tag whose tag name is "select" */
4123 } elseif ($token['type'] === HTML5::ENDTAG &&
4124 $token['name'] === 'select'
4125 ) {
4126 /* If the stack of open elements does not have an element in table
4127 scope with the same tag name as the token, this is a parse error.
4128 Ignore the token. (innerHTML case) */
4129 if (!$this->elementInScope($token['name'], true)) {
4130 // w/e
4131
4132 /* Otherwise: */
4133 } else {
4134 /* Pop elements from the stack of open elements until a select
4135 element has been popped from the stack. */
4136 while (true) {
4137 $current = end($this->stack)->nodeName;
4138 array_pop($this->stack);
4139
4140 if ($current === 'select') {
4141 break;
4142 }
4143 }
4144
4145 /* Reset the insertion mode appropriately. */
4146 $this->resetInsertionMode();
4147 }
4148
4149 /* A start tag whose tag name is "select" */
4150 } elseif ($token['name'] === 'select' &&
4151 $token['type'] === HTML5::STARTTAG
4152 ) {
4153 /* Parse error. Act as if the token had been an end tag with the
4154 tag name "select" instead. */
4155 $this->inSelect(
4156 array(
4157 'name' => 'select',
4158 'type' => HTML5::ENDTAG
4159 )
4160 );
4161
4162 /* An end tag whose tag name is one of: "caption", "table", "tbody",
4163 "tfoot", "thead", "tr", "td", "th" */
4164 } elseif (in_array(
4165 $token['name'],
4166 array(
4167 'caption',
4168 'table',
4169 'tbody',
4170 'tfoot',
4171 'thead',
4172 'tr',
4173 'td',
4174 'th'
4175 )
4176 ) && $token['type'] === HTML5::ENDTAG
4177 ) {
4178 /* Parse error. */
4179 // w/e
4180
4181 /* If the stack of open elements has an element in table scope with
4182 the same tag name as that of the token, then act as if an end tag
4183 with the tag name "select" had been seen, and reprocess the token.
4184 Otherwise, ignore the token. */
4185 if ($this->elementInScope($token['name'], true)) {
4186 $this->inSelect(
4187 array(
4188 'name' => 'select',
4189 'type' => HTML5::ENDTAG
4190 )
4191 );
4192
4193 $this->mainPhase($token);
4194 }
4195
4196 /* Anything else */
4197 } else {
4198 /* Parse error. Ignore the token. */
4199 }
4200 }
inSelect($token)
Definition: PH5P.php:4021

References $current, HTML5\CHARACTR, HTML5\COMMENT, elementInScope(), HTML5\ENDTAG, inSelect(), insertComment(), insertElement(), insertText(), mainPhase(), resetInsertionMode(), and HTML5\STARTTAG.

Referenced by inSelect(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inSelect() [2/2]

HTML5TreeConstructer::inSelect (   $token)
private

Definition at line 3190 of file PH5P.php.

3191 {
3192 /* Handle the token as follows: */
3193
3194 /* A character token */
3195 if($token['type'] === HTML5::CHARACTR) {
3196 /* Append the token's character to the current node. */
3197 $this->insertText($token['data']);
3198
3199 /* A comment token */
3200 } elseif($token['type'] === HTML5::COMMENT) {
3201 /* Append a Comment node to the current node with the data
3202 attribute set to the data given in the comment token. */
3203 $this->insertComment($token['data']);
3204
3205 /* A start tag token whose tag name is "option" */
3206 } elseif($token['type'] === HTML5::STARTTAG &&
3207 $token['name'] === 'option') {
3208 /* If the current node is an option element, act as if an end tag
3209 with the tag name "option" had been seen. */
3210 if(end($this->stack)->nodeName === 'option') {
3211 $this->inSelect(array(
3212 'name' => 'option',
3213 'type' => HTML5::ENDTAG
3214 ));
3215 }
3216
3217 /* Insert an HTML element for the token. */
3218 $this->insertElement($token);
3219
3220 /* A start tag token whose tag name is "optgroup" */
3221 } elseif($token['type'] === HTML5::STARTTAG &&
3222 $token['name'] === 'optgroup') {
3223 /* If the current node is an option element, act as if an end tag
3224 with the tag name "option" had been seen. */
3225 if(end($this->stack)->nodeName === 'option') {
3226 $this->inSelect(array(
3227 'name' => 'option',
3228 'type' => HTML5::ENDTAG
3229 ));
3230 }
3231
3232 /* If the current node is an optgroup element, act as if an end tag
3233 with the tag name "optgroup" had been seen. */
3234 if(end($this->stack)->nodeName === 'optgroup') {
3235 $this->inSelect(array(
3236 'name' => 'optgroup',
3237 'type' => HTML5::ENDTAG
3238 ));
3239 }
3240
3241 /* Insert an HTML element for the token. */
3242 $this->insertElement($token);
3243
3244 /* An end tag token whose tag name is "optgroup" */
3245 } elseif($token['type'] === HTML5::ENDTAG &&
3246 $token['name'] === 'optgroup') {
3247 /* First, if the current node is an option element, and the node
3248 immediately before it in the stack of open elements is an optgroup
3249 element, then act as if an end tag with the tag name "option" had
3250 been seen. */
3251 $elements_in_stack = count($this->stack);
3252
3253 if($this->stack[$elements_in_stack - 1]->nodeName === 'option' &&
3254 $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') {
3255 $this->inSelect(array(
3256 'name' => 'option',
3257 'type' => HTML5::ENDTAG
3258 ));
3259 }
3260
3261 /* If the current node is an optgroup element, then pop that node
3262 from the stack of open elements. Otherwise, this is a parse error,
3263 ignore the token. */
3264 if($this->stack[$elements_in_stack - 1] === 'optgroup') {
3265 array_pop($this->stack);
3266 }
3267
3268 /* An end tag token whose tag name is "option" */
3269 } elseif($token['type'] === HTML5::ENDTAG &&
3270 $token['name'] === 'option') {
3271 /* If the current node is an option element, then pop that node
3272 from the stack of open elements. Otherwise, this is a parse error,
3273 ignore the token. */
3274 if(end($this->stack)->nodeName === 'option') {
3275 array_pop($this->stack);
3276 }
3277
3278 /* An end tag whose tag name is "select" */
3279 } elseif($token['type'] === HTML5::ENDTAG &&
3280 $token['name'] === 'select') {
3281 /* If the stack of open elements does not have an element in table
3282 scope with the same tag name as the token, this is a parse error.
3283 Ignore the token. (innerHTML case) */
3284 if(!$this->elementInScope($token['name'], true)) {
3285 // w/e
3286
3287 /* Otherwise: */
3288 } else {
3289 /* Pop elements from the stack of open elements until a select
3290 element has been popped from the stack. */
3291 while(true) {
3292 $current = end($this->stack)->nodeName;
3293 array_pop($this->stack);
3294
3295 if($current === 'select') {
3296 break;
3297 }
3298 }
3299
3300 /* Reset the insertion mode appropriately. */
3301 $this->resetInsertionMode();
3302 }
3303
3304 /* A start tag whose tag name is "select" */
3305 } elseif($token['name'] === 'select' &&
3306 $token['type'] === HTML5::STARTTAG) {
3307 /* Parse error. Act as if the token had been an end tag with the
3308 tag name "select" instead. */
3309 $this->inSelect(array(
3310 'name' => 'select',
3311 'type' => HTML5::ENDTAG
3312 ));
3313
3314 /* An end tag whose tag name is one of: "caption", "table", "tbody",
3315 "tfoot", "thead", "tr", "td", "th" */
3316 } elseif(in_array($token['name'], array('caption', 'table', 'tbody',
3317 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) {
3318 /* Parse error. */
3319 // w/e
3320
3321 /* If the stack of open elements has an element in table scope with
3322 the same tag name as that of the token, then act as if an end tag
3323 with the tag name "select" had been seen, and reprocess the token.
3324 Otherwise, ignore the token. */
3325 if($this->elementInScope($token['name'], true)) {
3326 $this->inSelect(array(
3327 'name' => 'select',
3328 'type' => HTML5::ENDTAG
3329 ));
3330
3331 $this->mainPhase($token);
3332 }
3333
3334 /* Anything else */
3335 } else {
3336 /* Parse error. Ignore the token. */
3337 }
3338 }

References $current, HTML5\CHARACTR, HTML5\COMMENT, elementInScope(), HTML5\ENDTAG, inSelect(), insertComment(), insertElement(), insertText(), mainPhase(), resetInsertionMode(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ insertComment() [1/2]

HTML5TreeConstructer::insertComment (   $data)
private

Definition at line 4429 of file PH5P.php.

4430 {
4431 $comment = $this->dom->createComment($data);
4433 }
appendToRealParent($node)
Definition: PH5P.php:4435

References $comment, $data, and appendToRealParent().

Referenced by afterFrameset(), afterHead(), beforeHead(), inBody(), inFrameset(), inHead(), and inSelect().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insertComment() [2/2]

HTML5TreeConstructer::insertComment (   $data)
private

Definition at line 3543 of file PH5P.php.

3544 {
3545 $comment = $this->dom->createComment($data);
3547 }

References $comment, $data, and appendToRealParent().

+ Here is the call graph for this function:

◆ insertElement() [1/2]

HTML5TreeConstructer::insertElement (   $token,
  $append = true 
)
private

Definition at line 3521 of file PH5P.php.

3522 {
3523 $el = $this->dom->createElement($token['name']);
3524
3525 foreach($token['attr'] as $attr) {
3526 if(!$el->hasAttribute($attr['name'])) {
3527 $el->setAttribute($attr['name'], $attr['value']);
3528 }
3529 }
3530
3531 $this->appendToRealParent($el);
3532 $this->stack[] = $el;
3533
3534 return $el;
3535 }

References appendToRealParent().

+ Here is the call graph for this function:

◆ insertElement() [2/2]

HTML5TreeConstructer::insertElement (   $token,
  $append = true,
  $check = false 
)
private

Definition at line 4394 of file PH5P.php.

4395 {
4396 // Proprietary workaround for libxml2's limitations with tag names
4397 if ($check) {
4398 // Slightly modified HTML5 tag-name modification,
4399 // removing anything that's not an ASCII letter, digit, or hyphen
4400 $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']);
4401 // Remove leading hyphens and numbers
4402 $token['name'] = ltrim($token['name'], '-0..9');
4403 // In theory, this should ever be needed, but just in case
4404 if ($token['name'] === '') {
4405 $token['name'] = 'span';
4406 } // arbitrary generic choice
4407 }
4408
4409 $el = $this->dom->createElement($token['name']);
4410
4411 foreach ($token['attr'] as $attr) {
4412 if (!$el->hasAttribute($attr['name'])) {
4413 $el->setAttribute($attr['name'], $attr['value']);
4414 }
4415 }
4416
4417 $this->appendToRealParent($el);
4418 $this->stack[] = $el;
4419
4420 return $el;
4421 }

References appendToRealParent().

Referenced by afterHead(), beforeHead(), inBody(), inColumnGroup(), inFrameset(), inHead(), inRow(), inSelect(), inTable(), and inTableBody().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insertText() [1/2]

HTML5TreeConstructer::insertText (   $data)
private

Definition at line 4423 of file PH5P.php.

4424 {
4425 $text = $this->dom->createTextNode($data);
4426 $this->appendToRealParent($text);
4427 }

References $data, $text, and appendToRealParent().

Referenced by afterFrameset(), afterHead(), beforeHead(), inBody(), inFrameset(), inHead(), and inSelect().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insertText() [2/2]

HTML5TreeConstructer::insertText (   $data)
private

Definition at line 3537 of file PH5P.php.

3538 {
3539 $text = $this->dom->createTextNode($data);
3540 $this->appendToRealParent($text);
3541 }

References $data, $text, and appendToRealParent().

+ Here is the call graph for this function:

◆ inTable() [1/2]

HTML5TreeConstructer::inTable (   $token)
private

Definition at line 3316 of file PH5P.php.

3317 {
3318 $clear = array('html', 'table');
3319
3320 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3321 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3322 or U+0020 SPACE */
3323 if ($token['type'] === HTML5::CHARACTR &&
3324 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
3325 ) {
3326 /* Append the character to the current node. */
3327 $text = $this->dom->createTextNode($token['data']);
3328 end($this->stack)->appendChild($text);
3329
3330 /* A comment token */
3331 } elseif ($token['type'] === HTML5::COMMENT) {
3332 /* Append a Comment node to the current node with the data
3333 attribute set to the data given in the comment token. */
3334 $comment = $this->dom->createComment($token['data']);
3335 end($this->stack)->appendChild($comment);
3336
3337 /* A start tag whose tag name is "caption" */
3338 } elseif ($token['type'] === HTML5::STARTTAG &&
3339 $token['name'] === 'caption'
3340 ) {
3341 /* Clear the stack back to a table context. */
3342 $this->clearStackToTableContext($clear);
3343
3344 /* Insert a marker at the end of the list of active
3345 formatting elements. */
3346 $this->a_formatting[] = self::MARKER;
3347
3348 /* Insert an HTML element for the token, then switch the
3349 insertion mode to "in caption". */
3350 $this->insertElement($token);
3351 $this->mode = self::IN_CAPTION;
3352
3353 /* A start tag whose tag name is "colgroup" */
3354 } elseif ($token['type'] === HTML5::STARTTAG &&
3355 $token['name'] === 'colgroup'
3356 ) {
3357 /* Clear the stack back to a table context. */
3358 $this->clearStackToTableContext($clear);
3359
3360 /* Insert an HTML element for the token, then switch the
3361 insertion mode to "in column group". */
3362 $this->insertElement($token);
3363 $this->mode = self::IN_CGROUP;
3364
3365 /* A start tag whose tag name is "col" */
3366 } elseif ($token['type'] === HTML5::STARTTAG &&
3367 $token['name'] === 'col'
3368 ) {
3369 $this->inTable(
3370 array(
3371 'name' => 'colgroup',
3372 'type' => HTML5::STARTTAG,
3373 'attr' => array()
3374 )
3375 );
3376
3377 $this->inColumnGroup($token);
3378
3379 /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
3380 } elseif ($token['type'] === HTML5::STARTTAG && in_array(
3381 $token['name'],
3382 array('tbody', 'tfoot', 'thead')
3383 )
3384 ) {
3385 /* Clear the stack back to a table context. */
3386 $this->clearStackToTableContext($clear);
3387
3388 /* Insert an HTML element for the token, then switch the insertion
3389 mode to "in table body". */
3390 $this->insertElement($token);
3391 $this->mode = self::IN_TBODY;
3392
3393 /* A start tag whose tag name is one of: "td", "th", "tr" */
3394 } elseif ($token['type'] === HTML5::STARTTAG &&
3395 in_array($token['name'], array('td', 'th', 'tr'))
3396 ) {
3397 /* Act as if a start tag token with the tag name "tbody" had been
3398 seen, then reprocess the current token. */
3399 $this->inTable(
3400 array(
3401 'name' => 'tbody',
3402 'type' => HTML5::STARTTAG,
3403 'attr' => array()
3404 )
3405 );
3406
3407 return $this->inTableBody($token);
3408
3409 /* A start tag whose tag name is "table" */
3410 } elseif ($token['type'] === HTML5::STARTTAG &&
3411 $token['name'] === 'table'
3412 ) {
3413 /* Parse error. Act as if an end tag token with the tag name "table"
3414 had been seen, then, if that token wasn't ignored, reprocess the
3415 current token. */
3416 $this->inTable(
3417 array(
3418 'name' => 'table',
3419 'type' => HTML5::ENDTAG
3420 )
3421 );
3422
3423 return $this->mainPhase($token);
3424
3425 /* An end tag whose tag name is "table" */
3426 } elseif ($token['type'] === HTML5::ENDTAG &&
3427 $token['name'] === 'table'
3428 ) {
3429 /* If the stack of open elements does not have an element in table
3430 scope with the same tag name as the token, this is a parse error.
3431 Ignore the token. (innerHTML case) */
3432 if (!$this->elementInScope($token['name'], true)) {
3433 return false;
3434
3435 /* Otherwise: */
3436 } else {
3437 /* Generate implied end tags. */
3438 $this->generateImpliedEndTags();
3439
3440 /* Now, if the current node is not a table element, then this
3441 is a parse error. */
3442 // w/e
3443
3444 /* Pop elements from this stack until a table element has been
3445 popped from the stack. */
3446 while (true) {
3447 $current = end($this->stack)->nodeName;
3448 array_pop($this->stack);
3449
3450 if ($current === 'table') {
3451 break;
3452 }
3453 }
3454
3455 /* Reset the insertion mode appropriately. */
3456 $this->resetInsertionMode();
3457 }
3458
3459 /* An end tag whose tag name is one of: "body", "caption", "col",
3460 "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
3461 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3462 $token['name'],
3463 array(
3464 'body',
3465 'caption',
3466 'col',
3467 'colgroup',
3468 'html',
3469 'tbody',
3470 'td',
3471 'tfoot',
3472 'th',
3473 'thead',
3474 'tr'
3475 )
3476 )
3477 ) {
3478 // Parse error. Ignore the token.
3479
3480 /* Anything else */
3481 } else {
3482 /* Parse error. Process the token as if the insertion mode was "in
3483 body", with the following exception: */
3484
3485 /* If the current node is a table, tbody, tfoot, thead, or tr
3486 element, then, whenever a node would be inserted into the current
3487 node, it must instead be inserted into the foster parent element. */
3488 if (in_array(
3489 end($this->stack)->nodeName,
3490 array('table', 'tbody', 'tfoot', 'thead', 'tr')
3491 )
3492 ) {
3493 /* The foster parent element is the parent element of the last
3494 table element in the stack of open elements, if there is a
3495 table element and it has such a parent element. If there is no
3496 table element in the stack of open elements (innerHTML case),
3497 then the foster parent element is the first element in the
3498 stack of open elements (the html element). Otherwise, if there
3499 is a table element in the stack of open elements, but the last
3500 table element in the stack of open elements has no parent, or
3501 its parent node is not an element, then the foster parent
3502 element is the element before the last table element in the
3503 stack of open elements. */
3504 for ($n = count($this->stack) - 1; $n >= 0; $n--) {
3505 if ($this->stack[$n]->nodeName === 'table') {
3506 $table = $this->stack[$n];
3507 break;
3508 }
3509 }
3510
3511 if (isset($table) && $table->parentNode !== null) {
3512 $this->foster_parent = $table->parentNode;
3513
3514 } elseif (!isset($table)) {
3515 $this->foster_parent = $this->stack[0];
3516
3517 } elseif (isset($table) && ($table->parentNode === null ||
3518 $table->parentNode->nodeType !== XML_ELEMENT_NODE)
3519 ) {
3520 $this->foster_parent = $this->stack[$n - 1];
3521 }
3522 }
3523
3524 $this->inBody($token);
3525 }
3526 }
inTableBody($token)
Definition: PH5P.php:3685

References $comment, $current, $n, $table, $text, HTML5\CHARACTR, clearStackToTableContext(), HTML5\COMMENT, elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_CAPTION, IN_CGROUP, IN_TBODY, inBody(), inColumnGroup(), insertElement(), inTable(), inTableBody(), mainPhase(), MARKER, resetInsertionMode(), and HTML5\STARTTAG.

Referenced by inCaption(), inColumnGroup(), inRow(), inTable(), inTableBody(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inTable() [2/2]

HTML5TreeConstructer::inTable (   $token)
private

Definition at line 2604 of file PH5P.php.

2605 {
2606 $clear = array('html', 'table');
2607
2608 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2609 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2610 or U+0020 SPACE */
2611 if($token['type'] === HTML5::CHARACTR &&
2612 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
2613 /* Append the character to the current node. */
2614 $text = $this->dom->createTextNode($token['data']);
2615 end($this->stack)->appendChild($text);
2616
2617 /* A comment token */
2618 } elseif($token['type'] === HTML5::COMMENT) {
2619 /* Append a Comment node to the current node with the data
2620 attribute set to the data given in the comment token. */
2621 $comment = $this->dom->createComment($token['data']);
2622 end($this->stack)->appendChild($comment);
2623
2624 /* A start tag whose tag name is "caption" */
2625 } elseif($token['type'] === HTML5::STARTTAG &&
2626 $token['name'] === 'caption') {
2627 /* Clear the stack back to a table context. */
2628 $this->clearStackToTableContext($clear);
2629
2630 /* Insert a marker at the end of the list of active
2631 formatting elements. */
2632 $this->a_formatting[] = self::MARKER;
2633
2634 /* Insert an HTML element for the token, then switch the
2635 insertion mode to "in caption". */
2636 $this->insertElement($token);
2637 $this->mode = self::IN_CAPTION;
2638
2639 /* A start tag whose tag name is "colgroup" */
2640 } elseif($token['type'] === HTML5::STARTTAG &&
2641 $token['name'] === 'colgroup') {
2642 /* Clear the stack back to a table context. */
2643 $this->clearStackToTableContext($clear);
2644
2645 /* Insert an HTML element for the token, then switch the
2646 insertion mode to "in column group". */
2647 $this->insertElement($token);
2648 $this->mode = self::IN_CGROUP;
2649
2650 /* A start tag whose tag name is "col" */
2651 } elseif($token['type'] === HTML5::STARTTAG &&
2652 $token['name'] === 'col') {
2653 $this->inTable(array(
2654 'name' => 'colgroup',
2655 'type' => HTML5::STARTTAG,
2656 'attr' => array()
2657 ));
2658
2659 $this->inColumnGroup($token);
2660
2661 /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
2662 } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2663 array('tbody', 'tfoot', 'thead'))) {
2664 /* Clear the stack back to a table context. */
2665 $this->clearStackToTableContext($clear);
2666
2667 /* Insert an HTML element for the token, then switch the insertion
2668 mode to "in table body". */
2669 $this->insertElement($token);
2670 $this->mode = self::IN_TBODY;
2671
2672 /* A start tag whose tag name is one of: "td", "th", "tr" */
2673 } elseif($token['type'] === HTML5::STARTTAG &&
2674 in_array($token['name'], array('td', 'th', 'tr'))) {
2675 /* Act as if a start tag token with the tag name "tbody" had been
2676 seen, then reprocess the current token. */
2677 $this->inTable(array(
2678 'name' => 'tbody',
2679 'type' => HTML5::STARTTAG,
2680 'attr' => array()
2681 ));
2682
2683 return $this->inTableBody($token);
2684
2685 /* A start tag whose tag name is "table" */
2686 } elseif($token['type'] === HTML5::STARTTAG &&
2687 $token['name'] === 'table') {
2688 /* Parse error. Act as if an end tag token with the tag name "table"
2689 had been seen, then, if that token wasn't ignored, reprocess the
2690 current token. */
2691 $this->inTable(array(
2692 'name' => 'table',
2693 'type' => HTML5::ENDTAG
2694 ));
2695
2696 return $this->mainPhase($token);
2697
2698 /* An end tag whose tag name is "table" */
2699 } elseif($token['type'] === HTML5::ENDTAG &&
2700 $token['name'] === 'table') {
2701 /* If the stack of open elements does not have an element in table
2702 scope with the same tag name as the token, this is a parse error.
2703 Ignore the token. (innerHTML case) */
2704 if(!$this->elementInScope($token['name'], true)) {
2705 return false;
2706
2707 /* Otherwise: */
2708 } else {
2709 /* Generate implied end tags. */
2710 $this->generateImpliedEndTags();
2711
2712 /* Now, if the current node is not a table element, then this
2713 is a parse error. */
2714 // w/e
2715
2716 /* Pop elements from this stack until a table element has been
2717 popped from the stack. */
2718 while(true) {
2719 $current = end($this->stack)->nodeName;
2720 array_pop($this->stack);
2721
2722 if($current === 'table') {
2723 break;
2724 }
2725 }
2726
2727 /* Reset the insertion mode appropriately. */
2728 $this->resetInsertionMode();
2729 }
2730
2731 /* An end tag whose tag name is one of: "body", "caption", "col",
2732 "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2733 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
2734 array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
2735 'tfoot', 'th', 'thead', 'tr'))) {
2736 // Parse error. Ignore the token.
2737
2738 /* Anything else */
2739 } else {
2740 /* Parse error. Process the token as if the insertion mode was "in
2741 body", with the following exception: */
2742
2743 /* If the current node is a table, tbody, tfoot, thead, or tr
2744 element, then, whenever a node would be inserted into the current
2745 node, it must instead be inserted into the foster parent element. */
2746 if(in_array(end($this->stack)->nodeName,
2747 array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
2748 /* The foster parent element is the parent element of the last
2749 table element in the stack of open elements, if there is a
2750 table element and it has such a parent element. If there is no
2751 table element in the stack of open elements (innerHTML case),
2752 then the foster parent element is the first element in the
2753 stack of open elements (the html element). Otherwise, if there
2754 is a table element in the stack of open elements, but the last
2755 table element in the stack of open elements has no parent, or
2756 its parent node is not an element, then the foster parent
2757 element is the element before the last table element in the
2758 stack of open elements. */
2759 for($n = count($this->stack) - 1; $n >= 0; $n--) {
2760 if($this->stack[$n]->nodeName === 'table') {
2761 $table = $this->stack[$n];
2762 break;
2763 }
2764 }
2765
2766 if(isset($table) && $table->parentNode !== null) {
2767 $this->foster_parent = $table->parentNode;
2768
2769 } elseif(!isset($table)) {
2770 $this->foster_parent = $this->stack[0];
2771
2772 } elseif(isset($table) && ($table->parentNode === null ||
2773 $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
2774 $this->foster_parent = $this->stack[$n - 1];
2775 }
2776 }
2777
2778 $this->inBody($token);
2779 }
2780 }

References $comment, $current, $n, $table, $text, HTML5\CHARACTR, clearStackToTableContext(), HTML5\COMMENT, elementInScope(), HTML5\ENDTAG, generateImpliedEndTags(), IN_CAPTION, IN_CGROUP, IN_TBODY, inBody(), inColumnGroup(), insertElement(), inTable(), inTableBody(), mainPhase(), MARKER, resetInsertionMode(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ inTableBody() [1/2]

HTML5TreeConstructer::inTableBody (   $token)
private

Definition at line 3685 of file PH5P.php.

3686 {
3687 $clear = array('tbody', 'tfoot', 'thead', 'html');
3688
3689 /* A start tag whose tag name is "tr" */
3690 if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') {
3691 /* Clear the stack back to a table body context. */
3692 $this->clearStackToTableContext($clear);
3693
3694 /* Insert a tr element for the token, then switch the insertion
3695 mode to "in row". */
3696 $this->insertElement($token);
3697 $this->mode = self::IN_ROW;
3698
3699 /* A start tag whose tag name is one of: "th", "td" */
3700 } elseif ($token['type'] === HTML5::STARTTAG &&
3701 ($token['name'] === 'th' || $token['name'] === 'td')
3702 ) {
3703 /* Parse error. Act as if a start tag with the tag name "tr" had
3704 been seen, then reprocess the current token. */
3705 $this->inTableBody(
3706 array(
3707 'name' => 'tr',
3708 'type' => HTML5::STARTTAG,
3709 'attr' => array()
3710 )
3711 );
3712
3713 return $this->inRow($token);
3714
3715 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
3716 } elseif ($token['type'] === HTML5::ENDTAG &&
3717 in_array($token['name'], array('tbody', 'tfoot', 'thead'))
3718 ) {
3719 /* If the stack of open elements does not have an element in table
3720 scope with the same tag name as the token, this is a parse error.
3721 Ignore the token. */
3722 if (!$this->elementInScope($token['name'], true)) {
3723 // Ignore
3724
3725 /* Otherwise: */
3726 } else {
3727 /* Clear the stack back to a table body context. */
3728 $this->clearStackToTableContext($clear);
3729
3730 /* Pop the current node from the stack of open elements. Switch
3731 the insertion mode to "in table". */
3732 array_pop($this->stack);
3733 $this->mode = self::IN_TABLE;
3734 }
3735
3736 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3737 "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
3738 } elseif (($token['type'] === HTML5::STARTTAG && in_array(
3739 $token['name'],
3740 array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead')
3741 )) ||
3742 ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')
3743 ) {
3744 /* If the stack of open elements does not have a tbody, thead, or
3745 tfoot element in table scope, this is a parse error. Ignore the
3746 token. (innerHTML case) */
3747 if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
3748 // Ignore.
3749
3750 /* Otherwise: */
3751 } else {
3752 /* Clear the stack back to a table body context. */
3753 $this->clearStackToTableContext($clear);
3754
3755 /* Act as if an end tag with the same tag name as the current
3756 node ("tbody", "tfoot", or "thead") had been seen, then
3757 reprocess the current token. */
3758 $this->inTableBody(
3759 array(
3760 'name' => end($this->stack)->nodeName,
3761 'type' => HTML5::ENDTAG
3762 )
3763 );
3764
3765 return $this->mainPhase($token);
3766 }
3767
3768 /* An end tag whose tag name is one of: "body", "caption", "col",
3769 "colgroup", "html", "td", "th", "tr" */
3770 } elseif ($token['type'] === HTML5::ENDTAG && in_array(
3771 $token['name'],
3772 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr')
3773 )
3774 ) {
3775 /* Parse error. Ignore the token. */
3776
3777 /* Anything else */
3778 } else {
3779 /* Process the token as if the insertion mode was "in table". */
3780 $this->inTable($token);
3781 }
3782 }

References clearStackToTableContext(), elementInScope(), HTML5\ENDTAG, IN_ROW, IN_TABLE, inRow(), insertElement(), inTable(), inTableBody(), mainPhase(), and HTML5\STARTTAG.

Referenced by inTable(), inTableBody(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inTableBody() [2/2]

HTML5TreeConstructer::inTableBody (   $token)
private

Definition at line 2909 of file PH5P.php.

2910 {
2911 $clear = array('tbody', 'tfoot', 'thead', 'html');
2912
2913 /* A start tag whose tag name is "tr" */
2914 if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') {
2915 /* Clear the stack back to a table body context. */
2916 $this->clearStackToTableContext($clear);
2917
2918 /* Insert a tr element for the token, then switch the insertion
2919 mode to "in row". */
2920 $this->insertElement($token);
2921 $this->mode = self::IN_ROW;
2922
2923 /* A start tag whose tag name is one of: "th", "td" */
2924 } elseif($token['type'] === HTML5::STARTTAG &&
2925 ($token['name'] === 'th' || $token['name'] === 'td')) {
2926 /* Parse error. Act as if a start tag with the tag name "tr" had
2927 been seen, then reprocess the current token. */
2928 $this->inTableBody(array(
2929 'name' => 'tr',
2930 'type' => HTML5::STARTTAG,
2931 'attr' => array()
2932 ));
2933
2934 return $this->inRow($token);
2935
2936 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
2937 } elseif($token['type'] === HTML5::ENDTAG &&
2938 in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
2939 /* If the stack of open elements does not have an element in table
2940 scope with the same tag name as the token, this is a parse error.
2941 Ignore the token. */
2942 if(!$this->elementInScope($token['name'], true)) {
2943 // Ignore
2944
2945 /* Otherwise: */
2946 } else {
2947 /* Clear the stack back to a table body context. */
2948 $this->clearStackToTableContext($clear);
2949
2950 /* Pop the current node from the stack of open elements. Switch
2951 the insertion mode to "in table". */
2952 array_pop($this->stack);
2953 $this->mode = self::IN_TABLE;
2954 }
2955
2956 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2957 "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
2958 } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2959 array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) ||
2960 ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) {
2961 /* If the stack of open elements does not have a tbody, thead, or
2962 tfoot element in table scope, this is a parse error. Ignore the
2963 token. (innerHTML case) */
2964 if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
2965 // Ignore.
2966
2967 /* Otherwise: */
2968 } else {
2969 /* Clear the stack back to a table body context. */
2970 $this->clearStackToTableContext($clear);
2971
2972 /* Act as if an end tag with the same tag name as the current
2973 node ("tbody", "tfoot", or "thead") had been seen, then
2974 reprocess the current token. */
2975 $this->inTableBody(array(
2976 'name' => end($this->stack)->nodeName,
2977 'type' => HTML5::ENDTAG
2978 ));
2979
2980 return $this->mainPhase($token);
2981 }
2982
2983 /* An end tag whose tag name is one of: "body", "caption", "col",
2984 "colgroup", "html", "td", "th", "tr" */
2985 } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
2986 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
2987 /* Parse error. Ignore the token. */
2988
2989 /* Anything else */
2990 } else {
2991 /* Process the token as if the insertion mode was "in table". */
2992 $this->inTable($token);
2993 }
2994 }

References clearStackToTableContext(), elementInScope(), HTML5\ENDTAG, IN_ROW, IN_TABLE, inRow(), insertElement(), inTable(), inTableBody(), mainPhase(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ mainPhase() [1/2]

HTML5TreeConstructer::mainPhase (   $token)
private

Definition at line 1836 of file PH5P.php.

1837 {
1838 /* Tokens in the main phase must be handled as follows: */
1839
1840 /* A DOCTYPE token */
1841 if ($token['type'] === HTML5::DOCTYPE) {
1842 // Parse error. Ignore the token.
1843
1844 /* A start tag token with the tag name "html" */
1845 } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') {
1846 /* If this start tag token was not the first start tag token, then
1847 it is a parse error. */
1848
1849 /* For each attribute on the token, check to see if the attribute
1850 is already present on the top element of the stack of open elements.
1851 If it is not, add the attribute and its corresponding value to that
1852 element. */
1853 foreach ($token['attr'] as $attr) {
1854 if (!$this->stack[0]->hasAttribute($attr['name'])) {
1855 $this->stack[0]->setAttribute($attr['name'], $attr['value']);
1856 }
1857 }
1858
1859 /* An end-of-file token */
1860 } elseif ($token['type'] === HTML5::EOF) {
1861 /* Generate implied end tags. */
1862 $this->generateImpliedEndTags();
1863
1864 /* Anything else. */
1865 } else {
1866 /* Depends on the insertion mode: */
1867 switch ($this->mode) {
1868 case self::BEFOR_HEAD:
1869 return $this->beforeHead($token);
1870 break;
1871 case self::IN_HEAD:
1872 return $this->inHead($token);
1873 break;
1874 case self::AFTER_HEAD:
1875 return $this->afterHead($token);
1876 break;
1877 case self::IN_BODY:
1878 return $this->inBody($token);
1879 break;
1880 case self::IN_TABLE:
1881 return $this->inTable($token);
1882 break;
1883 case self::IN_CAPTION:
1884 return $this->inCaption($token);
1885 break;
1886 case self::IN_CGROUP:
1887 return $this->inColumnGroup($token);
1888 break;
1889 case self::IN_TBODY:
1890 return $this->inTableBody($token);
1891 break;
1892 case self::IN_ROW:
1893 return $this->inRow($token);
1894 break;
1895 case self::IN_CELL:
1896 return $this->inCell($token);
1897 break;
1898 case self::IN_SELECT:
1899 return $this->inSelect($token);
1900 break;
1901 case self::AFTER_BODY:
1902 return $this->afterBody($token);
1903 break;
1904 case self::IN_FRAME:
1905 return $this->inFrameset($token);
1906 break;
1907 case self::AFTR_FRAME:
1908 return $this->afterFrameset($token);
1909 break;
1910 case self::END_PHASE:
1911 return $this->trailingEndPhase($token);
1912 break;
1913 }
1914 }
1915 }
inFrameset($token)
Definition: PH5P.php:4243
afterFrameset($token)
Definition: PH5P.php:4312
const DOCTYPE
Definition: PH5P.php:454

References AFTER_BODY, AFTER_HEAD, afterBody(), afterFrameset(), afterHead(), AFTR_FRAME, BEFOR_HEAD, beforeHead(), HTML5\DOCTYPE, END_PHASE, HTML5\EOF, generateImpliedEndTags(), IN_BODY, IN_CAPTION, IN_CELL, IN_CGROUP, IN_FRAME, IN_HEAD, IN_ROW, IN_SELECT, IN_TABLE, IN_TBODY, inBody(), inCaption(), inCell(), inColumnGroup(), inFrameset(), inHead(), inRow(), inSelect(), inTable(), inTableBody(), HTML5\STARTTAG, and trailingEndPhase().

Referenced by emitToken(), inSelect(), inTable(), inTableBody(), rootElementPhase(), and trailingEndPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mainPhase() [2/2]

HTML5TreeConstructer::mainPhase (   $token)
private

Definition at line 1317 of file PH5P.php.

1318 {
1319 /* Tokens in the main phase must be handled as follows: */
1320
1321 /* A DOCTYPE token */
1322 if($token['type'] === HTML5::DOCTYPE) {
1323 // Parse error. Ignore the token.
1324
1325 /* A start tag token with the tag name "html" */
1326 } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') {
1327 /* If this start tag token was not the first start tag token, then
1328 it is a parse error. */
1329
1330 /* For each attribute on the token, check to see if the attribute
1331 is already present on the top element of the stack of open elements.
1332 If it is not, add the attribute and its corresponding value to that
1333 element. */
1334 foreach($token['attr'] as $attr) {
1335 if(!$this->stack[0]->hasAttribute($attr['name'])) {
1336 $this->stack[0]->setAttribute($attr['name'], $attr['value']);
1337 }
1338 }
1339
1340 /* An end-of-file token */
1341 } elseif($token['type'] === HTML5::EOF) {
1342 /* Generate implied end tags. */
1343 $this->generateImpliedEndTags();
1344
1345 /* Anything else. */
1346 } else {
1347 /* Depends on the insertion mode: */
1348 switch($this->mode) {
1349 case self::BEFOR_HEAD: return $this->beforeHead($token); break;
1350 case self::IN_HEAD: return $this->inHead($token); break;
1351 case self::AFTER_HEAD: return $this->afterHead($token); break;
1352 case self::IN_BODY: return $this->inBody($token); break;
1353 case self::IN_TABLE: return $this->inTable($token); break;
1354 case self::IN_CAPTION: return $this->inCaption($token); break;
1355 case self::IN_CGROUP: return $this->inColumnGroup($token); break;
1356 case self::IN_TBODY: return $this->inTableBody($token); break;
1357 case self::IN_ROW: return $this->inRow($token); break;
1358 case self::IN_CELL: return $this->inCell($token); break;
1359 case self::IN_SELECT: return $this->inSelect($token); break;
1360 case self::AFTER_BODY: return $this->afterBody($token); break;
1361 case self::IN_FRAME: return $this->inFrameset($token); break;
1362 case self::AFTR_FRAME: return $this->afterFrameset($token); break;
1363 case self::END_PHASE: return $this->trailingEndPhase($token); break;
1364 }
1365 }
1366 }

References AFTER_BODY, AFTER_HEAD, afterBody(), afterFrameset(), afterHead(), AFTR_FRAME, BEFOR_HEAD, beforeHead(), HTML5\DOCTYPE, END_PHASE, HTML5\EOF, generateImpliedEndTags(), IN_BODY, IN_CAPTION, IN_CELL, IN_CGROUP, IN_FRAME, IN_HEAD, IN_ROW, IN_SELECT, IN_TABLE, IN_TBODY, inBody(), inCaption(), inCell(), inColumnGroup(), inFrameset(), inHead(), inRow(), inSelect(), inTable(), inTableBody(), HTML5\STARTTAG, and trailingEndPhase().

+ Here is the call graph for this function:

◆ reconstructActiveFormattingElements() [1/2]

HTML5TreeConstructer::reconstructActiveFormattingElements ( )
private

Definition at line 4526 of file PH5P.php.

4527 {
4528 /* 1. If there are no entries in the list of active formatting elements,
4529 then there is nothing to reconstruct; stop this algorithm. */
4530 $formatting_elements = count($this->a_formatting);
4531
4532 if ($formatting_elements === 0) {
4533 return false;
4534 }
4535
4536 /* 3. Let entry be the last (most recently added) element in the list
4537 of active formatting elements. */
4538 $entry = end($this->a_formatting);
4539
4540 /* 2. If the last (most recently added) entry in the list of active
4541 formatting elements is a marker, or if it is an element that is in the
4542 stack of open elements, then there is nothing to reconstruct; stop this
4543 algorithm. */
4544 if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
4545 return false;
4546 }
4547
4548 for ($a = $formatting_elements - 1; $a >= 0; true) {
4549 /* 4. If there are no entries before entry in the list of active
4550 formatting elements, then jump to step 8. */
4551 if ($a === 0) {
4552 $step_seven = false;
4553 break;
4554 }
4555
4556 /* 5. Let entry be the entry one earlier than entry in the list of
4557 active formatting elements. */
4558 $a--;
4559 $entry = $this->a_formatting[$a];
4560
4561 /* 6. If entry is neither a marker nor an element that is also in
4562 thetack of open elements, go to step 4. */
4563 if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
4564 break;
4565 }
4566 }
4567
4568 while (true) {
4569 /* 7. Let entry be the element one later than entry in the list of
4570 active formatting elements. */
4571 if (isset($step_seven) && $step_seven === true) {
4572 $a++;
4573 $entry = $this->a_formatting[$a];
4574 }
4575
4576 /* 8. Perform a shallow clone of the element entry to obtain clone. */
4577 $clone = $entry->cloneNode();
4578
4579 /* 9. Append clone to the current node and push it onto the stack
4580 of open elements so that it is the new current node. */
4581 end($this->stack)->appendChild($clone);
4582 $this->stack[] = $clone;
4583
4584 /* 10. Replace the entry for entry in the list with an entry for
4585 clone. */
4586 $this->a_formatting[$a] = $clone;
4587
4588 /* 11. If the entry for clone in the list of active formatting
4589 elements is not the last entry in the list, return to step 7. */
4590 if (end($this->a_formatting) !== $clone) {
4591 $step_seven = true;
4592 } else {
4593 break;
4594 }
4595 }
4596 }

Referenced by inBody().

+ Here is the caller graph for this function:

◆ reconstructActiveFormattingElements() [2/2]

HTML5TreeConstructer::reconstructActiveFormattingElements ( )
private

Definition at line 3628 of file PH5P.php.

3629 {
3630 /* 1. If there are no entries in the list of active formatting elements,
3631 then there is nothing to reconstruct; stop this algorithm. */
3632 $formatting_elements = count($this->a_formatting);
3633
3634 if($formatting_elements === 0) {
3635 return false;
3636 }
3637
3638 /* 3. Let entry be the last (most recently added) element in the list
3639 of active formatting elements. */
3640 $entry = end($this->a_formatting);
3641
3642 /* 2. If the last (most recently added) entry in the list of active
3643 formatting elements is a marker, or if it is an element that is in the
3644 stack of open elements, then there is nothing to reconstruct; stop this
3645 algorithm. */
3646 if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3647 return false;
3648 }
3649
3650 for($a = $formatting_elements - 1; $a >= 0; true) {
3651 /* 4. If there are no entries before entry in the list of active
3652 formatting elements, then jump to step 8. */
3653 if($a === 0) {
3654 $step_seven = false;
3655 break;
3656 }
3657
3658 /* 5. Let entry be the entry one earlier than entry in the list of
3659 active formatting elements. */
3660 $a--;
3661 $entry = $this->a_formatting[$a];
3662
3663 /* 6. If entry is neither a marker nor an element that is also in
3664 thetack of open elements, go to step 4. */
3665 if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3666 break;
3667 }
3668 }
3669
3670 while(true) {
3671 /* 7. Let entry be the element one later than entry in the list of
3672 active formatting elements. */
3673 if(isset($step_seven) && $step_seven === true) {
3674 $a++;
3675 $entry = $this->a_formatting[$a];
3676 }
3677
3678 /* 8. Perform a shallow clone of the element entry to obtain clone. */
3679 $clone = $entry->cloneNode();
3680
3681 /* 9. Append clone to the current node and push it onto the stack
3682 of open elements so that it is the new current node. */
3683 end($this->stack)->appendChild($clone);
3684 $this->stack[] = $clone;
3685
3686 /* 10. Replace the entry for entry in the list with an entry for
3687 clone. */
3688 $this->a_formatting[$a] = $clone;
3689
3690 /* 11. If the entry for clone in the list of active formatting
3691 elements is not the last entry in the list, return to step 7. */
3692 if(end($this->a_formatting) !== $clone) {
3693 $step_seven = true;
3694 } else {
3695 break;
3696 }
3697 }
3698 }

◆ resetInsertionMode() [1/2]

HTML5TreeConstructer::resetInsertionMode ( )
private

Definition at line 4667 of file PH5P.php.

4668 {
4669 /* 1. Let last be false. */
4670 $last = false;
4671 $leng = count($this->stack);
4672
4673 for ($n = $leng - 1; $n >= 0; $n--) {
4674 /* 2. Let node be the last node in the stack of open elements. */
4675 $node = $this->stack[$n];
4676
4677 /* 3. If node is the first node in the stack of open elements, then
4678 set last to true. If the element whose innerHTML attribute is being
4679 set is neither a td element nor a th element, then set node to the
4680 element whose innerHTML attribute is being set. (innerHTML case) */
4681 if ($this->stack[0]->isSameNode($node)) {
4682 $last = true;
4683 }
4684
4685 /* 4. If node is a select element, then switch the insertion mode to
4686 "in select" and abort these steps. (innerHTML case) */
4687 if ($node->nodeName === 'select') {
4688 $this->mode = self::IN_SELECT;
4689 break;
4690
4691 /* 5. If node is a td or th element, then switch the insertion mode
4692 to "in cell" and abort these steps. */
4693 } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') {
4694 $this->mode = self::IN_CELL;
4695 break;
4696
4697 /* 6. If node is a tr element, then switch the insertion mode to
4698 "in row" and abort these steps. */
4699 } elseif ($node->nodeName === 'tr') {
4700 $this->mode = self::IN_ROW;
4701 break;
4702
4703 /* 7. If node is a tbody, thead, or tfoot element, then switch the
4704 insertion mode to "in table body" and abort these steps. */
4705 } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) {
4706 $this->mode = self::IN_TBODY;
4707 break;
4708
4709 /* 8. If node is a caption element, then switch the insertion mode
4710 to "in caption" and abort these steps. */
4711 } elseif ($node->nodeName === 'caption') {
4712 $this->mode = self::IN_CAPTION;
4713 break;
4714
4715 /* 9. If node is a colgroup element, then switch the insertion mode
4716 to "in column group" and abort these steps. (innerHTML case) */
4717 } elseif ($node->nodeName === 'colgroup') {
4718 $this->mode = self::IN_CGROUP;
4719 break;
4720
4721 /* 10. If node is a table element, then switch the insertion mode
4722 to "in table" and abort these steps. */
4723 } elseif ($node->nodeName === 'table') {
4724 $this->mode = self::IN_TABLE;
4725 break;
4726
4727 /* 11. If node is a head element, then switch the insertion mode
4728 to "in body" ("in body"! not "in head"!) and abort these steps.
4729 (innerHTML case) */
4730 } elseif ($node->nodeName === 'head') {
4731 $this->mode = self::IN_BODY;
4732 break;
4733
4734 /* 12. If node is a body element, then switch the insertion mode to
4735 "in body" and abort these steps. */
4736 } elseif ($node->nodeName === 'body') {
4737 $this->mode = self::IN_BODY;
4738 break;
4739
4740 /* 13. If node is a frameset element, then switch the insertion
4741 mode to "in frameset" and abort these steps. (innerHTML case) */
4742 } elseif ($node->nodeName === 'frameset') {
4743 $this->mode = self::IN_FRAME;
4744 break;
4745
4746 /* 14. If node is an html element, then: if the head element
4747 pointer is null, switch the insertion mode to "before head",
4748 otherwise, switch the insertion mode to "after head". In either
4749 case, abort these steps. (innerHTML case) */
4750 } elseif ($node->nodeName === 'html') {
4751 $this->mode = ($this->head_pointer === null)
4752 ? self::BEFOR_HEAD
4753 : self::AFTER_HEAD;
4754
4755 break;
4756
4757 /* 15. If last is true, then set the insertion mode to "in body"
4758 and abort these steps. (innerHTML case) */
4759 } elseif ($last) {
4760 $this->mode = self::IN_BODY;
4761 break;
4762 }
4763 }
4764 }

References $n, IN_BODY, IN_CAPTION, IN_CELL, IN_CGROUP, IN_FRAME, IN_ROW, IN_SELECT, IN_TABLE, and IN_TBODY.

Referenced by inSelect(), and inTable().

+ Here is the caller graph for this function:

◆ resetInsertionMode() [2/2]

HTML5TreeConstructer::resetInsertionMode ( )
private

Definition at line 3770 of file PH5P.php.

3771 {
3772 /* 1. Let last be false. */
3773 $last = false;
3774 $leng = count($this->stack);
3775
3776 for($n = $leng - 1; $n >= 0; $n--) {
3777 /* 2. Let node be the last node in the stack of open elements. */
3778 $node = $this->stack[$n];
3779
3780 /* 3. If node is the first node in the stack of open elements, then
3781 set last to true. If the element whose innerHTML attribute is being
3782 set is neither a td element nor a th element, then set node to the
3783 element whose innerHTML attribute is being set. (innerHTML case) */
3784 if($this->stack[0]->isSameNode($node)) {
3785 $last = true;
3786 }
3787
3788 /* 4. If node is a select element, then switch the insertion mode to
3789 "in select" and abort these steps. (innerHTML case) */
3790 if($node->nodeName === 'select') {
3791 $this->mode = self::IN_SELECT;
3792 break;
3793
3794 /* 5. If node is a td or th element, then switch the insertion mode
3795 to "in cell" and abort these steps. */
3796 } elseif($node->nodeName === 'td' || $node->nodeName === 'th') {
3797 $this->mode = self::IN_CELL;
3798 break;
3799
3800 /* 6. If node is a tr element, then switch the insertion mode to
3801 "in row" and abort these steps. */
3802 } elseif($node->nodeName === 'tr') {
3803 $this->mode = self::IN_ROW;
3804 break;
3805
3806 /* 7. If node is a tbody, thead, or tfoot element, then switch the
3807 insertion mode to "in table body" and abort these steps. */
3808 } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) {
3809 $this->mode = self::IN_TBODY;
3810 break;
3811
3812 /* 8. If node is a caption element, then switch the insertion mode
3813 to "in caption" and abort these steps. */
3814 } elseif($node->nodeName === 'caption') {
3815 $this->mode = self::IN_CAPTION;
3816 break;
3817
3818 /* 9. If node is a colgroup element, then switch the insertion mode
3819 to "in column group" and abort these steps. (innerHTML case) */
3820 } elseif($node->nodeName === 'colgroup') {
3821 $this->mode = self::IN_CGROUP;
3822 break;
3823
3824 /* 10. If node is a table element, then switch the insertion mode
3825 to "in table" and abort these steps. */
3826 } elseif($node->nodeName === 'table') {
3827 $this->mode = self::IN_TABLE;
3828 break;
3829
3830 /* 11. If node is a head element, then switch the insertion mode
3831 to "in body" ("in body"! not "in head"!) and abort these steps.
3832 (innerHTML case) */
3833 } elseif($node->nodeName === 'head') {
3834 $this->mode = self::IN_BODY;
3835 break;
3836
3837 /* 12. If node is a body element, then switch the insertion mode to
3838 "in body" and abort these steps. */
3839 } elseif($node->nodeName === 'body') {
3840 $this->mode = self::IN_BODY;
3841 break;
3842
3843 /* 13. If node is a frameset element, then switch the insertion
3844 mode to "in frameset" and abort these steps. (innerHTML case) */
3845 } elseif($node->nodeName === 'frameset') {
3846 $this->mode = self::IN_FRAME;
3847 break;
3848
3849 /* 14. If node is an html element, then: if the head element
3850 pointer is null, switch the insertion mode to "before head",
3851 otherwise, switch the insertion mode to "after head". In either
3852 case, abort these steps. (innerHTML case) */
3853 } elseif($node->nodeName === 'html') {
3854 $this->mode = ($this->head_pointer === null)
3855 ? self::BEFOR_HEAD
3856 : self::AFTER_HEAD;
3857
3858 break;
3859
3860 /* 15. If last is true, then set the insertion mode to "in body"
3861 and abort these steps. (innerHTML case) */
3862 } elseif($last) {
3863 $this->mode = self::IN_BODY;
3864 break;
3865 }
3866 }
3867 }

References $n, IN_BODY, IN_CAPTION, IN_CELL, IN_CGROUP, IN_FRAME, IN_ROW, IN_SELECT, IN_TABLE, and IN_TBODY.

◆ rootElementPhase() [1/2]

HTML5TreeConstructer::rootElementPhase (   $token)
private

Definition at line 1786 of file PH5P.php.

1787 {
1788 /* After the initial phase, as each token is emitted from the tokenisation
1789 stage, it must be processed as described in this section. */
1790
1791 /* A DOCTYPE token */
1792 if ($token['type'] === HTML5::DOCTYPE) {
1793 // Parse error. Ignore the token.
1794
1795 /* A comment token */
1796 } elseif ($token['type'] === HTML5::COMMENT) {
1797 /* Append a Comment node to the Document object with the data
1798 attribute set to the data given in the comment token. */
1799 $comment = $this->dom->createComment($token['data']);
1800 $this->dom->appendChild($comment);
1801
1802 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1803 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1804 or U+0020 SPACE */
1805 } elseif ($token['type'] === HTML5::CHARACTR &&
1806 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
1807 ) {
1808 /* Append that character to the Document node. */
1809 $text = $this->dom->createTextNode($token['data']);
1810 $this->dom->appendChild($text);
1811
1812 /* A character token that is not one of U+0009 CHARACTER TABULATION,
1813 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED
1814 (FF), or U+0020 SPACE
1815 A start tag token
1816 An end tag token
1817 An end-of-file token */
1818 } elseif (($token['type'] === HTML5::CHARACTR &&
1819 !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
1820 $token['type'] === HTML5::STARTTAG ||
1821 $token['type'] === HTML5::ENDTAG ||
1822 $token['type'] === HTML5::EOF
1823 ) {
1824 /* Create an HTMLElement node with the tag name html, in the HTML
1825 namespace. Append it to the Document object. Switch to the main
1826 phase and reprocess the current token. */
1827 $html = $this->dom->createElement('html');
1828 $this->dom->appendChild($html);
1829 $this->stack[] = $html;
1830
1831 $this->phase = self::MAIN_PHASE;
1832 return $this->mainPhase($token);
1833 }
1834 }
$html
Definition: example_001.php:87

References $comment, $html, $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF, MAIN_PHASE, mainPhase(), and HTML5\STARTTAG.

Referenced by emitToken(), and initPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rootElementPhase() [2/2]

HTML5TreeConstructer::rootElementPhase (   $token)
private

Definition at line 1269 of file PH5P.php.

1270 {
1271 /* After the initial phase, as each token is emitted from the tokenisation
1272 stage, it must be processed as described in this section. */
1273
1274 /* A DOCTYPE token */
1275 if($token['type'] === HTML5::DOCTYPE) {
1276 // Parse error. Ignore the token.
1277
1278 /* A comment token */
1279 } elseif($token['type'] === HTML5::COMMENT) {
1280 /* Append a Comment node to the Document object with the data
1281 attribute set to the data given in the comment token. */
1282 $comment = $this->dom->createComment($token['data']);
1283 $this->dom->appendChild($comment);
1284
1285 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1286 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1287 or U+0020 SPACE */
1288 } elseif($token['type'] === HTML5::CHARACTR &&
1289 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1290 /* Append that character to the Document node. */
1291 $text = $this->dom->createTextNode($token['data']);
1292 $this->dom->appendChild($text);
1293
1294 /* A character token that is not one of U+0009 CHARACTER TABULATION,
1295 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED
1296 (FF), or U+0020 SPACE
1297 A start tag token
1298 An end tag token
1299 An end-of-file token */
1300 } elseif(($token['type'] === HTML5::CHARACTR &&
1301 !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
1302 $token['type'] === HTML5::STARTTAG ||
1303 $token['type'] === HTML5::ENDTAG ||
1304 $token['type'] === HTML5::EOF) {
1305 /* Create an HTMLElement node with the tag name html, in the HTML
1306 namespace. Append it to the Document object. Switch to the main
1307 phase and reprocess the current token. */
1308 $html = $this->dom->createElement('html');
1309 $this->dom->appendChild($html);
1310 $this->stack[] = $html;
1311
1312 $this->phase = self::MAIN_PHASE;
1313 return $this->mainPhase($token);
1314 }
1315 }

References $comment, $html, $text, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF, MAIN_PHASE, mainPhase(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

◆ save() [1/2]

HTML5TreeConstructer::save ( )

Definition at line 4784 of file PH5P.php.

4785 {
4786 return $this->dom;
4787 }

References $dom.

◆ save() [2/2]

HTML5TreeConstructer::save ( )

Definition at line 3885 of file PH5P.php.

3886 {
3887 return $this->dom;
3888 }

References $dom.

◆ trailingEndPhase() [1/2]

HTML5TreeConstructer::trailingEndPhase (   $token)
private

Definition at line 4351 of file PH5P.php.

4352 {
4353 /* After the main phase, as each token is emitted from the tokenisation
4354 stage, it must be processed as described in this section. */
4355
4356 /* A DOCTYPE token */
4357 if ($token['type'] === HTML5::DOCTYPE) {
4358 // Parse error. Ignore the token.
4359
4360 /* A comment token */
4361 } elseif ($token['type'] === HTML5::COMMENT) {
4362 /* Append a Comment node to the Document object with the data
4363 attribute set to the data given in the comment token. */
4364 $comment = $this->dom->createComment($token['data']);
4365 $this->dom->appendChild($comment);
4366
4367 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
4368 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
4369 or U+0020 SPACE */
4370 } elseif ($token['type'] === HTML5::CHARACTR &&
4371 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
4372 ) {
4373 /* Process the token as it would be processed in the main phase. */
4374 $this->mainPhase($token);
4375
4376 /* A character token that is not one of U+0009 CHARACTER TABULATION,
4377 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
4378 or U+0020 SPACE. Or a start tag token. Or an end tag token. */
4379 } elseif (($token['type'] === HTML5::CHARACTR &&
4380 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
4381 $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG
4382 ) {
4383 /* Parse error. Switch back to the main phase and reprocess the
4384 token. */
4385 $this->phase = self::MAIN_PHASE;
4386 return $this->mainPhase($token);
4387
4388 /* An end-of-file token */
4389 } elseif ($token['type'] === HTML5::EOF) {
4390 /* OMG DONE!! */
4391 }
4392 }

References $comment, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF, MAIN_PHASE, mainPhase(), and HTML5\STARTTAG.

Referenced by emitToken(), and mainPhase().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ trailingEndPhase() [2/2]

HTML5TreeConstructer::trailingEndPhase (   $token)
private

Definition at line 3480 of file PH5P.php.

3481 {
3482 /* After the main phase, as each token is emitted from the tokenisation
3483 stage, it must be processed as described in this section. */
3484
3485 /* A DOCTYPE token */
3486 if($token['type'] === HTML5::DOCTYPE) {
3487 // Parse error. Ignore the token.
3488
3489 /* A comment token */
3490 } elseif($token['type'] === HTML5::COMMENT) {
3491 /* Append a Comment node to the Document object with the data
3492 attribute set to the data given in the comment token. */
3493 $comment = $this->dom->createComment($token['data']);
3494 $this->dom->appendChild($comment);
3495
3496 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3497 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3498 or U+0020 SPACE */
3499 } elseif($token['type'] === HTML5::CHARACTR &&
3500 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3501 /* Process the token as it would be processed in the main phase. */
3502 $this->mainPhase($token);
3503
3504 /* A character token that is not one of U+0009 CHARACTER TABULATION,
3505 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3506 or U+0020 SPACE. Or a start tag token. Or an end tag token. */
3507 } elseif(($token['type'] === HTML5::CHARACTR &&
3508 preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
3509 $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) {
3510 /* Parse error. Switch back to the main phase and reprocess the
3511 token. */
3512 $this->phase = self::MAIN_PHASE;
3513 return $this->mainPhase($token);
3514
3515 /* An end-of-file token */
3516 } elseif($token['type'] === HTML5::EOF) {
3517 /* OMG DONE!! */
3518 }
3519 }

References $comment, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF, MAIN_PHASE, mainPhase(), and HTML5\STARTTAG.

+ Here is the call graph for this function:

Field Documentation

◆ $a_formatting

HTML5TreeConstructer::$a_formatting = array()
private

Definition at line 1585 of file PH5P.php.

◆ $dom

HTML5TreeConstructer::$dom
private

Definition at line 1583 of file PH5P.php.

Referenced by save().

◆ $form_pointer

HTML5TreeConstructer::$form_pointer = null
private

Definition at line 1588 of file PH5P.php.

◆ $formatting

HTML5TreeConstructer::$formatting
private
Initial value:
= array(
'a',
'b',
'big',
'em',
'font',
'i',
'nobr',
's',
'small',
'strike',
'strong',
'tt',
'u'
)

Definition at line 1591 of file PH5P.php.

◆ $foster_parent

HTML5TreeConstructer::$foster_parent = null
private

Definition at line 1584 of file PH5P.php.

◆ $head_pointer

HTML5TreeConstructer::$head_pointer = null
private

Definition at line 1587 of file PH5P.php.

◆ $mode

HTML5TreeConstructer::$mode
private

Definition at line 1582 of file PH5P.php.

◆ $phase

HTML5TreeConstructer::$phase
private

Definition at line 1581 of file PH5P.php.

◆ $scoping

HTML5TreeConstructer::$scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th')
private

Definition at line 1590 of file PH5P.php.

◆ $special

HTML5TreeConstructer::$special
private

Definition at line 1606 of file PH5P.php.

◆ $stack

HTML5TreeConstructer::$stack = array()

Definition at line 1579 of file PH5P.php.

◆ AFTER_BODY

const HTML5TreeConstructer::AFTER_BODY = 11

Definition at line 1688 of file PH5P.php.

Referenced by inBody(), and mainPhase().

◆ AFTER_HEAD

const HTML5TreeConstructer::AFTER_HEAD = 2

Definition at line 1679 of file PH5P.php.

Referenced by inHead(), and mainPhase().

◆ AFTR_FRAME

const HTML5TreeConstructer::AFTR_FRAME = 13

Definition at line 1690 of file PH5P.php.

Referenced by inFrameset(), and mainPhase().

◆ BEFOR_HEAD

const HTML5TreeConstructer::BEFOR_HEAD = 0

Definition at line 1677 of file PH5P.php.

Referenced by __construct(), and mainPhase().

◆ END_PHASE

const HTML5TreeConstructer::END_PHASE = 3

Definition at line 1674 of file PH5P.php.

Referenced by afterBody(), afterFrameset(), emitToken(), and mainPhase().

◆ FORMATTING

const HTML5TreeConstructer::FORMATTING = 2

Definition at line 1695 of file PH5P.php.

Referenced by getElementCategory().

◆ IN_BODY

const HTML5TreeConstructer::IN_BODY = 3

Definition at line 1680 of file PH5P.php.

Referenced by afterBody(), afterHead(), mainPhase(), and resetInsertionMode().

◆ IN_CAPTION

const HTML5TreeConstructer::IN_CAPTION = 5

Definition at line 1682 of file PH5P.php.

Referenced by inTable(), mainPhase(), and resetInsertionMode().

◆ IN_CELL

const HTML5TreeConstructer::IN_CELL = 9

Definition at line 1686 of file PH5P.php.

Referenced by inRow(), mainPhase(), and resetInsertionMode().

◆ IN_CGROUP

const HTML5TreeConstructer::IN_CGROUP = 6

Definition at line 1683 of file PH5P.php.

Referenced by inTable(), mainPhase(), and resetInsertionMode().

◆ IN_FRAME

const HTML5TreeConstructer::IN_FRAME = 12

Definition at line 1689 of file PH5P.php.

Referenced by afterHead(), mainPhase(), and resetInsertionMode().

◆ IN_HEAD

const HTML5TreeConstructer::IN_HEAD = 1

Definition at line 1678 of file PH5P.php.

Referenced by afterHead(), beforeHead(), and mainPhase().

◆ IN_ROW

const HTML5TreeConstructer::IN_ROW = 8

Definition at line 1685 of file PH5P.php.

Referenced by inCell(), inTableBody(), mainPhase(), and resetInsertionMode().

◆ IN_SELECT

const HTML5TreeConstructer::IN_SELECT = 10

Definition at line 1687 of file PH5P.php.

Referenced by inBody(), mainPhase(), and resetInsertionMode().

◆ IN_TABLE

const HTML5TreeConstructer::IN_TABLE = 4

Definition at line 1681 of file PH5P.php.

Referenced by inBody(), inCaption(), inColumnGroup(), inTableBody(), mainPhase(), and resetInsertionMode().

◆ IN_TBODY

const HTML5TreeConstructer::IN_TBODY = 7

Definition at line 1684 of file PH5P.php.

Referenced by inRow(), inTable(), mainPhase(), and resetInsertionMode().

◆ INIT_PHASE

const HTML5TreeConstructer::INIT_PHASE = 0

Definition at line 1671 of file PH5P.php.

Referenced by __construct(), and emitToken().

◆ MAIN_PHASE

const HTML5TreeConstructer::MAIN_PHASE = 2

Definition at line 1673 of file PH5P.php.

Referenced by emitToken(), rootElementPhase(), and trailingEndPhase().

◆ MARKER

const HTML5TreeConstructer::MARKER = 0

Definition at line 1698 of file PH5P.php.

Referenced by inBody(), inRow(), and inTable().

◆ PHRASING

const HTML5TreeConstructer::PHRASING = 3

Definition at line 1696 of file PH5P.php.

Referenced by getElementCategory().

◆ ROOT_PHASE

const HTML5TreeConstructer::ROOT_PHASE = 1

Definition at line 1672 of file PH5P.php.

Referenced by emitToken(), and initPhase().

◆ SCOPING

const HTML5TreeConstructer::SCOPING = 1

Definition at line 1694 of file PH5P.php.

Referenced by getElementCategory().

◆ SPECIAL

const HTML5TreeConstructer::SPECIAL = 0

Definition at line 1693 of file PH5P.php.

Referenced by getElementCategory().


The documentation for this class was generated from the following files: