Skip to content

Commit

Permalink
vaev-markup: in table cell html insertion mode
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloamed committed Jan 15, 2025
1 parent 6d6d4b9 commit 195dd1b
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 2 deletions.
114 changes: 112 additions & 2 deletions src/web/vaev-markup/html.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4117,7 +4117,7 @@ static constexpr Array IMPLIED_END_TAGS = {
Html::DD, Html::DT, Html::LI, Html::OPTION, Html::OPTGROUP, Html::P, Html::RB, Html::RP, Html::RT, Html::RTC
};

static void generateImpliedEndTags(HtmlParser &b, TagName except) {
static void generateImpliedEndTags(HtmlParser &b, Opt<TagName> except = NONE) {
while (contains(IMPLIED_END_TAGS, last(b._openElements)->tagName) and
last(b._openElements)->tagName != except) {
b._openElements.popBack();
Expand Down Expand Up @@ -5483,6 +5483,116 @@ void HtmlParser::_handleInTableRow(HtmlToken const &t) {
}
}

// 13.2.6.4.15 MARK: The "in cell" insertion mode
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intd
void HtmlParser::_handleInCell(HtmlToken const &t) {
auto _closeTheCell = [&]() {
// Generate implied end tags.
generateImpliedEndTags(*this);

// If the current node is not now a td element or a th element, then this is a parse error.
if (last(_openElements)->tagName != Html::TD and last(_openElements)->tagName != Html::TR) {
_raise();
}

// Pop elements from the stack of open elements until a td element or a th element has been popped from the stack.
while (Karm::any(_openElements)) {
auto poppedEl = _openElements.popBack();
if (poppedEl == Html::TD or poppedEl == Html::TH)
break;
}

// TODO: Clear the list of active formatting elements up to the last marker.

// Switch the insertion mode to "in row".
_switchTo(Mode::IN_ROW);
};

// An end tag whose tag name is one of: "td", "th"
if (t.type == HtmlToken::END_TAG and (t.name == "td" or t.name == "th")) {
// If the stack of open elements does not have an element in table scope that is an HTML element with the same
// tag name as that of the token,
TagName tokenTagName{TagName::make(t.name, Vaev::HTML)};

if (not _hasElementInTableScope(tokenTagName)) {
// this is a parse error; ignore the token.
_raise();
return;
}

// Otherwise:

// Generate implied end tags.
generateImpliedEndTags(*this);

// Now, if the current node is not an HTML element with the same tag name as the token,
if (last(_openElements)->tagName != tokenTagName) {
// then this is a parse error.
_raise();
}

// Pop elements from the stack of open elements until an HTML element with the same tag name as
// the token has been popped from the stack.
while (Karm::any(_openElements) and _openElements.popBack()->tagName != tokenTagName) {
// do nothing
}

// TODO: Clear the list of active formatting elements up to the last marker.

// Switch the insertion mode to "in row".
_switchTo(Mode::IN_ROW);
}

// A start tag whose tag name is one of: "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"
else if (t.type == HtmlToken::START_TAG and
(t.name == "caption" or t.name == "col" or t.name == "colgroup" or
t.name == "tbody" or t.name == "td" or t.name == "tfoot" or
t.name == "th" or t.name == "thead" or t.name == "tr"
)) {

// Assert: The stack of open elements has a td or th element in table scope.
if (not _hasElementInTableScope(Html::TD) and not _hasElementInTableScope(Html::TR)) {
_raise();
// FIXME: should this be a panic()?
}

// Close the cell (see below) and reprocess the token.
_closeTheCell();
accept(t);
}

// An end tag whose tag name is one of: "body", "caption", "col", "colgroup", "html"
else if (t.type == HtmlToken::END_TAG and
(t.name == "body" or t.name == "caption" or t.name == "col" or
t.name == "colgroup" or t.name == "html"
)) {
// Parse error. Ignore the token.
_raise();
}

// An end tag whose tag name is one of: "table", "tbody", "tfoot", "thead", "tr"
else if (t.type == HtmlToken::END_TAG and
(t.name == "table" or t.name == "tbody" or t.name == "tfoot" or t.name == "thead" or t.name == "tr")) {

// If the stack of open elements does not have an element in table scope that is an HTML element with the same
// tag name as the token,
if (not _hasElementInTableScope(TagName::make(t.name, Vaev::HTML))) {
// this is a parse error; ignore the token.
_raise();
return;
}

// Otherwise, close the cell (see below) and reprocess the token.
_closeTheCell();
accept(t);
}

else {
// Process the token using the rules for the "in body" insertion mode.
_acceptIn(Mode::IN_BODY, t);
}
}

// 3.2.6.4.22 MARK: The "after after body" insertion mode
// https://html.spec.whatwg.org/multipage/parsing.html#the-after-after-body-insertion-mode
void HtmlParser::_handleAfterBody(HtmlToken const &t) {
Expand Down Expand Up @@ -5579,8 +5689,8 @@ void HtmlParser::_acceptIn(Mode mode, HtmlToken const &t) {
_handleInTableRow(t);
break;

// TODO: https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incell
case Mode::IN_CELL:
_handleInCell(t);
break;

// TODO: https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inselect
Expand Down
2 changes: 2 additions & 0 deletions src/web/vaev-markup/html.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ struct HtmlParser : public HtmlSink {

void _handleInTableRow(HtmlToken const &t);

void _handleInCell(HtmlToken const &t);

void _handleAfterBody(HtmlToken const &t);

void _switchTo(Mode mode);
Expand Down

0 comments on commit 195dd1b

Please sign in to comment.