ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 1576 of file PH5P.php.

Constructor & Destructor Documentation

◆ __construct() [1/2]

HTML5TreeConstructer::__construct ( )

Definition at line 1699 of file PH5P.php.

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

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 4201 of file PH5P.php.

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

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

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

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 4434 of file PH5P.php.

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

References $n.

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.

◆ beforeHead() [1/2]

HTML5TreeConstructer::beforeHead (   $token)
private

Definition at line 1916 of file PH5P.php.

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

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 4648 of file PH5P.php.

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

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 4597 of file PH5P.php.

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

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 4765 of file PH5P.php.

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

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 4465 of file PH5P.php.

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

References $n, 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, and elementInScope().

+ Here is the call graph for this function:

◆ emitToken() [1/2]

HTML5TreeConstructer::emitToken (   $token)

Definition at line 1712 of file PH5P.php.

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

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 4619 of file PH5P.php.

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

References FORMATTING, PHRASING, SCOPING, and SPECIAL.

◆ getElementCategory() [2/2]

HTML5TreeConstructer::getElementCategory (   $node)
private

Definition at line 4634 of file PH5P.php.

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

References 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 2175 of file PH5P.php.

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

References $n, $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, $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 3527 of file PH5P.php.

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

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 3881 of file PH5P.php.

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

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 3622 of file PH5P.php.

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

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 4242 of file PH5P.php.

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

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 1977 of file PH5P.php.

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

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

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

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 4020 of file PH5P.php.

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

References 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 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 4428 of file PH5P.php.

4429 {
4430 $comment = $this->dom->createComment($data);
4432 }
appendToRealParent($node)
Definition: PH5P.php:4434

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 4393 of file PH5P.php.

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

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 4422 of file PH5P.php.

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

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 3315 of file PH5P.php.

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

References $comment, $n, $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, $n, $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 3684 of file PH5P.php.

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

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 1835 of file PH5P.php.

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

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

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 4666 of file PH5P.php.

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

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 1785 of file PH5P.php.

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

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

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 4350 of file PH5P.php.

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

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 1584 of file PH5P.php.

◆ $dom

HTML5TreeConstructer::$dom
private

Definition at line 1582 of file PH5P.php.

Referenced by save().

◆ $form_pointer

HTML5TreeConstructer::$form_pointer = null
private

Definition at line 1587 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 1590 of file PH5P.php.

◆ $foster_parent

HTML5TreeConstructer::$foster_parent = null
private

Definition at line 1583 of file PH5P.php.

◆ $head_pointer

HTML5TreeConstructer::$head_pointer = null
private

Definition at line 1586 of file PH5P.php.

◆ $mode

HTML5TreeConstructer::$mode
private

Definition at line 1581 of file PH5P.php.

◆ $phase

HTML5TreeConstructer::$phase
private

Definition at line 1580 of file PH5P.php.

◆ $scoping

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

Definition at line 1589 of file PH5P.php.

◆ $special

HTML5TreeConstructer::$special
private

Definition at line 1605 of file PH5P.php.

◆ $stack

HTML5TreeConstructer::$stack = array()

Definition at line 1578 of file PH5P.php.

◆ AFTER_BODY

const HTML5TreeConstructer::AFTER_BODY = 11

Definition at line 1687 of file PH5P.php.

Referenced by inBody(), and mainPhase().

◆ AFTER_HEAD

const HTML5TreeConstructer::AFTER_HEAD = 2

Definition at line 1678 of file PH5P.php.

Referenced by inHead(), and mainPhase().

◆ AFTR_FRAME

const HTML5TreeConstructer::AFTR_FRAME = 13

Definition at line 1689 of file PH5P.php.

Referenced by inFrameset(), and mainPhase().

◆ BEFOR_HEAD

const HTML5TreeConstructer::BEFOR_HEAD = 0

Definition at line 1676 of file PH5P.php.

Referenced by __construct(), and mainPhase().

◆ END_PHASE

const HTML5TreeConstructer::END_PHASE = 3

Definition at line 1673 of file PH5P.php.

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

◆ FORMATTING

const HTML5TreeConstructer::FORMATTING = 2

Definition at line 1694 of file PH5P.php.

Referenced by getElementCategory().

◆ IN_BODY

const HTML5TreeConstructer::IN_BODY = 3

Definition at line 1679 of file PH5P.php.

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

◆ IN_CAPTION

const HTML5TreeConstructer::IN_CAPTION = 5

Definition at line 1681 of file PH5P.php.

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

◆ IN_CELL

const HTML5TreeConstructer::IN_CELL = 9

Definition at line 1685 of file PH5P.php.

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

◆ IN_CGROUP

const HTML5TreeConstructer::IN_CGROUP = 6

Definition at line 1682 of file PH5P.php.

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

◆ IN_FRAME

const HTML5TreeConstructer::IN_FRAME = 12

Definition at line 1688 of file PH5P.php.

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

◆ IN_HEAD

const HTML5TreeConstructer::IN_HEAD = 1

Definition at line 1677 of file PH5P.php.

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

◆ IN_ROW

const HTML5TreeConstructer::IN_ROW = 8

Definition at line 1684 of file PH5P.php.

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

◆ IN_SELECT

const HTML5TreeConstructer::IN_SELECT = 10

Definition at line 1686 of file PH5P.php.

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

◆ IN_TABLE

const HTML5TreeConstructer::IN_TABLE = 4

Definition at line 1680 of file PH5P.php.

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

◆ IN_TBODY

const HTML5TreeConstructer::IN_TBODY = 7

Definition at line 1683 of file PH5P.php.

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

◆ INIT_PHASE

const HTML5TreeConstructer::INIT_PHASE = 0

Definition at line 1670 of file PH5P.php.

Referenced by __construct(), and emitToken().

◆ MAIN_PHASE

const HTML5TreeConstructer::MAIN_PHASE = 2

Definition at line 1672 of file PH5P.php.

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

◆ MARKER

const HTML5TreeConstructer::MARKER = 0

Definition at line 1697 of file PH5P.php.

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

◆ PHRASING

const HTML5TreeConstructer::PHRASING = 3

Definition at line 1695 of file PH5P.php.

Referenced by getElementCategory().

◆ ROOT_PHASE

const HTML5TreeConstructer::ROOT_PHASE = 1

Definition at line 1671 of file PH5P.php.

Referenced by emitToken(), and initPhase().

◆ SCOPING

const HTML5TreeConstructer::SCOPING = 1

Definition at line 1693 of file PH5P.php.

Referenced by getElementCategory().

◆ SPECIAL

const HTML5TreeConstructer::SPECIAL = 0

Definition at line 1692 of file PH5P.php.

Referenced by getElementCategory().


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