Changeset 80201 in webkit


Ignore:
Timestamp:
Mar 2, 2011 8:40:56 PM (13 years ago)
Author:
aestes@apple.com
Message:

2011-03-02 Andy Estes <aestes@apple.com>

Reviewed by Eric Seidel.

HTML5 TreeBuilder regressed a Peacekeeper DOM test by 25% (was 40%)
https://bugs.webkit.org/show_bug.cgi?id=48719


Instead of pushing a fake HTMLHtmlElement onto the open element stack
during fragment parsing only to later remove it and reparent its
children to the DocumentFragment, push the DocumentFragment directly
onto the open element stack as the root node. This requires refactoring
HTMLElementStack to hold ContainerNode pointers rather than Element
pointers, which has implications for HTMLConstructionSite and
HTMLTreeBuilder as well.


With this patch, the regression in Peacekeeper due to the introduction
of the HTML5 fragment parsing algorithm is ~14%. The regression from
Safari 5.0.3 is ~24%.

No new tests. No change in behavior.

  • dom/Element.h: (WebCore::Node::hasLocalName):
  • dom/Node.h:
  • html/parser/HTMLConstructionSite.cpp: (WebCore::HTMLNames::hasImpliedEndTag): (WebCore::HTMLConstructionSite::HTMLConstructionSite): (WebCore::HTMLConstructionSite::insertHTMLHtmlStartTagInBody): (WebCore::HTMLConstructionSite::insertComment): (WebCore::HTMLConstructionSite::insertCommentOnHTMLHtmlElement): (WebCore::HTMLConstructionSite::attachToCurrent): (WebCore::HTMLConstructionSite::insertScriptElement): (WebCore::HTMLConstructionSite::insertTextNode): (WebCore::HTMLConstructionSite::createElement): (WebCore::HTMLConstructionSite::createHTMLElement): (WebCore::HTMLConstructionSite::generateImpliedEndTagsWithExclusion): (WebCore::HTMLConstructionSite::generateImpliedEndTags): (WebCore::HTMLConstructionSite::findFosterSite): (WebCore::HTMLConstructionSite::shouldFosterParent):
  • html/parser/HTMLConstructionSite.h: (WebCore::HTMLConstructionSite::currentNode):
  • html/parser/HTMLElementStack.cpp: (WebCore::HTMLNames::isNumberedHeaderElement): (WebCore::HTMLNames::isScopeMarker): (WebCore::HTMLNames::isListItemScopeMarker): (WebCore::HTMLNames::isTableScopeMarker): (WebCore::HTMLNames::isTableBodyScopeMarker): (WebCore::HTMLNames::isTableRowScopeMarker): (WebCore::HTMLNames::isButtonScopeMarker): (WebCore::HTMLNames::isSelectScopeMarker): (WebCore::HTMLElementStack::ElementRecord::ElementRecord): (WebCore::HTMLElementStack::ElementRecord::replaceElement): (WebCore::HTMLElementStack::HTMLElementStack): (WebCore::HTMLElementStack::secondElementIsHTMLBodyElement): (WebCore::HTMLElementStack::popAll): (WebCore::HTMLElementStack::popUntilNumberedHeaderElementPopped): (WebCore::HTMLElementStack::popUntil): (WebCore::HTMLElementStack::popUntilPopped): (WebCore::HTMLElementStack::popUntilTableScopeMarker): (WebCore::HTMLElementStack::popUntilTableBodyScopeMarker): (WebCore::HTMLElementStack::popUntilTableRowScopeMarker): (WebCore::HTMLElementStack::pushHTMLHtmlElement): (WebCore::HTMLElementStack::push): (WebCore::HTMLElementStack::insertAbove): (WebCore::HTMLElementStack::find): (WebCore::HTMLElementStack::topmost): (WebCore::HTMLElementStack::contains): (WebCore::inScopeCommon): (WebCore::HTMLElementStack::hasNumberedHeaderElementInScope): (WebCore::HTMLElementStack::htmlElement): (WebCore::HTMLElementStack::rootNode): (WebCore::HTMLElementStack::pushCommon):
  • html/parser/HTMLElementStack.h: (WebCore::HTMLElementStack::ElementRecord::element): (WebCore::HTMLElementStack::ElementRecord::node): (WebCore::HTMLElementStack::topNode):
  • html/parser/HTMLTreeBuilder.cpp: (WebCore::HTMLTreeBuilder::HTMLTreeBuilder): (WebCore::HTMLTreeBuilder::processCloseWhenNestedTag): (WebCore::HTMLTreeBuilder::processStartTagForInBody): (WebCore::HTMLTreeBuilder::processColgroupEndTagForInColumnGroup): (WebCore::HTMLTreeBuilder::processStartTag): (WebCore::HTMLTreeBuilder::processAnyOtherEndTagForInBody): (WebCore::HTMLTreeBuilder::callTheAdoptionAgency): (WebCore::HTMLTreeBuilder::resetInsertionModeAppropriately): (WebCore::HTMLTreeBuilder::processEndTagForInCell): (WebCore::HTMLTreeBuilder::processEndTagForInBody): (WebCore::HTMLTreeBuilder::processEndTag): (WebCore::HTMLTreeBuilder::processEndOfFile): (WebCore::HTMLTreeBuilder::finished):
  • html/parser/HTMLTreeBuilder.h:
Location:
trunk/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r80200 r80201  
     12011-03-02  Andy Estes  <aestes@apple.com>
     2
     3        Reviewed by Eric Seidel.
     4
     5        HTML5 TreeBuilder regressed a Peacekeeper DOM test by 25% (was 40%)
     6        https://bugs.webkit.org/show_bug.cgi?id=48719
     7       
     8        Instead of pushing a fake HTMLHtmlElement onto the open element stack
     9        during fragment parsing only to later remove it and reparent its
     10        children to the DocumentFragment, push the DocumentFragment directly
     11        onto the open element stack as the root node. This requires refactoring
     12        HTMLElementStack to hold ContainerNode pointers rather than Element
     13        pointers, which has implications for HTMLConstructionSite and
     14        HTMLTreeBuilder as well.
     15       
     16        With this patch, the regression in Peacekeeper due to the introduction
     17        of the HTML5 fragment parsing algorithm is ~14%. The regression from
     18        Safari 5.0.3 is ~24%.
     19
     20        No new tests. No change in behavior.
     21
     22        * dom/Element.h:
     23        (WebCore::Node::hasLocalName):
     24        * dom/Node.h:
     25        * html/parser/HTMLConstructionSite.cpp:
     26        (WebCore::HTMLNames::hasImpliedEndTag):
     27        (WebCore::HTMLConstructionSite::HTMLConstructionSite):
     28        (WebCore::HTMLConstructionSite::insertHTMLHtmlStartTagInBody):
     29        (WebCore::HTMLConstructionSite::insertComment):
     30        (WebCore::HTMLConstructionSite::insertCommentOnHTMLHtmlElement):
     31        (WebCore::HTMLConstructionSite::attachToCurrent):
     32        (WebCore::HTMLConstructionSite::insertScriptElement):
     33        (WebCore::HTMLConstructionSite::insertTextNode):
     34        (WebCore::HTMLConstructionSite::createElement):
     35        (WebCore::HTMLConstructionSite::createHTMLElement):
     36        (WebCore::HTMLConstructionSite::generateImpliedEndTagsWithExclusion):
     37        (WebCore::HTMLConstructionSite::generateImpliedEndTags):
     38        (WebCore::HTMLConstructionSite::findFosterSite):
     39        (WebCore::HTMLConstructionSite::shouldFosterParent):
     40        * html/parser/HTMLConstructionSite.h:
     41        (WebCore::HTMLConstructionSite::currentNode):
     42        * html/parser/HTMLElementStack.cpp:
     43        (WebCore::HTMLNames::isNumberedHeaderElement):
     44        (WebCore::HTMLNames::isScopeMarker):
     45        (WebCore::HTMLNames::isListItemScopeMarker):
     46        (WebCore::HTMLNames::isTableScopeMarker):
     47        (WebCore::HTMLNames::isTableBodyScopeMarker):
     48        (WebCore::HTMLNames::isTableRowScopeMarker):
     49        (WebCore::HTMLNames::isButtonScopeMarker):
     50        (WebCore::HTMLNames::isSelectScopeMarker):
     51        (WebCore::HTMLElementStack::ElementRecord::ElementRecord):
     52        (WebCore::HTMLElementStack::ElementRecord::replaceElement):
     53        (WebCore::HTMLElementStack::HTMLElementStack):
     54        (WebCore::HTMLElementStack::secondElementIsHTMLBodyElement):
     55        (WebCore::HTMLElementStack::popAll):
     56        (WebCore::HTMLElementStack::popUntilNumberedHeaderElementPopped):
     57        (WebCore::HTMLElementStack::popUntil):
     58        (WebCore::HTMLElementStack::popUntilPopped):
     59        (WebCore::HTMLElementStack::popUntilTableScopeMarker):
     60        (WebCore::HTMLElementStack::popUntilTableBodyScopeMarker):
     61        (WebCore::HTMLElementStack::popUntilTableRowScopeMarker):
     62        (WebCore::HTMLElementStack::pushHTMLHtmlElement):
     63        (WebCore::HTMLElementStack::push):
     64        (WebCore::HTMLElementStack::insertAbove):
     65        (WebCore::HTMLElementStack::find):
     66        (WebCore::HTMLElementStack::topmost):
     67        (WebCore::HTMLElementStack::contains):
     68        (WebCore::inScopeCommon):
     69        (WebCore::HTMLElementStack::hasNumberedHeaderElementInScope):
     70        (WebCore::HTMLElementStack::htmlElement):
     71        (WebCore::HTMLElementStack::rootNode):
     72        (WebCore::HTMLElementStack::pushCommon):
     73        * html/parser/HTMLElementStack.h:
     74        (WebCore::HTMLElementStack::ElementRecord::element):
     75        (WebCore::HTMLElementStack::ElementRecord::node):
     76        (WebCore::HTMLElementStack::topNode):
     77        * html/parser/HTMLTreeBuilder.cpp:
     78        (WebCore::HTMLTreeBuilder::HTMLTreeBuilder):
     79        (WebCore::HTMLTreeBuilder::processCloseWhenNestedTag):
     80        (WebCore::HTMLTreeBuilder::processStartTagForInBody):
     81        (WebCore::HTMLTreeBuilder::processColgroupEndTagForInColumnGroup):
     82        (WebCore::HTMLTreeBuilder::processStartTag):
     83        (WebCore::HTMLTreeBuilder::processAnyOtherEndTagForInBody):
     84        (WebCore::HTMLTreeBuilder::callTheAdoptionAgency):
     85        (WebCore::HTMLTreeBuilder::resetInsertionModeAppropriately):
     86        (WebCore::HTMLTreeBuilder::processEndTagForInCell):
     87        (WebCore::HTMLTreeBuilder::processEndTagForInBody):
     88        (WebCore::HTMLTreeBuilder::processEndTag):
     89        (WebCore::HTMLTreeBuilder::processEndOfFile):
     90        (WebCore::HTMLTreeBuilder::finished):
     91        * html/parser/HTMLTreeBuilder.h:
     92
    1932011-03-02  Sheriff Bot  <webkit.review.bot@gmail.com>
    294
  • trunk/Source/WebCore/dom/Element.h

    r80030 r80201  
    428428    return isElementNode() && toElement(this)->hasTagName(name);
    429429}
     430   
     431inline bool Node::hasLocalName(const AtomicString& name) const
     432{
     433    return isElementNode() && toElement(this)->hasLocalName(name);
     434}
    430435
    431436inline bool Node::hasAttributes() const
  • trunk/Source/WebCore/dom/Node.h

    r79269 r80201  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2001 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
    66 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
    77 *
     
    135135
    136136    bool hasTagName(const QualifiedName&) const;
     137    bool hasLocalName(const AtomicString&) const;
    137138    virtual String nodeName() const = 0;
    138139    virtual String nodeValue() const;
  • trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp

    r78286 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    5960namespace {
    6061
    61 bool hasImpliedEndTag(Element* element)
    62 {
    63     return element->hasTagName(ddTag)
    64         || element->hasTagName(dtTag)
    65         || element->hasTagName(liTag)
    66         || element->hasTagName(optionTag)
    67         || element->hasTagName(optgroupTag)
    68         || element->hasTagName(pTag)
    69         || element->hasTagName(rpTag)
    70         || element->hasTagName(rtTag);
     62bool hasImpliedEndTag(ContainerNode* node)
     63{
     64    return node->hasTagName(ddTag)
     65        || node->hasTagName(dtTag)
     66        || node->hasTagName(liTag)
     67        || node->hasTagName(optionTag)
     68        || node->hasTagName(optgroupTag)
     69        || node->hasTagName(pTag)
     70        || node->hasTagName(rpTag)
     71        || node->hasTagName(rtTag);
    7172}
    7273
     
    205206{
    206207    // FIXME: parse error
     208   
     209    // Fragments do not have a root HTML element, so any additional HTML elements
     210    // encountered during fragment parsing should be ignored.
     211    if (m_isParsingFragment)
     212        return;
     213
    207214    mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
    208215}
     
    237244{
    238245    ASSERT(token.type() == HTMLToken::Comment);
    239     attach(currentElement(), Comment::create(currentElement()->document(), token.comment()));
     246    attach(currentNode(), Comment::create(currentNode()->document(), token.comment()));
    240247}
    241248
     
    249256{
    250257    ASSERT(token.type() == HTMLToken::Comment);
    251     Element* parent = m_openElements.htmlElement();
     258    ContainerNode* parent = m_openElements.rootNode();
    252259    attach(parent, Comment::create(parent->document(), token.comment()));
    253260}
     
    255262PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)
    256263{
    257     return attach(currentElement(), child);
     264    return attach(currentNode(), child);
    258265}
    259266
     
    311318void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken& token)
    312319{
    313     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, currentElement()->document(), true);
     320    RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, currentNode()->document(), true);
    314321    if (m_fragmentScriptingPermission == FragmentScriptingAllowed)
    315322        element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
     
    330337{
    331338    AttachmentSite site;
    332     site.parent = currentElement();
     339    site.parent = currentNode();
    333340    site.nextChild = 0;
    334341    if (shouldFosterParent())
     
    350357{
    351358    QualifiedName tagName(nullAtom, token.name(), namespaceURI);
    352     RefPtr<Element> element = currentElement()->document()->createElement(tagName, true);
     359    RefPtr<Element> element = currentNode()->document()->createElement(tagName, true);
    353360    element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
    354361    return element.release();
     
    361368    // have to pass the current form element.  We should rework form association
    362369    // to occur after construction to allow better code sharing here.
    363     RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, currentElement()->document(), form(), true);
     370    RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, currentNode()->document(), form(), true);
    364371    element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
    365372    ASSERT(element->isHTMLElement());
     
    440447void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
    441448{
    442     while (hasImpliedEndTag(currentElement()) && !currentElement()->hasLocalName(tagName))
     449    while (hasImpliedEndTag(currentNode()) && !currentNode()->hasLocalName(tagName))
    443450        m_openElements.pop();
    444451}
     
    446453void HTMLConstructionSite::generateImpliedEndTags()
    447454{
    448     while (hasImpliedEndTag(currentElement()))
     455    while (hasImpliedEndTag(currentNode()))
    449456        m_openElements.pop();
    450457}
     
    465472    }
    466473    // Fragment case
    467     site.parent = m_openElements.bottom(); // <html> element
     474    site.parent = m_openElements.rootNode(); // DocumentFragment
    468475    site.nextChild = 0;
    469476}
     
    472479{
    473480    return m_redirectAttachToFosterParent
     481        && currentNode()->isElementNode()
    474482        && causesFosterParenting(currentElement()->tagQName());
    475483}
  • trunk/Source/WebCore/html/parser/HTMLConstructionSite.h

    r78286 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    8182
    8283    Element* currentElement() const { return m_openElements.top(); }
     84    ContainerNode* currentNode() const { return m_openElements.topNode(); }
    8385    Element* oneBelowTop() const { return m_openElements.oneBelowTop(); }
    8486
  • trunk/Source/WebCore/html/parser/HTMLElementStack.cpp

    r70293 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    2728#include "HTMLElementStack.h"
    2829
     30#include "DocumentFragment.h"
    2931#include "Element.h"
    3032#include "HTMLNames.h"
     
    4850        || element->hasTagName(h6Tag);
    4951}
    50 
    51 inline bool isScopeMarker(Element* element)
    52 {
    53     return element->hasTagName(appletTag)
    54         || element->hasTagName(captionTag)
    55         || element->hasTagName(htmlTag)
    56         || element->hasTagName(marqueeTag)
    57         || element->hasTagName(objectTag)
    58         || element->hasTagName(tableTag)
    59         || element->hasTagName(tdTag)
    60         || element->hasTagName(thTag)
    61         || element->hasTagName(MathMLNames::miTag)
    62         || element->hasTagName(MathMLNames::moTag)
    63         || element->hasTagName(MathMLNames::mnTag)
    64         || element->hasTagName(MathMLNames::msTag)
    65         || element->hasTagName(MathMLNames::mtextTag)
    66         || element->hasTagName(MathMLNames::annotation_xmlTag)
    67         || element->hasTagName(SVGNames::foreignObjectTag)
    68         || element->hasTagName(SVGNames::descTag)
    69         || element->hasTagName(SVGNames::titleTag);
    70 }
    71 
    72 inline bool isListItemScopeMarker(Element* element)
    73 {
    74     return isScopeMarker(element)
    75         || element->hasTagName(olTag)
    76         || element->hasTagName(ulTag);
    77 }
    78 
    79 inline bool isTableScopeMarker(Element* element)
    80 {
    81     return element->hasTagName(tableTag)
    82         || element->hasTagName(htmlTag);
    83 }
    84 
    85 inline bool isTableBodyScopeMarker(Element* element)
    86 {
    87     return element->hasTagName(tbodyTag)
    88         || element->hasTagName(tfootTag)
    89         || element->hasTagName(theadTag)
    90         || element->hasTagName(htmlTag);
    91 }
    92 
    93 inline bool isTableRowScopeMarker(Element* element)
    94 {
    95     return element->hasTagName(trTag)
    96         || element->hasTagName(htmlTag);
     52   
     53inline bool isRootNode(ContainerNode* node)
     54{
     55    return node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE
     56        || node->hasTagName(htmlTag);
     57}
     58
     59inline bool isScopeMarker(ContainerNode* node)
     60{
     61    return node->hasTagName(appletTag)
     62        || node->hasTagName(captionTag)
     63        || node->hasTagName(marqueeTag)
     64        || node->hasTagName(objectTag)
     65        || node->hasTagName(tableTag)
     66        || node->hasTagName(tdTag)
     67        || node->hasTagName(thTag)
     68        || node->hasTagName(MathMLNames::miTag)
     69        || node->hasTagName(MathMLNames::moTag)
     70        || node->hasTagName(MathMLNames::mnTag)
     71        || node->hasTagName(MathMLNames::msTag)
     72        || node->hasTagName(MathMLNames::mtextTag)
     73        || node->hasTagName(MathMLNames::annotation_xmlTag)
     74        || node->hasTagName(SVGNames::foreignObjectTag)
     75        || node->hasTagName(SVGNames::descTag)
     76        || node->hasTagName(SVGNames::titleTag)
     77        || isRootNode(node);
     78}
     79
     80inline bool isListItemScopeMarker(ContainerNode* node)
     81{
     82    return isScopeMarker(node)
     83        || node->hasTagName(olTag)
     84        || node->hasTagName(ulTag);
     85}
     86
     87inline bool isTableScopeMarker(ContainerNode* node)
     88{
     89    return node->hasTagName(tableTag)
     90        || isRootNode(node);
     91}
     92
     93inline bool isTableBodyScopeMarker(ContainerNode* node)
     94{
     95    return node->hasTagName(tbodyTag)
     96        || node->hasTagName(tfootTag)
     97        || node->hasTagName(theadTag)
     98        || isRootNode(node);
     99}
     100
     101inline bool isTableRowScopeMarker(ContainerNode* node)
     102{
     103    return node->hasTagName(trTag)
     104        || isRootNode(node);
    97105}
    98106
     
    110118}
    111119
    112 inline bool isButtonScopeMarker(Element* element)
    113 {
    114     return isScopeMarker(element)
    115         || element->hasTagName(buttonTag);
    116 }
    117 
    118 inline bool isSelectScopeMarker(Element* element)
    119 {
    120     return !element->hasTagName(optgroupTag)
    121         && !element->hasTagName(optionTag);
    122 }
    123 
    124 }
    125 
    126 HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
    127     : m_element(element)
     120inline bool isButtonScopeMarker(ContainerNode* node)
     121{
     122    return isScopeMarker(node)
     123        || node->hasTagName(buttonTag);
     124}
     125
     126inline bool isSelectScopeMarker(ContainerNode* node)
     127{
     128    return !node->hasTagName(optgroupTag)
     129        && !node->hasTagName(optionTag);
     130}
     131
     132}
     133
     134HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<ContainerNode> node, PassOwnPtr<ElementRecord> next)
     135    : m_node(node)
    128136    , m_next(next)
    129137{
    130     ASSERT(m_element);
     138    ASSERT(m_node);
    131139}
    132140
     
    138146{
    139147    ASSERT(element);
     148    ASSERT(!m_node || m_node->isElementNode());
    140149    // FIXME: Should this call finishParsingChildren?
    141     m_element = element;
     150    m_node = element;
    142151}
    143152
     
    152161
    153162HTMLElementStack::HTMLElementStack()
    154     : m_htmlElement(0)
     163    : m_rootNode(0)
    155164    , m_headElement(0)
    156165    , m_bodyElement(0)
     
    172181    // insertion mode.
    173182    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
    174     ASSERT(m_htmlElement);
     183    ASSERT(m_rootNode);
    175184    // If we have a body element, it must always be the second element on the
    176185    // stack, as we always start with an html element, and any other element
     
    195204void HTMLElementStack::popAll()
    196205{
    197     m_htmlElement = 0;
     206    m_rootNode = 0;
    198207    m_headElement = 0;
    199208    m_bodyElement = 0;
    200209    while (m_top) {
    201         top()->finishParsingChildren();
     210        topNode()->finishParsingChildren();
    202211        m_top = m_top->releaseNext();
    203212    }
     
    247256{
    248257    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-context
    249     while (!isTableScopeMarker(top()))
     258    while (!isTableScopeMarker(topNode()))
    250259        pop();
    251260}
     
    254263{
    255264    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-body-context
    256     while (!isTableBodyScopeMarker(top()))
     265    while (!isTableBodyScopeMarker(topNode()))
    257266        pop();
    258267}
     
    261270{
    262271    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-row-context
    263     while (!isTableRowScopeMarker(top()))
     272    while (!isTableRowScopeMarker(topNode()))
    264273        pop();
    265274}
     
    270279        pop();
    271280}
     281   
     282void HTMLElementStack::pushRootNode(PassRefPtr<ContainerNode> rootNode)
     283{
     284    ASSERT(rootNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE);
     285    pushRootNodeCommon(rootNode);
     286}
    272287
    273288void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element)
    274289{
    275     ASSERT(!m_top); // <html> should always be the bottom of the stack.
    276290    ASSERT(element->hasTagName(HTMLNames::htmlTag));
    277     ASSERT(!m_htmlElement);
    278     m_htmlElement = element.get();
    279     pushCommon(element);
     291    pushRootNodeCommon(element);
     292}
     293   
     294void HTMLElementStack::pushRootNodeCommon(PassRefPtr<ContainerNode> rootNode)
     295{
     296    ASSERT(!m_top);
     297    ASSERT(!m_rootNode);
     298    m_rootNode = rootNode.get();
     299    pushCommon(rootNode);
    280300}
    281301
     
    301321    ASSERT(!element->hasTagName(HTMLNames::headTag));
    302322    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
    303     ASSERT(m_htmlElement);
     323    ASSERT(m_rootNode);
    304324    pushCommon(element);
    305325}
     
    313333    ASSERT(!element->hasTagName(HTMLNames::headTag));
    314334    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
    315     ASSERT(m_htmlElement);
     335    ASSERT(m_rootNode);
    316336    if (recordBelow == m_top) {
    317337        push(element);
     
    373393{
    374394    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
    375         if (pos->element() == element)
     395        if (pos->node() == element)
    376396            return pos;
    377397    }
     
    382402{
    383403    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
    384         if (pos->element()->hasLocalName(tagName))
     404        if (pos->node()->hasLocalName(tagName))
    385405            return pos;
    386406    }
     
    398418}
    399419
    400 template <bool isMarker(Element*)>
     420template <bool isMarker(ContainerNode*)>
    401421bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
    402422{
    403423    for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) {
    404         Element* element = pos->element();
    405         if (element->hasLocalName(targetTag))
     424        ContainerNode* node = pos->node();
     425        if (node->hasLocalName(targetTag))
    406426            return true;
    407         if (isMarker(element))
     427        if (isMarker(node))
    408428            return false;
    409429    }
     
    428448{
    429449    for (ElementRecord* record = m_top.get(); record; record = record->next()) {
    430         Element* element = record->element();
    431         if (isNumberedHeaderElement(element))
     450        if (isScopeMarker(record->node()))
     451            return false;
     452        if (isNumberedHeaderElement(record->element()))
    432453            return true;
    433         if (isScopeMarker(element))
    434             return false;
    435454    }
    436455    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
     
    508527Element* HTMLElementStack::htmlElement() const
    509528{
    510     ASSERT(m_htmlElement);
    511     return m_htmlElement;
     529    ASSERT(m_rootNode);
     530    return toElement(m_rootNode);
    512531}
    513532
     
    523542    return m_bodyElement;
    524543}
    525 
    526 void HTMLElementStack::pushCommon(PassRefPtr<Element> element)
    527 {
    528     ASSERT(m_htmlElement);
    529     m_top = adoptPtr(new ElementRecord(element, m_top.release()));
    530     top()->beginParsingChildren();
     544   
     545ContainerNode* HTMLElementStack::rootNode() const
     546{
     547    ASSERT(m_rootNode);
     548    return m_rootNode;
     549}
     550
     551void HTMLElementStack::pushCommon(PassRefPtr<ContainerNode> node)
     552{
     553    ASSERT(m_rootNode);
     554    m_top = adoptPtr(new ElementRecord(node, m_top.release()));
     555    topNode()->beginParsingChildren();
    531556}
    532557
  • trunk/Source/WebCore/html/parser/HTMLElementStack.h

    r76248 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    2728#define HTMLElementStack_h
    2829
     30#include "Element.h"
    2931#include <wtf/Forward.h>
    3032#include <wtf/Noncopyable.h>
     
    3537namespace WebCore {
    3638
     39class ContainerNode;
     40class DocumentFragment;
    3741class Element;
    3842class QualifiedName;
     
    5155        ~ElementRecord(); // Public for ~PassOwnPtr()
    5256   
    53         Element* element() const { return m_element.get(); }
     57        Element* element() const { return toElement(m_node.get()); }
     58        ContainerNode* node() const { return m_node.get(); }
    5459        void replaceElement(PassRefPtr<Element>);
    5560
     
    6166        friend class HTMLElementStack;
    6267
    63         ElementRecord(PassRefPtr<Element>, PassOwnPtr<ElementRecord>);
     68        ElementRecord(PassRefPtr<ContainerNode>, PassOwnPtr<ElementRecord>);
    6469
    6570        PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
    6671        void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
    6772
    68         RefPtr<Element> m_element;
     73        RefPtr<ContainerNode> m_node;
    6974        OwnPtr<ElementRecord> m_next;
    7075    };
     
    7681        ASSERT(m_top->element());
    7782        return m_top->element();
     83    }
     84   
     85    ContainerNode* topNode() const
     86    {
     87        ASSERT(m_top->node());
     88        return m_top->node();
    7889    }
    7990
     
    8798
    8899    void push(PassRefPtr<Element>);
     100    void pushRootNode(PassRefPtr<ContainerNode>);
    89101    void pushHTMLHtmlElement(PassRefPtr<Element>);
    90102    void pushHTMLHeadElement(PassRefPtr<Element>);
     
    132144    Element* headElement() const;
    133145    Element* bodyElement() const;
     146   
     147    ContainerNode* rootNode() const;
    134148
    135149#ifndef NDEBUG
     
    138152
    139153private:
    140     void pushCommon(PassRefPtr<Element>);
     154    void pushCommon(PassRefPtr<ContainerNode>);
     155    void pushRootNodeCommon(PassRefPtr<ContainerNode>);
    141156    void popCommon();
    142157    void removeNonTopCommon(Element*);
     
    144159    OwnPtr<ElementRecord> m_top;
    145160
    146     // We remember <html>, <head> and <body> as they are pushed. Their
    147     // ElementRecords keep them alive.  <html> is never popped.
     161    // We remember the root node, <head> and <body> as they are pushed. Their
     162    // ElementRecords keep them alive. The root node is never popped.
    148163    // FIXME: We don't currently require type-specific information about
    149164    // these elements so we haven't yet bothered to plumb the types all the
    150165    // way down through createElement, etc.
    151     Element* m_htmlElement;
     166    ContainerNode* m_rootNode;
    152167    Element* m_headElement;
    153168    Element* m_bodyElement;
  • trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp

    r79816 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    122123        || node->hasTagName(SVGNames::descTag)
    123124        || node->hasTagName(SVGNames::titleTag))
     125        return true;
     126    if (node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
    124127        return true;
    125128    if (node->namespaceURI() != xhtmlNamespaceURI)
     
    376379        // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm:
    377380        // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
    378         processFakeStartTag(htmlTag);
     381        // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
     382        // and instead use the DocumentFragment as a root node.
     383        m_tree.openElements()->pushRootNode(fragment);
    379384        resetInsertionModeAppropriately();
    380385        m_tree.setForm(closestFormAncestor(contextElement));
     
    409414{
    410415    ASSERT(!fragment->hasChildNodes());
    411 }
    412 
    413 void HTMLTreeBuilder::FragmentParsingContext::finished()
    414 {
    415     if (!m_contextElement)
    416         return;
    417    
    418     // The HTML5 spec says to return the children of the fragment's document
    419     // element when there is a context element (10.4.7).
    420     RefPtr<ContainerNode> documentElement = firstElementChild(m_fragment);
    421     m_fragment->removeChildren();
    422     ASSERT(documentElement);
    423     m_fragment->takeAllChildrenFrom(documentElement.get());
    424416}
    425417
     
    575567namespace {
    576568
    577 bool isLi(const Element* element)
     569bool isLi(const ContainerNode* element)
    578570{
    579571    return element->hasTagName(liTag);
    580572}
    581573
    582 bool isDdOrDt(const Element* element)
     574bool isDdOrDt(const ContainerNode* element)
    583575{
    584576    return element->hasTagName(ddTag)
     
    588580}
    589581
    590 template <bool shouldClose(const Element*)>
     582template <bool shouldClose(const ContainerNode*)>
    591583void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken& token)
    592584{
     
    594586    HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
    595587    while (1) {
    596         Element* node = nodeRecord->element();
     588        ContainerNode* node = nodeRecord->node();
    597589        if (shouldClose(node)) {
    598             processFakeEndTag(node->tagQName());
     590            ASSERT(node->isElementNode());
     591            processFakeEndTag(toElement(node)->tagQName());
    599592            break;
    600593        }
     
    787780    if (isNumberedHeaderTag(token.name())) {
    788781        processFakePEndTagIfPInButtonScope();
    789         if (isNumberedHeaderTag(m_tree.currentElement()->localName())) {
     782        if (isNumberedHeaderTag(m_tree.currentNode()->localName())) {
    790783            parseError(token);
    791784            m_tree.openElements()->pop();
     
    979972        if (m_tree.openElements()->inScope(rubyTag.localName())) {
    980973            m_tree.generateImpliedEndTags();
    981             if (!m_tree.currentElement()->hasTagName(rubyTag)) {
     974            if (!m_tree.currentNode()->hasTagName(rubyTag)) {
    982975                parseError(token);
    983976                m_tree.openElements()->popUntil(rubyTag.localName());
     
    10201013bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
    10211014{
    1022     if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
     1015    if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
    10231016        ASSERT(isParsingFragment());
    10241017        // FIXME: parse error
     
    11161109namespace {
    11171110
    1118 bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, Element* currentElement)
     1111bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, ContainerNode* currentElement)
    11191112{
    11201113    ASSERT(token.type() == HTMLToken::StartTag);
     
    14101403        }
    14111404        if (token.name() == optionTag) {
    1412             if (m_tree.currentElement()->hasTagName(optionTag)) {
     1405            if (m_tree.currentNode()->hasTagName(optionTag)) {
    14131406                AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
    14141407                processEndTag(endOption);
     
    14181411        }
    14191412        if (token.name() == optgroupTag) {
    1420             if (m_tree.currentElement()->hasTagName(optionTag)) {
     1413            if (m_tree.currentNode()->hasTagName(optionTag)) {
    14211414                AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
    14221415                processEndTag(endOption);
    14231416            }
    1424             if (m_tree.currentElement()->hasTagName(optgroupTag)) {
     1417            if (m_tree.currentNode()->hasTagName(optgroupTag)) {
    14251418                AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
    14261419                processEndTag(endOptgroup);
     
    15441537    HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
    15451538    while (1) {
    1546         Element* node = record->element();
     1539        ContainerNode* node = record->node();
    15471540        if (node->hasLocalName(token.name())) {
    15481541            m_tree.generateImpliedEndTags();
    1549             if (!m_tree.currentElement()->hasLocalName(token.name())) {
     1542            if (!m_tree.currentNode()->hasLocalName(token.name())) {
    15501543                parseError(token);
    15511544                // FIXME: This is either a bug in the spec, or a bug in our
     
    15541547                // We might have already popped the node for the token in
    15551548                // generateImpliedEndTags, just abort.
    1556                 if (!m_tree.openElements()->contains(node))
     1549                if (!m_tree.openElements()->contains(record->element()))
    15571550                    return;
    15581551            }
    1559             m_tree.openElements()->popUntilPopped(node);
     1552            m_tree.openElements()->popUntilPopped(record->element());
    15601553            return;
    15611554        }
     
    16171610        // 4.
    16181611        ASSERT(furthestBlock->isAbove(formattingElementRecord));
    1619         Element* commonAncestor = formattingElementRecord->next()->element();
     1612        ContainerNode* commonAncestor = formattingElementRecord->next()->node();
    16201613        // 5.
    16211614        HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement);
     
    16691662        else {
    16701663            commonAncestor->parserAddChild(lastNode->element());
    1671             if (lastNode->element()->parentElement()->attached() && !lastNode->element()->attached())
     1664            ASSERT(lastNode->node()->isElementNode());
     1665            ASSERT(lastNode->element()->parentNode());
     1666            if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached())
    16721667                lastNode->element()->lazyAttach();
    16731668        }
     
    17011696    HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
    17021697    while (1) {
    1703         Element* node = nodeRecord->element();
    1704         if (node == m_tree.openElements()->bottom()) {
     1698        ContainerNode* node = nodeRecord->node();
     1699        if (node == m_tree.openElements()->rootNode()) {
    17051700            ASSERT(isParsingFragment());
    17061701            last = true;
     
    18321827        }
    18331828        m_tree.generateImpliedEndTags();
    1834         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1829        if (!m_tree.currentNode()->hasLocalName(token.name()))
    18351830            parseError(token);
    18361831        m_tree.openElements()->popUntilPopped(token.name());
     
    19021897        }
    19031898        m_tree.generateImpliedEndTags();
    1904         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1899        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19051900            parseError(token);
    19061901        m_tree.openElements()->popUntilPopped(token.name());
     
    19271922        }
    19281923        m_tree.generateImpliedEndTagsWithExclusion(token.name());
    1929         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1924        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19301925            parseError(token);
    19311926        m_tree.openElements()->popUntilPopped(token.name());
     
    19381933        }
    19391934        m_tree.generateImpliedEndTagsWithExclusion(token.name());
    1940         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1935        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19411936            parseError(token);
    19421937        m_tree.openElements()->popUntilPopped(token.name());
     
    19501945        }
    19511946        m_tree.generateImpliedEndTagsWithExclusion(token.name());
    1952         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1947        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19531948            parseError(token);
    19541949        m_tree.openElements()->popUntilPopped(token.name());
     
    19611956        }
    19621957        m_tree.generateImpliedEndTags();
    1963         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1958        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19641959            parseError(token);
    19651960        m_tree.openElements()->popUntilNumberedHeaderElementPopped();
     
    19781973        }
    19791974        m_tree.generateImpliedEndTags();
    1980         if (!m_tree.currentElement()->hasLocalName(token.name()))
     1975        if (!m_tree.currentNode()->hasLocalName(token.name()))
    19811976            parseError(token);
    19821977        m_tree.openElements()->popUntilPopped(token.name());
     
    22222217        ASSERT(insertionMode() == InFramesetMode);
    22232218        if (token.name() == framesetTag) {
    2224             if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
     2219            if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
    22252220                parseError(token);
    22262221                return;
     
    22622257        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
    22632258        if (token.name() == optgroupTag) {
    2264             if (m_tree.currentElement()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag))
     2259            if (m_tree.currentNode()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag))
    22652260                processFakeEndTag(optionTag);
    2266             if (m_tree.currentElement()->hasTagName(optgroupTag)) {
     2261            if (m_tree.currentNode()->hasTagName(optgroupTag)) {
    22672262                m_tree.openElements()->pop();
    22682263                return;
     
    22952290        break;
    22962291    case InForeignContentMode:
    2297         if (token.name() == SVGNames::scriptTag && m_tree.currentElement()->hasTagName(SVGNames::scriptTag)) {
     2292        if (token.name() == SVGNames::scriptTag && m_tree.currentNode()->hasTagName(SVGNames::scriptTag)) {
    22982293            notImplemented();
    22992294            return;
    23002295        }
    2301         if (m_tree.currentElement()->namespaceURI() != xhtmlNamespaceURI) {
     2296        if (m_tree.currentNode()->namespaceURI() != xhtmlNamespaceURI) {
    23022297            // FIXME: This code just wants an Element* iterator, instead of an ElementRecord*
    23032298            HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
    2304             if (!nodeRecord->element()->hasLocalName(token.name()))
     2299            if (!nodeRecord->node()->hasLocalName(token.name()))
    23052300                parseError(token);
    23062301            while (1) {
    2307                 if (nodeRecord->element()->hasLocalName(token.name())) {
     2302                if (nodeRecord->node()->hasLocalName(token.name())) {
    23082303                    m_tree.openElements()->popUntilPopped(nodeRecord->element());
    23092304                    resetForeignInsertionMode();
     
    23112306                }
    23122307                nodeRecord = nodeRecord->next();
    2313                 if (nodeRecord->element()->namespaceURI() == xhtmlNamespaceURI)
     2308               
     2309                // Fragments containing only foreign content will not have a
     2310                // node with the XHTML namespace URI, so we should stop walking
     2311                // the element stack when we encounter the DocumentFragment itself.
     2312                if (nodeRecord->node()->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
     2313                    ASSERT(isParsingFragment());
     2314                    break;
     2315                }
     2316               
     2317                if (nodeRecord->node()->namespaceURI() == xhtmlNamespaceURI)
    23142318                    break;
    23152319            }
     
    26102614    case InSelectMode:
    26112615        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode);
    2612         if (m_tree.currentElement() != m_tree.openElements()->htmlElement())
     2616        if (m_tree.currentNode() != m_tree.openElements()->rootNode())
    26132617            parseError(token);
    26142618        break;
    26152619    case InColumnGroupMode:
    2616         if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
     2620        if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
    26172621            ASSERT(isParsingFragment());
    26182622            return; // FIXME: Should we break here instead of returning?
     
    26432647        return;
    26442648    }
    2645     ASSERT(m_tree.openElements()->top());
     2649    ASSERT(m_tree.currentNode());
    26462650    m_tree.openElements()->popAll();
    26472651}
     
    27952799void HTMLTreeBuilder::finished()
    27962800{
     2801    if (isParsingFragment())
     2802        return;
     2803   
    27972804    ASSERT(m_document);
    2798     if (isParsingFragment()) {
    2799         m_fragmentContext.finished();
    2800         return;
    2801     }
    2802 
    28032805    // Warning, this may detach the parser. Do not do anything else after this.
    28042806    m_document->finishedParsing();
  • trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h

    r78286 r80201  
    11/*
    22 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     3 * Copyright (C) 2011 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    179180    void closeTheCell();
    180181
    181     template <bool shouldClose(const Element*)>
     182    template <bool shouldClose(const ContainerNode*)>
    182183    void processCloseWhenNestedTag(AtomicHTMLToken&);
    183184
     
    216217        FragmentScriptingPermission scriptingPermission() const { ASSERT(m_fragment); return m_scriptingPermission; }
    217218
    218         void finished();
    219 
    220219    private:
    221220        DocumentFragment* m_fragment;
Note: See TracChangeset for help on using the changeset viewer.