Changeset 62468 in webkit


Ignore:
Timestamp:
Jul 4, 2010 2:15:44 PM (14 years ago)
Author:
eric@webkit.org
Message:

2010-07-02 Eric Seidel <eric@webkit.org>

Reviewed by Adam Barth.

HTMLTreeBuilder needs an adoption agency
https://bugs.webkit.org/show_bug.cgi?id=41453

Added new adoption01 suite for testing adoption agency
bugs. Right now only the simplest adoption test passes.
I'll be adding more in future commits.

  • html5lib/resources/adoption01.dat: Added.
  • html5lib/runner-expected-html5.txt:
  • html5lib/runner-expected.txt:
  • html5lib/runner.html:

2010-07-01 Eric Seidel <eric@webkit.org>

Reviewed by Adam Barth.

HTMLTreeBuilder needs an adoption agency
https://bugs.webkit.org/show_bug.cgi?id=41453

This changes some test results, but only makes the simplest
adoption agency cases pass. I think the code is likely
very close, but further iteration to make this change larger
seems counter-productive. I recommend we check in this
progression and work from here.

  • dom/ContainerNode.cpp: (WebCore::ContainerNode::addChildCommon):
    • Make sure callers don't assume this will reparent.

(WebCore::ContainerNode::parserAddChild):

  • Update comment to document lack of reparenting behavior.
  • html/HTMLElementStack.cpp: (WebCore::HTMLElementStack::ElementRecord::ElementRecord): (WebCore::HTMLElementStack::ElementRecord::~ElementRecord): (WebCore::HTMLElementStack::ElementRecord::replaceElement): (WebCore::HTMLElementStack::ElementRecord::isAbove):
    • Added for debugging.

(WebCore::HTMLElementStack::pushHTMLHtmlElement):
(WebCore::HTMLElementStack::insertAbove):

  • Needed for the adoption agency.

(WebCore::HTMLElementStack::topRecord):
(WebCore::HTMLElementStack::bottom):
(WebCore::HTMLElementStack::removeHTMLHeadElement):
(WebCore::HTMLElementStack::remove):
(WebCore::HTMLElementStack::find):
(WebCore::HTMLElementStack::topmost):
(WebCore::HTMLElementStack::contains):
(WebCore::HTMLElementStack::htmlElement):
(WebCore::HTMLElementStack::headElement):
(WebCore::HTMLElementStack::bodyElement):
(WebCore::HTMLElementStack::pushCommon):
(WebCore::HTMLElementStack::removeNonTopCommon):

  • Fix the name to match top/bottom.
  • html/HTMLElementStack.h: (WebCore::HTMLElementStack::ElementRecord::element): (WebCore::HTMLElementStack::ElementRecord::next): (WebCore::HTMLElementStack::ElementRecord::releaseNext): (WebCore::HTMLElementStack::ElementRecord::setNext):
  • html/HTMLFormattingElementList.cpp: (WebCore::HTMLFormattingElementList::closestElementInScopeWithName): (WebCore::HTMLFormattingElementList::contains): (WebCore::HTMLFormattingElementList::find): (WebCore::HTMLFormattingElementList::remove):
  • html/HTMLFormattingElementList.h: (WebCore::HTMLFormattingElementList::isEmpty): (WebCore::HTMLFormattingElementList::size):
  • html/HTMLTreeBuilder.cpp: (WebCore::HTMLTreeBuilder::processStartTag): (WebCore::HTMLTreeBuilder::furthestBlockForFormattingElement):
    • Part of the Adoption Agency algorithm.

(WebCore::HTMLTreeBuilder::findFosterParentFor):

  • Used to move mis-nested content out of tables. This doesn't seem to work quite right yet.

(WebCore::HTMLTreeBuilder::reparentChildren):
(WebCore::HTMLTreeBuilder::callTheAdoptionAgency):

  • The ridiculously long/complicated adoption agency algorithm from HTML5.

(WebCore::HTMLTreeBuilder::processEndTag):

  • html/HTMLTreeBuilder.h:
Location:
trunk
Files:
1 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r62465 r62468  
     12010-07-02  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Adam Barth.
     4
     5        HTMLTreeBuilder needs an adoption agency
     6        https://bugs.webkit.org/show_bug.cgi?id=41453
     7
     8        Added new adoption01 suite for testing adoption agency
     9        bugs.  Right now only the simplest adoption test passes.
     10        I'll be adding more in future commits.
     11
     12        * html5lib/resources/adoption01.dat: Added.
     13        * html5lib/runner-expected-html5.txt:
     14        * html5lib/runner-expected.txt:
     15        * html5lib/runner.html:
     16
    1172010-07-04  Robert Hogan  <robert@webkit.org>
    218
  • trunk/LayoutTests/html5lib/runner-expected-html5.txt

    r62460 r62468  
    130130|           <a>
    131131|             "Y"
    132 |             "Z"
     132|           "Z"
    133133Expected:
    134134| <html>
     
    389389|   <body>
    390390|     <b>
    391 |       <p>
     391|     <p>
     392|       <b>
    392393|         "TEST"
    393394Expected:
     
    436437|           <b>
    437438|             "cruel"
    438 |             "world"
     439|         "world"
    439440Expected:
    440441| <html>
     
    526527|         <cite>
    527528|           "B"
    528 |           <div>
    529 |             "C"
    530 |             "D"
     529|       <div>
     530|         <b>
     531|           "C"
     532|           "D"
    531533Expected:
    532534| <html>
     
    562564|                             <i>
    563565|                               <i>
    564 |                                 <div>
    565 |                                   "X"
    566 |                                   "TEST"
     566|             <i>
     567|               <i>
     568|                 <i>
     569|                   <div>
     570|                     <b>
     571|                       "X"
     572|                       "TEST"
    567573Expected:
    568574| <html>
     
    698704|           <i>
    699705|             " ghi "
    700 |             <p>
     706|         <i>
     707|           <p>
     708|             <b>
    701709|               " jkl "
    702710Expected:
     
    728736|           <i>
    729737|             " ghi "
    730 |             <p>
     738|         <i>
     739|           <p>
     740|             <b>
    731741|               " jkl "
    732742|               " mno"
     
    760770|           <i>
    761771|             " ghi "
    762 |             <p>
     772|         <i>
     773|         <p>
     774|           <i>
     775|             <b>
    763776|               " jkl "
    764777|               " mno "
     
    793806|           <i>
    794807|             " ghi "
    795 |             <p>
     808|         <i>
     809|         <p>
     810|           <i>
     811|             <b>
    796812|               " jkl "
    797813|               " mno "
     
    828844|           <i>
    829845|             " ghi "
    830 |             <p>
     846|         <i>
     847|         <p>
     848|           <i>
     849|             <b>
    831850|               " jkl "
    832851|               " mno "
     
    863882|           <i>
    864883|             " ghi "
    865 |             <p>
     884|         <i>
     885|         <p>
     886|           <i>
     887|             <b>
    866888|               " jkl "
    867889|               " mno "
    868890|               " pqr "
    869 |             " stu"
     891|         " stu"
    870892Expected:
    871893| <html>
     
    10131035|       <strike>
    10141036|         <code>
    1015 |           <code>
    1016 |             <code>
    1017 |               <code>
    1018 |                 <strike>
     1037|       <code>
     1038|         <code>
     1039|           <strike>
    10191040Expected:
    10201041| <html>
     
    12521273|                     <b>
    12531274|                       <em>
    1254 |                         <li>
     1275|                     <li>
    12551276Expected:
    12561277| <html>
     
    19011922|       <nobr>
    19021923|         <nobr>
     1924|         <nobr>
    19031925|           <nobr>
    1904 |             <nobr>
    19051926Expected:
    19061927| <!DOCTYPE html>
     
    31013122|       "a"
    31023123|       <div>
    3103 |       <div>
     3124|     <div>
     3125|       <b>
    31043126|         "y"
    31053127Expected:
     
    31213143|   <body>
    31223144|     <a>
    3123 |       <div>
     3145|     <div>
     3146|       <a>
    31243147|         <p>
    31253148Expected:
     
    54895512
    54905513resources/comments01.dat: PASS
     5514
     5515resources/adoption01.dat:
     55162
     55173
     55184
     55195
     55206
     5521
     5522Test 2 of 6 in resources/adoption01.dat failed. Input:
     5523<a>1<p>2</a>3</p>
     5524Got:
     5525| <html>
     5526|   <head>
     5527|   <body>
     5528|     <a>
     5529|       "1"
     5530|     <p>
     5531|       <a>
     5532|         "2"
     5533|         "3"
     5534Expected:
     5535| <html>
     5536|   <head>
     5537|   <body>
     5538|     <a>
     5539|       "1"
     5540|     <p>
     5541|       <a>
     5542|         "2"
     5543|       "3"
     5544
     5545Test 3 of 6 in resources/adoption01.dat failed. Input:
     5546<a>1<button>2</a>3</button>
     5547Got:
     5548| <html>
     5549|   <head>
     5550|   <body>
     5551|     <a>
     5552|       "1"
     5553|       <a>
     5554|         <button>
     5555|           "2"
     5556|           "3"
     5557Expected:
     5558| <html>
     5559|   <head>
     5560|   <body>
     5561|     <a>
     5562|       "1"
     5563|       <button>
     5564|         "2"
     5565|     "3"
     5566
     5567Test 4 of 6 in resources/adoption01.dat failed. Input:
     5568<a>1<b>2</a>3</b>
     5569Got:
     5570| <html>
     5571|   <head>
     5572|   <body>
     5573|     <a>
     5574|       "1"
     5575|       <a>
     5576|         <b>
     5577|           "2"
     5578|       "3"
     5579Expected:
     5580| <html>
     5581|   <head>
     5582|   <body>
     5583|     <a>
     5584|       "1"
     5585|       <b>
     5586|         "2"
     5587|     <b>
     5588|       "3"
     5589
     5590Test 5 of 6 in resources/adoption01.dat failed. Input:
     5591<a>1<div>2<div>3</a>4</div>5</div>
     5592Got:
     5593| <html>
     5594|   <head>
     5595|   <body>
     5596|     <a>
     5597|       "1"
     5598|     <div>
     5599|       <a>
     5600|         "2"
     5601|         <div>
     5602|           "3"
     5603|           "4"
     5604|     "5"
     5605Expected:
     5606| <html>
     5607|   <head>
     5608|   <body>
     5609|     <a>
     5610|       "1"
     5611|     <div>
     5612|       <a>
     5613|         "2"
     5614|       <div>
     5615|         <a>
     5616|           "3"
     5617|         "4"
     5618|       "5"
     5619
     5620Test 6 of 6 in resources/adoption01.dat failed. Input:
     5621<table><a>1<p>2</a>3</p>
     5622Got:
     5623| <html>
     5624|   <head>
     5625|   <body>
     5626|     <table>
     5627Expected:
     5628| <html>
     5629|   <head>
     5630|   <body>
     5631|     <a>
     5632|       "1"
     5633|     <p>
     5634|       <a>
     5635|         "2"
     5636|       "3"
     5637|     <table>
    54915638#EOF
  • trunk/LayoutTests/html5lib/runner-expected.txt

    r62460 r62468  
    48914891
    48924892resources/comments01.dat: PASS
     4893
     4894resources/adoption01.dat:
     48951
     48966
     4897
     4898Test 1 of 6 in resources/adoption01.dat failed. Input:
     4899<a><p></a></p>
     4900Got:
     4901| <html>
     4902|   <head>
     4903|   <body>
     4904|     <a>
     4905|     <p>
     4906Expected:
     4907| <html>
     4908|   <head>
     4909|   <body>
     4910|     <a>
     4911|     <p>
     4912|       <a>
     4913
     4914Test 6 of 6 in resources/adoption01.dat failed. Input:
     4915<table><a>1<p>2</a>3</p>
     4916Got:
     4917| <html>
     4918|   <head>
     4919|   <body>
     4920|     <a>
     4921|       "1"
     4922|       <p>
     4923|         "2"
     4924|         "3"
     4925|     <table>
     4926|       <tbody>
     4927Expected:
     4928| <html>
     4929|   <head>
     4930|   <body>
     4931|     <a>
     4932|       "1"
     4933|     <p>
     4934|       <a>
     4935|         "2"
     4936|       "3"
     4937|     <table>
  • trunk/LayoutTests/html5lib/runner.html

    r62237 r62468  
    5959        'resources/entities01.dat',
    6060        'resources/entities02.dat',
    61         'resources/comments01.dat'
     61        'resources/comments01.dat',
     62        'resources/adoption01.dat'
    6263    ],
    6364    tests = [],
  • trunk/WebCore/ChangeLog

    r62467 r62468  
     12010-07-01  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Adam Barth.
     4
     5        HTMLTreeBuilder needs an adoption agency
     6        https://bugs.webkit.org/show_bug.cgi?id=41453
     7
     8        This changes some test results, but only makes the simplest
     9        adoption agency cases pass.  I think the code is likely
     10        very close, but further iteration to make this change larger
     11        seems counter-productive.  I recommend we check in this
     12        progression and work from here.
     13
     14        * dom/ContainerNode.cpp:
     15        (WebCore::ContainerNode::addChildCommon):
     16         - Make sure callers don't assume this will reparent.
     17        (WebCore::ContainerNode::parserAddChild):
     18         - Update comment to document lack of reparenting behavior.
     19        * html/HTMLElementStack.cpp:
     20        (WebCore::HTMLElementStack::ElementRecord::ElementRecord):
     21        (WebCore::HTMLElementStack::ElementRecord::~ElementRecord):
     22        (WebCore::HTMLElementStack::ElementRecord::replaceElement):
     23        (WebCore::HTMLElementStack::ElementRecord::isAbove):
     24         - Added for debugging.
     25        (WebCore::HTMLElementStack::pushHTMLHtmlElement):
     26        (WebCore::HTMLElementStack::insertAbove):
     27         - Needed for the adoption agency.
     28        (WebCore::HTMLElementStack::topRecord):
     29        (WebCore::HTMLElementStack::bottom):
     30        (WebCore::HTMLElementStack::removeHTMLHeadElement):
     31        (WebCore::HTMLElementStack::remove):
     32        (WebCore::HTMLElementStack::find):
     33        (WebCore::HTMLElementStack::topmost):
     34        (WebCore::HTMLElementStack::contains):
     35        (WebCore::HTMLElementStack::htmlElement):
     36        (WebCore::HTMLElementStack::headElement):
     37        (WebCore::HTMLElementStack::bodyElement):
     38        (WebCore::HTMLElementStack::pushCommon):
     39        (WebCore::HTMLElementStack::removeNonTopCommon):
     40         - Fix the name to match top/bottom.
     41        * html/HTMLElementStack.h:
     42        (WebCore::HTMLElementStack::ElementRecord::element):
     43        (WebCore::HTMLElementStack::ElementRecord::next):
     44        (WebCore::HTMLElementStack::ElementRecord::releaseNext):
     45        (WebCore::HTMLElementStack::ElementRecord::setNext):
     46        * html/HTMLFormattingElementList.cpp:
     47        (WebCore::HTMLFormattingElementList::closestElementInScopeWithName):
     48        (WebCore::HTMLFormattingElementList::contains):
     49        (WebCore::HTMLFormattingElementList::find):
     50        (WebCore::HTMLFormattingElementList::remove):
     51        * html/HTMLFormattingElementList.h:
     52        (WebCore::HTMLFormattingElementList::isEmpty):
     53        (WebCore::HTMLFormattingElementList::size):
     54        * html/HTMLTreeBuilder.cpp:
     55        (WebCore::HTMLTreeBuilder::processStartTag):
     56        (WebCore::HTMLTreeBuilder::furthestBlockForFormattingElement):
     57         - Part of the Adoption Agency algorithm.
     58        (WebCore::HTMLTreeBuilder::findFosterParentFor):
     59         - Used to move mis-nested content out of tables.
     60           This doesn't seem to work quite right yet.
     61        (WebCore::HTMLTreeBuilder::reparentChildren):
     62        (WebCore::HTMLTreeBuilder::callTheAdoptionAgency):
     63         - The ridiculously long/complicated adoption agency algorithm from HTML5.
     64        (WebCore::HTMLTreeBuilder::processEndTag):
     65        * html/HTMLTreeBuilder.h:
     66
    1672010-07-04  Justin Schuh  <jschuh@chromium.org>
    268
  • trunk/WebCore/dom/ContainerNode.cpp

    r62086 r62468  
    540540void ContainerNode::addChildCommon(Node* newChild)
    541541{
     542    ASSERT(!newChild->parent()); // Use appendChild if you need to handle reparenting.
    542543    forbidEventDispatch();
    543544    Node* last = m_lastChild;
     
    556557    ASSERT(newChild);
    557558    // This function is only used during parsing.
    558     // It does not send any DOM mutation events.
     559    // It does not send any DOM mutation events or handle reparenting.
    559560
    560561    addChildCommon(newChild.get());
  • trunk/WebCore/html/HTMLElementStack.cpp

    r62438 r62468  
    3939using namespace HTMLNames;
    4040
    41 class HTMLElementStack::ElementRecord : public Noncopyable {
    42 public:
    43     ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
    44         : m_element(element)
    45         , m_next(next)
    46     {
    47     }
    48 
    49     Element* element() const { return m_element.get(); }
    50     ElementRecord* next() const { return m_next.get(); }
    51     PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
    52     void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
    53 
    54 private:
    55     RefPtr<Element> m_element;
    56     OwnPtr<ElementRecord> m_next;
    57 };
     41HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
     42    : m_element(element)
     43    , m_next(next)
     44{
     45    ASSERT(m_element);
     46}
     47
     48HTMLElementStack::ElementRecord::~ElementRecord()
     49{
     50}
     51
     52void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<Element> element)
     53{
     54    ASSERT(element);
     55    // FIXME: Should this call finishParsingChildren?
     56    m_element = element;
     57}
     58
     59bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
     60{
     61    for (ElementRecord* below = next(); below; below = below->next()) {
     62        if (below == other)
     63            return true;
     64    }
     65    return false;
     66}
    5867
    5968HTMLElementStack::HTMLElementStack()
     
    105114void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element)
    106115{
     116    ASSERT(!m_top); // <html> should always be the bottom of the stack.
    107117    ASSERT(element->hasTagName(HTMLNames::htmlTag));
    108118    ASSERT(!m_htmlElement);
     
    136146}
    137147
     148void HTMLElementStack::insertAbove(PassRefPtr<Element> element, ElementRecord* recordBelow)
     149{
     150    ASSERT(element);
     151    ASSERT(recordBelow);
     152    ASSERT(m_top);
     153    ASSERT(!element->hasTagName(HTMLNames::htmlTag));
     154    ASSERT(!element->hasTagName(HTMLNames::headTag));
     155    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
     156    ASSERT(m_htmlElement);
     157    if (recordBelow == m_top) {
     158        push(element);
     159        return;
     160    }
     161
     162    for (ElementRecord* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) {
     163        if (recordAbove->next() != recordBelow)
     164            continue;
     165
     166        recordAbove->setNext(new ElementRecord(element, recordAbove->releaseNext()));
     167        recordAbove->next()->element()->beginParsingChildren();
     168        return;
     169    }
     170    ASSERT_NOT_REACHED();
     171}
     172
     173HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const
     174{
     175    return m_top.get();
     176}
     177
    138178Element* HTMLElementStack::top() const
    139179{
    140180    return m_top->element();
     181}
     182
     183Element* HTMLElementStack::bottom() const
     184{
     185    return htmlElement();
    141186}
    142187
     
    149194    }
    150195    m_headElement = 0;
    151     removeNonFirstCommon(element);
     196    removeNonTopCommon(element);
    152197}
    153198
     
    159204        return;
    160205    }
    161     removeNonFirstCommon(element);
    162 }
    163 
    164 bool HTMLElementStack::contains(Element* element) const
     206    removeNonTopCommon(element);
     207}
     208
     209HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const
    165210{
    166211    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
    167212        if (pos->element() == element)
    168             return true;
    169     }
    170     return false;
     213            return pos;
     214    }
     215    return 0;
     216}
     217
     218HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const
     219{
     220    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
     221        if (pos->element()->hasLocalName(tagName))
     222            return pos;
     223    }
     224    return 0;
     225}
     226
     227bool HTMLElementStack::contains(Element* element) const
     228{
     229    return !!find(element);
    171230}
    172231
    173232namespace {
    174233
    175 inline bool isScopeMarker(const Element* element)
     234inline bool isScopeMarker(Element* element)
    176235{
    177236    return element->hasTagName(appletTag)
     237        || element->hasTagName(buttonTag)
    178238        || element->hasTagName(captionTag)
    179         || element->hasTagName(appletTag)
    180239        || element->hasTagName(htmlTag)
     240        || element->hasTagName(marqueeTag)
     241        || element->hasTagName(objectTag)
    181242        || element->hasTagName(tableTag)
    182243        || element->hasTagName(tdTag)
    183244        || element->hasTagName(thTag)
    184         || element->hasTagName(buttonTag)
    185         || element->hasTagName(marqueeTag)
    186         || element->hasTagName(objectTag)
    187245#if ENABLE(SVG_FOREIGN_OBJECT)
    188246        || element->hasTagName(SVGNames::foreignObjectTag)
     
    191249}
    192250
    193 inline bool isListItemScopeMarker(const Element* element)
     251inline bool isListItemScopeMarker(Element* element)
    194252{
    195253    return isScopeMarker(element)
     
    197255        || element->hasTagName(ulTag);
    198256}
    199 inline bool isTableScopeMarker(const Element* element)
     257inline bool isTableScopeMarker(Element* element)
    200258{
    201259    return element->hasTagName(htmlTag)
     
    205263}
    206264
    207 template <bool isMarker(const Element*)>
     265template <bool isMarker(Element*)>
    208266bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
    209267{
     
    247305}
    248306
    249 Element* HTMLElementStack::htmlElement()
     307Element* HTMLElementStack::htmlElement() const
    250308{
    251309    ASSERT(m_htmlElement);
     
    253311}
    254312
    255 Element* HTMLElementStack::headElement()
     313Element* HTMLElementStack::headElement() const
    256314{
    257315    ASSERT(m_headElement);
     
    259317}
    260318
    261 Element* HTMLElementStack::bodyElement()
     319Element* HTMLElementStack::bodyElement() const
    262320{
    263321    ASSERT(m_bodyElement);
     
    267325void HTMLElementStack::pushCommon(PassRefPtr<Element> element)
    268326{
     327    ASSERT(m_htmlElement);
    269328    m_top.set(new ElementRecord(element, m_top.release()));
    270329    top()->beginParsingChildren();
     
    280339}
    281340
    282 void HTMLElementStack::removeNonFirstCommon(Element* element)
     341void HTMLElementStack::removeNonTopCommon(Element* element)
    283342{
    284343    ASSERT(!element->hasTagName(HTMLNames::htmlTag));
    285344    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
    286     ElementRecord* pos = m_top.get();
    287     ASSERT(pos->element() != element);
    288     while (pos->next()) {
     345    ASSERT(top() != element);
     346    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
    289347        if (pos->next()->element() == element) {
    290348            // FIXME: Is it OK to call finishParsingChildren()
  • trunk/WebCore/html/HTMLElementStack.h

    r62438 r62468  
    2727#define HTMLElementStack_h
    2828
    29 #include <wtf/Forward.h>
    3029#include <wtf/Noncopyable.h>
    3130#include <wtf/OwnPtr.h>
     31#include <wtf/PassOwnPtr.h>
     32#include <wtf/RefPtr.h>
    3233
    3334namespace WebCore {
     
    3637class Element;
    3738
     39// NOTE: The HTML5 spec uses a backwards (grows downward) stack.  We're using
     40// more standard (grows upwards) stack terminology here.
    3841class HTMLElementStack : public Noncopyable {
    3942public:
     
    4144    ~HTMLElementStack();
    4245
     46    class ElementRecord : public Noncopyable {
     47    public:
     48        ~ElementRecord(); // Public for ~PassOwnPtr()
     49   
     50        Element* element() const { return m_element.get(); }
     51        void replaceElement(PassRefPtr<Element>);
     52
     53        bool isAbove(ElementRecord*) const;
     54
     55        ElementRecord* next() const { return m_next.get(); }
     56
     57    private:
     58        friend class HTMLElementStack;
     59
     60        ElementRecord(PassRefPtr<Element>, PassOwnPtr<ElementRecord>);
     61
     62        PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
     63        void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
     64
     65        RefPtr<Element> m_element;
     66        OwnPtr<ElementRecord> m_next;
     67    };
     68   
    4369    Element* top() const;
     70    ElementRecord* topRecord() const;
     71    Element* bottom() const;
     72    ElementRecord* find(Element*) const;
     73    ElementRecord* topmost(const AtomicString& tagName) const;
     74
     75    void insertAbove(PassRefPtr<Element>, ElementRecord*);
    4476
    4577    void push(PassRefPtr<Element>);
     
    6496    bool inTableScope(const AtomicString& tagName) const;
    6597
    66     Element* htmlElement();
    67     Element* headElement();
    68     Element* bodyElement();
     98    Element* htmlElement() const;
     99    Element* headElement() const;
     100    Element* bodyElement() const;
    69101
    70     // Public so free functions can use it, but defined privately.
    71     class ElementRecord;
    72102private:
    73103    void pushCommon(PassRefPtr<Element>);
    74104    void popCommon();
    75     void removeNonFirstCommon(Element*);
     105    void removeNonTopCommon(Element*);
    76106
    77107    OwnPtr<ElementRecord> m_top;
  • trunk/WebCore/html/HTMLFormattingElementList.cpp

    r62235 r62468  
    6565}
    6666
     67bool HTMLFormattingElementList::Entry::operator==(const Entry& other) const
     68{
     69    return element() == other.element();
     70}
     71
     72bool HTMLFormattingElementList::Entry::operator!=(const Entry& other) const
     73{
     74    return element() != other.element();
     75}
     76
    6777HTMLFormattingElementList::HTMLFormattingElementList()
    6878{
     
    7383}
    7484
     85Element* HTMLFormattingElementList::closestElementInScopeWithName(const AtomicString& targetName)
     86{
     87    for (unsigned i = 1; i <= m_entries.size(); ++i) {
     88        const Entry& entry = m_entries[m_entries.size() - i];
     89        if (entry.isMarker())
     90            return 0;
     91        if (entry.element()->hasLocalName(targetName))
     92            return entry.element();
     93    }
     94    return 0;
     95}
     96
     97bool HTMLFormattingElementList::contains(Element* element)
     98{
     99    return !!find(element);
     100}
     101
     102HTMLFormattingElementList::Entry* HTMLFormattingElementList::find(Element* element)
     103{
     104    size_t index = m_entries.find(element);
     105    if (index != notFound) {
     106        // This is somewhat of a hack, and is why this method can't be const.
     107        return &m_entries[index];
     108    }
     109    return 0;
     110}
     111
    75112void HTMLFormattingElementList::append(Element* element)
    76113{
    77114    m_entries.append(element);
     115}
     116
     117void HTMLFormattingElementList::remove(Element* element)
     118{
     119    size_t index = m_entries.find(element);
     120    if (index != notFound)
     121        m_entries.remove(index);
    78122}
    79123
  • trunk/WebCore/html/HTMLFormattingElementList.h

    r62235 r62468  
    3333namespace WebCore {
    3434
     35class AtomicString;
    3536class Element;
    3637
     
    4041    HTMLFormattingElementList();
    4142    ~HTMLFormattingElementList();
    42 
    43     bool isEmpty() const { return !size(); }
    44     size_t size() const { return m_entries.size(); }
    45 
    46     void append(Element*);
    47     void clearToLastMarker();
    4843
    4944    // Ideally Entry would be private, but HTMLTreeBuilder has to coordinate
     
    6257        void replaceElement(PassRefPtr<Element>);
    6358
     59        // Needed for use with Vector.
     60        bool operator==(const Entry&) const;
     61        bool operator!=(const Entry&) const;
     62
    6463    private:
    6564        RefPtr<Element> m_element;
    6665    };
     66
     67    bool isEmpty() const { return !size(); }
     68    size_t size() const { return m_entries.size(); }
     69
     70    Element* closestElementInScopeWithName(const AtomicString&);
     71
     72    Entry* find(Element*);
     73    bool contains(Element*);
     74    void append(Element*);
     75    void remove(Element*);
     76    void clearToLastMarker();
    6777
    6878    const Entry& operator[](size_t i) const { return m_entries[i]; }
  • trunk/WebCore/html/HTMLTreeBuilder.cpp

    r62460 r62468  
    3232#include "Element.h"
    3333#include "Frame.h"
     34#include "HTMLDocument.h"
    3435#include "HTMLElementFactory.h"
     36#include "HTMLHtmlElement.h"
     37#include "HTMLNames.h"
    3538#include "HTMLScriptElement.h"
     39#include "HTMLToken.h"
    3640#include "HTMLTokenizer.h"
    37 #include "HTMLToken.h"
    38 #include "HTMLDocument.h"
    39 #include "HTMLHtmlElement.h"
    4041#include "LegacyHTMLDocumentParser.h"
    41 #include "HTMLNames.h"
    4242#include "LegacyHTMLTreeBuilder.h"
    4343#include "NotImplemented.h"
     44#include "SVGNames.h"
     45#include "ScriptController.h"
    4446#include "Settings.h"
    45 #include "ScriptController.h"
    4647#include "Text.h"
    4748#include <wtf/UnusedParam.h>
     
    6364{
    6465    return !document->settings() || !document->settings()->html5TreeBuilderEnabled();
     66}
     67
     68bool isNumberedHeaderTag(const AtomicString& tagName)
     69{
     70    return tagName == h1Tag
     71        || tagName == h2Tag
     72        || tagName == h3Tag
     73        || tagName == h4Tag
     74        || tagName == h5Tag
     75        || tagName == h6Tag;
     76}
     77
     78// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
     79bool isSpecialTag(const AtomicString& tagName)
     80{
     81    return tagName == addressTag
     82        || tagName == articleTag
     83        || tagName == asideTag
     84        || tagName == baseTag
     85        || tagName == basefontTag
     86        || tagName == "bgsound"
     87        || tagName == blockquoteTag
     88        || tagName == bodyTag
     89        || tagName == brTag
     90        || tagName == buttonTag
     91        || tagName == centerTag
     92        || tagName == colTag
     93        || tagName == colgroupTag
     94        || tagName == "command"
     95        || tagName == ddTag
     96        || tagName == "details"
     97        || tagName == dirTag
     98        || tagName == divTag
     99        || tagName == dlTag
     100        || tagName == dtTag
     101        || tagName == embedTag
     102        || tagName == fieldsetTag
     103        || tagName == "figure"
     104        || tagName == footerTag
     105        || tagName == formTag
     106        || tagName == frameTag
     107        || tagName == framesetTag
     108        || isNumberedHeaderTag(tagName)
     109        || tagName == headTag
     110        || tagName == headerTag
     111        || tagName == hgroupTag
     112        || tagName == hrTag
     113        || tagName == iframeTag
     114        || tagName == imgTag
     115        || tagName == inputTag
     116        || tagName == isindexTag
     117        || tagName == liTag
     118        || tagName == linkTag
     119        || tagName == listingTag
     120        || tagName == menuTag
     121        || tagName == metaTag
     122        || tagName == navTag
     123        || tagName == noembedTag
     124        || tagName == noframesTag
     125        || tagName == noscriptTag
     126        || tagName == olTag
     127        || tagName == pTag
     128        || tagName == paramTag
     129        || tagName == plaintextTag
     130        || tagName == preTag
     131        || tagName == scriptTag
     132        || tagName == sectionTag
     133        || tagName == selectTag
     134        || tagName == styleTag
     135        || tagName == tbodyTag
     136        || tagName == textareaTag
     137        || tagName == tfootTag
     138        || tagName == theadTag
     139        || tagName == titleTag
     140        || tagName == trTag
     141        || tagName == ulTag
     142        || tagName == wbrTag
     143        || tagName == xmpTag;
     144}
     145
     146// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#scoping
     147// Same as isScopingTag in LegacyHTMLTreeBuilder.cpp
     148// and isScopeMarker in HTMLElementStack.cpp
     149bool isScopingTag(const AtomicString& tagName)
     150{
     151    return tagName == appletTag
     152        || tagName == buttonTag
     153        || tagName == captionTag
     154#if ENABLE(SVG_FOREIGN_OBJECT)
     155        || tagName == SVGNames::foreignObjectTag
     156#endif
     157        || tagName == htmlTag
     158        || tagName == marqueeTag
     159        || tagName == objectTag
     160        || tagName == tableTag
     161        || tagName == tdTag
     162        || tagName == thTag;
     163}
     164
     165bool isNonAnchorFormattingTag(const AtomicString& tagName)
     166{
     167    return tagName == bTag
     168        || tagName == bigTag
     169        || tagName == codeTag
     170        || tagName == emTag
     171        || tagName == fontTag
     172        || tagName == iTag
     173        || tagName == nobrTag
     174        || tagName == sTag
     175        || tagName == smallTag
     176        || tagName == strikeTag
     177        || tagName == strongTag
     178        || tagName == ttTag
     179        || tagName == uTag;
     180}
     181
     182// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting
     183bool isFormattingTag(const AtomicString& tagName)
     184{
     185    return tagName == aTag || isNonAnchorFormattingTag(tagName);
     186}
     187
     188// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#phrasing
     189bool isPhrasingTag(const AtomicString& tagName)
     190{
     191    return !isSpecialTag(tagName) && !isScopingTag(tagName) && !isFormattingTag(tagName);
    65192}
    66193
     
    420547            return;
    421548        }
    422         if (token.name() == h1Tag || token.name() == h2Tag || token.name() == h3Tag || token.name() == h4Tag || token.name() == h5Tag || token.name() == h6Tag) {
     549        if (isNumberedHeaderTag(token.name())) {
    423550            processFakePEndTagIfPInScope();
    424551            notImplemented();
     
    471598            return;
    472599        }
    473         if (token.name() == bTag || token.name() == bigTag || token.name() == codeTag || token.name() == emTag || token.name() == fontTag || token.name() == iTag || token.name() == sTag || token.name() == smallTag || token.name() == strikeTag || token.name() == strongTag || token.name() == ttTag || token.name() == uTag) {
     600        if (isNonAnchorFormattingTag(token.name())) {
    474601            reconstructTheActiveFormattingElements();
    475602            insertFormattingElement(token);
     
    672799    m_insertionMode = AfterBodyMode;
    673800    return true;
     801}
     802
     803// FIXME: This probably belongs on HTMLElementStack.
     804HTMLElementStack::ElementRecord* HTMLTreeBuilder::furthestBlockForFormattingElement(Element* formattingElement)
     805{
     806    HTMLElementStack::ElementRecord* furthestBlock = 0;
     807    HTMLElementStack::ElementRecord* record = m_openElements.topRecord();
     808    for (; record; record = record->next()) {
     809        if (record->element() == formattingElement)
     810            return furthestBlock;
     811        const AtomicString& tagName = record->element()->localName();
     812        // !phrasing && !formatting == scoping || special
     813        if (isScopingTag(tagName) || isSpecialTag(tagName))
     814            furthestBlock = record;
     815    }
     816    ASSERT_NOT_REACHED();
     817    return 0;
     818}
     819
     820void HTMLTreeBuilder::findFosterParentFor(Element* element)
     821{
     822    Element* fosterParentElement = 0;
     823    HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
     824    if (lastTableElementRecord) {
     825        Element* lastTableElement = lastTableElementRecord->element();
     826        if (lastTableElement->parent()) {
     827            // FIXME: We need an insertElement which does not send mutation events.
     828            ExceptionCode ec = 0;
     829            lastTableElement->parent()->insertBefore(element, lastTableElement, ec);
     830            ASSERT(!ec);
     831            return;
     832        }
     833        fosterParentElement = lastTableElementRecord->next()->element();
     834    } else {
     835        ASSERT(m_isParsingFragment);
     836        fosterParentElement = m_openElements.bottom(); // <html> element
     837    }
     838
     839    fosterParentElement->parserAddChild(element);
     840}
     841
     842// FIXME: This should have a whitty name.
     843// FIXME: This must be implemented in many other places in WebCore.
     844void HTMLTreeBuilder::reparentChildren(Element* oldParent, Element* newParent)
     845{
     846    Node* child = oldParent->firstChild();
     847    while (child) {
     848        Node* nextChild = child->nextSibling();
     849        ExceptionCode ec;
     850        newParent->appendChild(child, ec);
     851        ASSERT(!ec);
     852        child = nextChild;
     853    }
     854}
     855
     856// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
     857void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
     858{
     859    while (1) {
     860        // 1.
     861        Element* formattingElement = m_activeFormattingElements.closestElementInScopeWithName(token.name());
     862        if (!formattingElement || !m_openElements.inScope(formattingElement)) {
     863            parseError(token);
     864            notImplemented(); // Check the stack of open elements for a more specific parse error.
     865            return;
     866        }
     867        HTMLElementStack::ElementRecord* formattingElementRecord = m_openElements.find(formattingElement);
     868        if (!formattingElementRecord) {
     869            parseError(token);
     870            m_activeFormattingElements.remove(formattingElement);
     871            return;
     872        }
     873        if (formattingElement != currentElement())
     874            parseError(token);
     875        // 2.
     876        HTMLElementStack::ElementRecord* furthestBlock = furthestBlockForFormattingElement(formattingElement);
     877        // 3.
     878        if (!furthestBlock) {
     879            m_openElements.popUntil(formattingElement);
     880            m_openElements.pop();
     881            m_activeFormattingElements.remove(formattingElement);
     882            return;
     883        }
     884        // 4.
     885        ASSERT(furthestBlock->isAbove(formattingElementRecord));
     886        Element* commonAncestor = formattingElementRecord->next()->element();
     887        // 5.
     888        notImplemented(); // bookmark?
     889        // 6.
     890        HTMLElementStack::ElementRecord* node = furthestBlock;
     891        HTMLElementStack::ElementRecord* nextNode = node->next();
     892        HTMLElementStack::ElementRecord* lastNode = furthestBlock;
     893        while (1) {
     894            // 6.1
     895            node = nextNode;
     896            ASSERT(node);
     897            nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 6.2.
     898            // 6.2
     899            if (!m_activeFormattingElements.contains(node->element())) {
     900                m_openElements.remove(node->element());
     901                node = 0;
     902                continue;
     903            }
     904            // 6.3
     905            if (node == formattingElementRecord)
     906                break;
     907            // 6.4
     908            if (lastNode == furthestBlock)
     909                notImplemented(); // move bookmark.
     910            // 6.5
     911            // FIXME: We're supposed to save the original token in the entry.
     912            AtomicHTMLToken fakeToken(HTMLToken::StartTag, node->element()->localName());
     913            // Is createElement correct? (instead of insertElement)
     914            // Does this code ever leave newElement unattached?
     915            RefPtr<Element> newElement = createElement(fakeToken);
     916            HTMLFormattingElementList::Entry* nodeEntry = m_activeFormattingElements.find(node->element());
     917            nodeEntry->replaceElement(newElement.get());
     918            node->replaceElement(newElement.release());
     919            // 6.6
     920            // Use appendChild instead of parserAddChild to handle possible reparenting.
     921            ExceptionCode ec;
     922            node->element()->appendChild(lastNode->element(), ec);
     923            ASSERT(!ec);
     924            // 6.7
     925            lastNode = node;
     926        }
     927        // 7
     928        const AtomicString& commonAncestorTag = commonAncestor->localName();
     929        if (commonAncestorTag == tableTag
     930            || commonAncestorTag == tbodyTag
     931            || commonAncestorTag == tfootTag
     932            || commonAncestorTag == theadTag
     933            || commonAncestorTag == trTag)
     934            findFosterParentFor(lastNode->element());
     935        else {
     936            ExceptionCode ec;
     937            commonAncestor->appendChild(lastNode->element(), ec);
     938            ASSERT(!ec);
     939        }
     940        // 8
     941        // FIXME: We're supposed to save the original token in the entry.
     942        AtomicHTMLToken fakeToken(HTMLToken::StartTag, formattingElement->localName());
     943        RefPtr<Element> newElement = createElement(fakeToken);
     944        // 9
     945        reparentChildren(furthestBlock->element(), newElement.get());
     946        // 10
     947        furthestBlock->element()->parserAddChild(newElement);
     948        // 11
     949        m_activeFormattingElements.remove(formattingElement);
     950        notImplemented(); // insert new element at bookmark
     951        // 12
     952        m_openElements.remove(formattingElement);
     953        m_openElements.insertAbove(newElement, furthestBlock);
     954    }
    674955}
    675956
     
    7881069            return;
    7891070        }
    790         if (token.name() == h1Tag || token.name() == h2Tag || token.name() == h3Tag || token.name() == h4Tag || token.name() == h5Tag || token.name() == h6Tag) {
     1071        if (isNumberedHeaderTag(token.name())) {
    7911072            if (!m_openElements.inScope(token.name())) {
    7921073                parseError(token);
     
    8041085            return;
    8051086        }
    806         if (token.name() == aTag || token.name() == bTag || token.name() == bigTag || token.name() == codeTag || token.name() == emTag || token.name() == fontTag || token.name() == iTag || token.name() == nobrTag || token.name() == sTag || token.name() == smallTag || token.name() == strikeTag || token.name() == strongTag || token.name() == ttTag || token.name() == uTag) {
    807             notImplemented();
    808             // FIXME: There's a complicated algorithm that goes here.
     1087        if (isFormattingTag(token.name())) {
     1088            callTheAdoptionAgency(token);
    8091089            return;
    8101090        }
  • trunk/WebCore/html/HTMLTreeBuilder.h

    r62431 r62468  
    126126    void processFakePEndTagIfPInScope();
    127127
     128    HTMLElementStack::ElementRecord* furthestBlockForFormattingElement(Element*);
     129    void findFosterParentFor(Element*);
     130    void reparentChildren(Element* oldParent, Element* newParent);
     131    void callTheAdoptionAgency(AtomicHTMLToken&);
     132
    128133    template<typename ChildType>
    129134    PassRefPtr<ChildType> attach(Node* parent, PassRefPtr<ChildType> prpChild)
  • trunk/WebCore/page/Frame.cpp

    r61324 r62468  
    153153    , m_excludeFromTextSearch(false)
    154154{
     155    ASSERT(page);
    155156    AtomicString::init();
    156157    HTMLNames::init();
Note: See TracChangeset for help on using the changeset viewer.