Element getActiveFormattingElement(String nodeName) { for (int pos = formattingElements.size() -1; pos >= 0; pos--) { Element next = formattingElements.get(pos); if (next == null) // scope marker break; else if (next.nodeName().equals(nodeName)) return next; } return null; }
Element getFromStack(String elName) { for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); if (next.nodeName().equals(elName)) { return next; } } return null; }
void popStackToClose(String elName) { for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); stack.remove(pos); if (next.nodeName().equals(elName)) break; } }
void popStackToBefore(String elName) { for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); if (next.nodeName().equals(elName)) { break; } else { stack.remove(pos); } } }
void popStackToClose(String... elNames) { for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); stack.remove(pos); if (inSorted(next.nodeName(), elNames)) break; } }
boolean isSpecial(Element el) { // todo: mathml's mi, mo, mn // todo: svg's foreigObject, desc, title String name = el.nodeName(); return inSorted(name, TagSearchSpecial); }
private boolean isSameFormattingElement(Element a, Element b) { // same if: same namespace, tag, and attributes. Element.equals only checks tag, might in future check children return a.nodeName().equals(b.nodeName()) && // a.namespace().equals(b.namespace()) && a.attributes().equals(b.attributes()); // todo: namespaces }
boolean inSelectScope(String targetName) { for (int pos = stack.size() -1; pos >= 0; pos--) { Element el = stack.get(pos); String elName = el.nodeName(); if (elName.equals(targetName)) return true; if (!inSorted(elName, TagSearchSelectScope)) // all elements except return false; } Validate.fail("Should not be reachable"); return false; }
/** * If the stack contains an element with this tag's name, pop up the stack to remove the first occurrence. If not * found, skips. * * @param endTag tag to close */ private void popStackToClose(Token.EndTag endTag) { String elName = settings.normalizeTag(endTag.tagName); Element firstFound = null; for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); if (next.nodeName().equals(elName)) { firstFound = next; break; } } if (firstFound == null) return; // not found, skip for (int pos = stack.size() -1; pos >= 0; pos--) { Element next = stack.get(pos); stack.remove(pos); if (next == firstFound) break; } }
/** 11.2.5.2 Closing elements that have implied end tags<p/> When the steps below require the UA to generate implied end tags, then, while the current node is a dd element, a dt element, an li element, an option element, an optgroup element, a p element, an rp element, or an rt element, the UA must pop the current node off the stack of open elements. @param excludeTag If a step requires the UA to generate implied end tags but lists an element to exclude from the process, then the UA must perform the above steps as if that element was not in the above list. */ void generateImpliedEndTags(String excludeTag) { while ((excludeTag != null && !currentElement().nodeName().equals(excludeTag)) && inSorted(currentElement().nodeName(), TagSearchEndTags)) pop(); }
@Signature public String nodeName() { return getWrappedObject().nodeName(); }
private boolean inSpecificScope(String[] targetNames, String[] baseTypes, String[] extraTypes) { // https://html.spec.whatwg.org/multipage/parsing.html#has-an-element-in-the-specific-scope final int bottom = stack.size() -1; final int top = bottom > MaxScopeSearchDepth ? bottom - MaxScopeSearchDepth : 0; // don't walk too far up the tree for (int pos = bottom; pos >= top; pos--) { final String elName = stack.get(pos).nodeName(); if (inSorted(elName, targetNames)) return true; if (inSorted(elName, baseTypes)) return false; if (extraTypes != null && inSorted(elName, extraTypes)) return false; } //Validate.fail("Should not be reachable"); // would end up false because hitting 'html' at root (basetypes) return false; }
boolean anyOtherEndTag(Token t, HtmlTreeBuilder tb) { String name = tb.settings.normalizeTag(t.asEndTag().name()); // matches with case sensitivity if enabled ArrayList<Element> stack = tb.getStack(); for (int pos = stack.size() -1; pos >= 0; pos--) { Element node = stack.get(pos); if (node.nodeName().equals(name)) { tb.generateImpliedEndTags(name); if (!name.equals(tb.currentElement().nodeName())) tb.error(this); tb.popStackToClose(name); break; } else { if (tb.isSpecial(node)) { tb.error(this); return false; } } } return true; } },
Element newEl = insertStartTag(entry.nodeName()); // todo: avoid fostering here?
boolean anythingElse(Token t, HtmlTreeBuilder tb) { tb.error(this); boolean processed; if (StringUtil.in(tb.currentElement().nodeName(), "table", "tbody", "tfoot", "thead", "tr")) { tb.setFosterInserts(true); processed = tb.process(t, InBody); tb.setFosterInserts(false); } else { processed = tb.process(t, InBody); } return processed; } },
private boolean exitTableBody(Token t, HtmlTreeBuilder tb) { if (!(tb.inTableScope("tbody") || tb.inTableScope("thead") || tb.inScope("tfoot"))) { // frag case tb.error(this); return false; } tb.clearStackToTableBodyContext(); tb.processEndTag(tb.currentElement().nodeName()); // tbody, tfoot, thead return tb.process(t); }
if (tb.currentElement().nodeName().equals("html")) { // frag tb.error(this); return false; } else { tb.pop(); if (!tb.isFragmentParsing() && !tb.currentElement().nodeName().equals("frameset")) { tb.transition(AfterFrameset); if (!tb.currentElement().nodeName().equals("html")) { tb.error(this); return true;
if (StringUtil.in(tb.currentElement().nodeName(), "table", "tbody", "tfoot", "thead", "tr")) { tb.setFosterInserts(true); tb.process(new Token.Character().data(character), InBody);
} else { tb.generateImpliedEndTags(); if (!tb.currentElement().nodeName().equals("caption")) tb.error(this); tb.popStackToClose("caption");