Skip to content
Permalink
Browse files
Implement HTML spec change to Adoption Agency Algorithm to not revers…
…e the order of nodes in the document,

by removing nodes that we're not recreating from the stack of open elements
https://bugs.webkit.org/show_bug.cgi?id=119478

Reviewed by Chris Dumez.

Implement the spec change. Also updated labeling of each line of code to match the latest spec.
New behavior matches the spec and that of Firefox.

* LayoutTests/html5lib/resources/webkit02.dat: Updated the expected parsing result to match the new behavior.
* LayoutTests/imported/w3c/web-platform-tests/html/syntax/parsing/html5lib_innerHTML_adoption01-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/syntax/parsing/html5lib_innerHTML_webkit02-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/syntax/parsing/html5lib_webkit02-expected.txt:

* Source/WebCore/html/parser/HTMLFormattingElementList.cpp:
(WebCore::HTMLFormattingElementList::swapTo):
* Source/WebCore/html/parser/HTMLTreeBuilder.cpp:
(WebCore::HTMLTreeBuilder::callTheAdoptionAgency):

Canonical link: https://commits.webkit.org/253505@main
  • Loading branch information
rniwa committed Aug 17, 2022
1 parent 3363325 commit 6f377390c19bd1327c626fbff6868926faef5193
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 179 deletions.
@@ -154,8 +154,7 @@ div
| <missing_glyph>
| <hkern>
| <aside>
| <em>
| <b>
| <b>

#data
<option><XH<optgroup></optgroup>
@@ -1,31 +1,5 @@
html5lib Parser Test


FAIL html5lib_innerHTML_adoption01.html 0bf80e1546d4c221354aa9734f61713b7d64ee6d assert_equals: expected "#document\n| <b>\n| <em>\n| <foo>\n| <foob>\n| <fooc>\n| <aside>\n| <b>" but got "#document\n| <b>\n| <em>\n| <foo>\n| <foob>\n| <fooc>\n| <aside>\n| <em>\n| <b>"
0bf80e1546d4c221354aa9734f61713b7d64ee6d

Input

undefined
Expected

#document
| <b>
| <em>
| <foo>
| <foob>
| <fooc>
| <aside>
| <b>
Actual

|<div>
| <b>
| <em>
| <foo>
| <foob>
| <fooc>
| <aside>
| <em>
| <b>
PASS html5lib_innerHTML_adoption01.html 0bf80e1546d4c221354aa9734f61713b7d64ee6d

@@ -1,87 +1,7 @@
html5lib Parser Test


FAIL html5lib_innerHTML_webkit02.html bafeef55f21b568ab89a91082464614e4ebe7c2f assert_equals: expected "#document\n| <b>\n| <em>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <aside>\n| <b>" but got "#document\n| <b>\n| <em>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <foo>\n| <aside>\n| <em>\n| <b>"
FAIL html5lib_innerHTML_webkit02.html 9461cfc6d9d4f08b05b3a95bbe5baa264f868a44 assert_equals: expected "#document\n| <b>\n| <em>\n| <foo>\n| <foob>\n| <foob>\n| <foob>\n| <foob>\n| <fooc>\n| <fooc>\n| <fooc>\n| <fooc>\n| <food>\n| <aside>\n| <b>" but got "#document\n| <b>\n| <em>\n| <foo>\n| <foob>\n| <foob>\n| <foob>\n| <foob>\n| <fooc>\n| <fooc>\n| <fooc>\n| <fooc>\n| <food>\n| <aside>\n| <em>\n| <b>"
PASS html5lib_innerHTML_webkit02.html bafeef55f21b568ab89a91082464614e4ebe7c2f
PASS html5lib_innerHTML_webkit02.html 9461cfc6d9d4f08b05b3a95bbe5baa264f868a44
PASS html5lib_innerHTML_webkit02.html c2c4647447354abc154f1917a7fbefa4a679d5fb
bafeef55f21b568ab89a91082464614e4ebe7c2f

Input

undefined
Expected

#document
| <b>
| <em>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <aside>
| <b>
Actual

|<div>
| <b>
| <em>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <foo>
| <aside>
| <em>
| <b>
9461cfc6d9d4f08b05b3a95bbe5baa264f868a44

Input

undefined
Expected

#document
| <b>
| <em>
| <foo>
| <foob>
| <foob>
| <foob>
| <foob>
| <fooc>
| <fooc>
| <fooc>
| <fooc>
| <food>
| <aside>
| <b>
Actual

|<div>
| <b>
| <em>
| <foo>
| <foob>
| <foob>
| <foob>
| <foob>
| <fooc>
| <fooc>
| <fooc>
| <fooc>
| <food>
| <aside>
| <em>
| <b>

@@ -14,40 +14,8 @@ PASS html5lib_webkit02.html 464eeaecc49646ff810cadad537880c9b473a262
PASS html5lib_webkit02.html 7b4eb6981451ede406f2f4112e83a8584e7adbf5
PASS html5lib_webkit02.html 73aed96d7cd3116e4a3e701104616c07d1ec5e0c
PASS html5lib_webkit02.html 139a546c72bfcedf638d031f33da43f24995f688
FAIL html5lib_webkit02.html 6e33515b4dc011dd390d433a6358bf68b786b1fd assert_equals: expected "#document\n| <html>\n| <head>\n| <body>\n| <b>\n| <em>\n| <foo>\n| <foo>\n| <foo>\n| <aside>\n| <b>" but got "#document\n| <html>\n| <head>\n| <body>\n| <b>\n| <em>\n| <foo>\n| <foo>\n| <foo>\n| <aside>\n| <em>\n| <b>"
PASS html5lib_webkit02.html 6e33515b4dc011dd390d433a6358bf68b786b1fd
PASS html5lib_webkit02.html b6d2377b0dd710ca812c97b2b65cb5d2e93b0e5b
PASS html5lib_webkit02.html 21a5b2b413c4db8ed588334b9a50dea9872bbcfa
PASS html5lib_webkit02.html 90d3f6f2dff994f63293ca46f7cd50a75cde96a6
6e33515b4dc011dd390d433a6358bf68b786b1fd

Input

<b><em><foo><foo><foo><aside></b></em>
Expected

#document
| <html>
| <head>
| <body>
| <b>
| <em>
| <foo>
| <foo>
| <foo>
| <aside>
| <b>
Actual

#document
| <html>
| <head>
| <body>
| <b>
| <em>
| <foo>
| <foo>
| <foo>
| <aside>
| <em>
| <b>

@@ -85,8 +85,8 @@ void HTMLFormattingElementList::swapTo(Element& oldElement, HTMLStackItem&& newI
return;
}
size_t index = &bookmark.mark() - &first();
ASSERT_WITH_SECURITY_IMPLICATION(index < size());
m_entries.insert(index + 1, WTFMove(newItem));
ASSERT_WITH_SECURITY_IMPLICATION(index <= size());
m_entries.insert(index, WTFMove(newItem));
remove(oldElement);
}

@@ -1435,85 +1435,90 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomHTMLToken& token)

// 4 is covered by the for() loop.
for (int i = 0; i < outerIterationLimit; ++i) {
// 4.
// 4.3.
RefPtr<Element> formattingElement = m_tree.activeFormattingElements().closestElementInScopeWithName(token.name());
// 4.a
if (!formattingElement)
return processAnyOtherEndTagForInBody(WTFMove(token));
// 4.c
// 4.5.
if ((m_tree.openElements().contains(*formattingElement)) && !m_tree.openElements().inScope(*formattingElement)) {
parseError(token);
notImplemented(); // Check the stack of open elements for a more specific parse error.
return;
}
// 4.b
// 4.4.
auto* formattingElementRecord = m_tree.openElements().find(*formattingElement);
if (!formattingElementRecord) {
parseError(token);
m_tree.activeFormattingElements().remove(*formattingElement);
return;
}
// 4.d
// 4.6.
if (formattingElement != &m_tree.currentElement())
parseError(token);
// 5.
// 4.7.
auto* furthestBlock = m_tree.openElements().furthestBlockForFormattingElement(*formattingElement);
// 6.
// 4.8.
if (!furthestBlock) {
m_tree.openElements().popUntilPopped(*formattingElement);
m_tree.activeFormattingElements().remove(*formattingElement);
return;
}
// 7.
// 4.9.
ASSERT(furthestBlock->isAbove(*formattingElementRecord));
auto& commonAncestor = formattingElementRecord->next()->stackItem();
// 8.
// 4.10.
HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements().bookmarkFor(*formattingElement);
// 9.
// 4.11.
auto* node = furthestBlock;
auto* nextNode = node->next();
auto* lastNode = furthestBlock;
// 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop.
for (int i = 0; i < innerIterationLimit; ++i) {
// 9.4
auto* nextNode = node->next();
// 4.13.
unsigned innerLoopCounter = 0;
while (true) {
++innerLoopCounter;
// 4.13.2.
node = nextNode;
ASSERT(node);
nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5.
// 9.5
if (!m_tree.activeFormattingElements().contains(node->element())) {
nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in the next step.
// 4.13.3.
if (node == formattingElementRecord)
break;
// 4.13.4.
bool nodeIsInListOfActiveFormattingElements = m_tree.activeFormattingElements().contains(node->element());
if (innerLoopCounter > innerIterationLimit && nodeIsInListOfActiveFormattingElements)
m_tree.activeFormattingElements().remove(node->element());
// 4.13.5.
auto* nodeEntry = m_tree.activeFormattingElements().find(node->element());
if (!nodeEntry) {
m_tree.openElements().remove(node->element());
node = 0;
node = nullptr;
continue;
}
// 9.6
if (node == formattingElementRecord)
break;
// 9.7
// 4.13.6.
auto newItem = m_tree.createElementFromSavedToken(node->stackItem());

HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements().find(node->element());
nodeEntry->replaceElement(HTMLStackItem(newItem));
node->replaceElement(WTFMove(newItem));

// 9.8
// 4.13.7.
if (lastNode == furthestBlock)
bookmark.moveToAfter(*nodeEntry);
// 9.9
// 4.13.8.
m_tree.reparent(*node, *lastNode);
// 9.10
// 4.13.9.
lastNode = node;
}
// 10.
// 14.
m_tree.insertAlreadyParsedChild(commonAncestor, *lastNode);
// 11.
// 15.
auto newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem());
// 12. & 13.
// 16.
m_tree.takeAllChildrenAndReparent(newItem, *furthestBlock);
// 14.
m_tree.activeFormattingElements().swapTo(*formattingElement, HTMLStackItem(newItem), bookmark);
// 15.
m_tree.openElements().insertAbove(HTMLStackItem(newItem), *furthestBlock);
// 18.
m_tree.activeFormattingElements().swapTo(*formattingElement, WTFMove(newItem), bookmark);
// 19.
m_tree.openElements().remove(*formattingElement);
m_tree.openElements().insertAbove(WTFMove(newItem), *furthestBlock);
}
}

0 comments on commit 6f37739

Please sign in to comment.