Browse Source

Fix object reference cycle

split-manual
J. King 3 years ago
parent
commit
2522059fa8
  1. 59
      lib/ActiveFormattingElementsList.php
  2. 91
      lib/TreeBuilder.php

59
lib/ActiveFormattingElementsList.php

@ -17,10 +17,8 @@ namespace dW\HTML5;
class ActiveFormattingElementsList extends Stack {
protected $_storage = [];
protected $stack;
protected $tree;
public function __construct(TreeBuilder $tree, OpenElementsStack $stack) {
$this->tree = $tree;
public function __construct(OpenElementsStack $stack) {
$this->stack = $stack;
}
@ -119,61 +117,6 @@ class ActiveFormattingElementsList extends Stack {
$this[] = new ActiveFormattingElementsMarker;
}
public function reconstruct(): void {
# When the steps below require the UA to reconstruct the active formatting
# elements, the UA must perform the following steps:
# 1. If there are no entries in the list of active formatting elements, then
# there is nothing to reconstruct; stop this algorithm.
if (!$this->_storage) {
return;
}
$last = $this->count - 1;
# 2. If the last (most recently added) entry in the list of active formatting
# elements is a marker, or if it is an element that is in the stack of open
# elements, then there is nothing to reconstruct; stop this algorithm.
$pos = $last;
$entry = $this[$pos];
if ($entry instanceof ActiveFormattingElementsMarker || $this->stack->findSame($entry['element']) > -1) {
return;
}
# 3. Let entry be the last (most recently added) element in the list of
# active formatting elements.
// Already done
while ($pos >= 0) {
# 4. Rewind: If there are no entries before entry in the list of active
# formatting elements, then jump to the step labeled Create.
if ($pos === 0) {
// DEVIATION: Instead don't increment position before breaking, unlike below
break;
}
# 5. Let entry be the entry one earlier than entry in the list of active
# formatting elements.
$entry = $this[--$pos];
# 6. If entry is neither a marker nor an element that is also in the stack of
# open elements, go to the step labeled Rewind.
// Instead break if it is a marker or present in the stack
if ($entry instanceof ActiveFormattingElementsMarker || $this->stack->findSame($entry['element']) > -1) {
// DEVIATION: We increment before breaking to avoid having two loop exit points
$pos++;
break;
}
}
while ($pos <= $last) {
# 7. Advance: Let entry be the element one later than entry in the list of
# active formatting elements.
// DEVIATION: We increment at the end of the loop since we incremented when necessary before breaking out of the earlier loop
$entry = $this[$pos];
# 8. Create: Insert an HTML element for the token for which the element entry
# was created, to obtain new element.
$element = $this->tree->insertStartTagToken($entry['token']);
# 9. Replace the entry for entry in the list with an entry for new element.
$this->_storage[$pos]['element'] = $element;
# 10. If the entry for new element in the list of active formatting elements is
# not the last entry in the list, return to the step labeled Advance.
$pos++;
}
}
public function clearToTheLastMarker(): void {
# When the steps below require the UA to clear the list of active formatting
# elements up to the last marker, the UA must perform the following steps:

91
lib/TreeBuilder.php

@ -238,7 +238,7 @@ class TreeBuilder {
$this->tokenizer = $tokenizer;
$this->data = $data;
$this->errorHandler = $errorHandler;
$this->activeFormattingElementsList = new ActiveFormattingElementsList($this, $stack);
$this->activeFormattingElementsList = new ActiveFormattingElementsList($stack);
$this->tokenList = $tokenList;
# Parsing HTML fragments
@ -1057,14 +1057,14 @@ class TreeBuilder {
# (LF), U+000C FORM FEED (FF), U+000D CARRIAGE RETURN (CR), or U+0020 SPACE
elseif ($token instanceof WhitespaceToken) {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert the token’s character.
$this->insertCharacterToken($token);
}
# Any other character token
elseif ($token instanceof CharacterToken) {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert the token’s character.
$this->insertCharacterToken($token);
# Set the frameset-ok flag to "not ok".
@ -1347,7 +1347,7 @@ class TreeBuilder {
$this->stack->popUntil('button');
}
# 2. Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# 3. Insert an HTML element for the token.
$this->insertStartTagToken($token);
# 4. Set the frameset-ok flag to "not ok".
@ -1370,7 +1370,7 @@ class TreeBuilder {
$this->stack->removeSame($element);
}
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$element = $this->insertStartTagToken($token);
# Push onto the list of active formatting elements that element.
@ -1381,7 +1381,7 @@ class TreeBuilder {
# "strong", "tt", "u"
elseif ($token->name === "b" || $token->name === "big" || $token->name === "code" || $token->name === "em" || $token->name === "font" || $token->name === "i" || $token->name === "s" || $token->name === "small" || $token->name === "strike" || $token->name === "strong" || $token->name === "tt" || $token->name === "u") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$element = $this->insertStartTagToken($token);
# Push onto the list of active formatting elements that element.
@ -1390,14 +1390,14 @@ class TreeBuilder {
# A start tag whose tag name is "nobr"
elseif ($token->name === "nobr") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# If the stack of open elements has a nobr element in scope, then this is a parse error;
if($this->stack->hasElementInScope("nobr")) {
$this->error(ParseError::UNEXPECTED_START_TAG_IMPLIES_END_TAG, $token->name);
# ... run the adoption agency algorithm for the token,
$this->adopt($token);
# ... then once again reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
}
# Insert an HTML element for the token.
$element = $this->insertStartTagToken($token);
@ -1407,7 +1407,7 @@ class TreeBuilder {
# A start tag whose tag name is one of: "applet", "marquee", "object"
elseif ($token->name === "applet" || $token->name === "marquee" || $token->name === "object") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$this->insertStartTagToken($token);
# Insert a marker at the end of the list of active formatting elements.
@ -1432,7 +1432,7 @@ class TreeBuilder {
# "embed", "img", "keygen", "wbr"
elseif ($token->name === "area" || $token->name === "br" || $token->name === "embed" || $token->name === "img" || $token->name === "keygen" || $token->name === "wbr") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
# Immediately pop the current node off the stack of open elements.
$this->insertStartTagToken($token);
@ -1445,7 +1445,7 @@ class TreeBuilder {
# A start tag whose tag name is "input"
elseif ($token->name === "input") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
# Immediately pop the current node off the stack of open elements.
$element = $this->insertStartTagToken($token);
@ -1528,7 +1528,7 @@ class TreeBuilder {
$this->closePElement($token);
}
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Set the frameset-ok flag to "not ok".
$this->framesetOk = false;
# Follow the generic raw text element parsing algorithm.
@ -1551,7 +1551,7 @@ class TreeBuilder {
# A start tag whose tag name is "select"
elseif ($token->name === "select") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$this->insertStartTagToken($token);
# Set the frameset-ok flag to "not ok".
@ -1580,7 +1580,7 @@ class TreeBuilder {
$this->stack->pop();
}
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$this->insertStartTagToken($token);
}
@ -1614,7 +1614,7 @@ class TreeBuilder {
# A start tag whose tag name is "math"
elseif ($token->name === "math") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Adjust MathML attributes for the token. (This fixes the case of MathML attributes that are not all lowercase.)
# Adjust foreign attributes for the token. (This fixes the use of namespaced attributes, in particular XLink.)
foreach ($token->attributes as $a) {
@ -1634,7 +1634,7 @@ class TreeBuilder {
# A start tag whose tag name is "svg"
elseif ($token->name === "svg") {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Adjust SVG attributes for the token. (This fixes the case of SVG attributes that are not all lowercase.)
# Adjust foreign attributes for the token. (This fixes the use of namespaced attributes, in particular XLink in SVG.)
foreach ($token->attributes as $a) {
@ -1657,7 +1657,7 @@ class TreeBuilder {
# Any other start tag
else {
# Reconstruct the active formatting elements, if any.
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
# Insert an HTML element for the token.
$this->insertStartTagToken($token);
}
@ -2233,7 +2233,7 @@ class TreeBuilder {
$this->fosterParenting = true;
foreach ($this->pendingTableCharacterTokens as $pending) {
// The relevant parts of the "in body" mode are reproduced here
$this->activeFormattingElementsList->reconstruct();
$this->reconstructActiveFormattingElements();
if ($pending instanceof NullCharacterToken) {
// Ignore the token
} elseif ($pending instanceof WhitespaceToken) {
@ -4333,4 +4333,59 @@ class TreeBuilder {
)
);
}
public function reconstructActiveFormattingElements(): void {
# When the steps below require the UA to reconstruct the active formatting
# elements, the UA must perform the following steps:
# 1. If there are no entries in the list of active formatting elements, then
# there is nothing to reconstruct; stop this algorithm.
$last = count($this->activeFormattingElementsList) - 1;
if ($last < 0) {
return;
}
# 2. If the last (most recently added) entry in the list of active formatting
# elements is a marker, or if it is an element that is in the stack of open
# elements, then there is nothing to reconstruct; stop this algorithm.
$pos = $last;
$entry = $this->activeFormattingElementsList[$pos];
if ($entry instanceof ActiveFormattingElementsMarker || $this->stack->findSame($entry['element']) > -1) {
return;
}
# 3. Let entry be the last (most recently added) element in the list of
# active formatting elements.
// Already done
while ($pos >= 0) {
# 4. Rewind: If there are no entries before entry in the list of active
# formatting elements, then jump to the step labeled Create.
if ($pos === 0) {
// DEVIATION: Instead don't increment position before breaking, unlike below
break;
}
# 5. Let entry be the entry one earlier than entry in the list of active
# formatting elements.
$entry = $this->activeFormattingElementsList[--$pos];
# 6. If entry is neither a marker nor an element that is also in the stack of
# open elements, go to the step labeled Rewind.
// Instead break if it is a marker or present in the stack
if ($entry instanceof ActiveFormattingElementsMarker || $this->stack->findSame($entry['element']) > -1) {
// DEVIATION: We increment before breaking to avoid having two loop exit points
$pos++;
break;
}
}
while ($pos <= $last) {
# 7. Advance: Let entry be the element one later than entry in the list of
# active formatting elements.
// DEVIATION: We increment at the end of the loop since we incremented when necessary before breaking out of the earlier loop
$entry = $this->activeFormattingElementsList[$pos];
# 8. Create: Insert an HTML element for the token for which the element entry
# was created, to obtain new element.
$element = $this->insertStartTagToken($entry['token']);
# 9. Replace the entry for entry in the list with an entry for new element.
$this->activeFormattingElementsList[$pos] = ['token' => $entry['token'], 'element' => $element];
# 10. If the entry for new element in the list of active formatting elements is
# not the last entry in the list, return to the step labeled Advance.
$pos++;
}
}
}

Loading…
Cancel
Save