Implement one single parsing quirk for HTML5 parser: <p><table>. Required to pass Acid2 and to be compatible with legacy content.
authorHenri Sivonen <hsivonen@iki.fi>
Wed, 22 Apr 2009 12:17:08 +0300
changeset 26759 435227e1a5a9
parent 26758 fdbedef2a8c2
child 26760 6cde8eebfed4
push id49
push userhsivonen@iki.fi
push dateWed, 22 Apr 2009 09:21:30 +0000
milestone1.9.2a1pre
Implement one single parsing quirk for HTML5 parser: <p><table>. Required to pass Acid2 and to be compatible with legacy content.
content/base/src/nsContentUtils.cpp
content/html/parser/src/nsHtml5Parser.cpp
content/html/parser/src/nsHtml5Parser.h
content/html/parser/src/nsHtml5TreeBuilder.cpp
content/html/parser/src/nsHtml5TreeBuilder.h
parser/htmlparser/public/nsIParser.h
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3580,17 +3580,21 @@ nsContentUtils::CreateContextualFragment
     }
     nsCOMPtr<nsIDOMDocumentFragment> frag;
     rv = NS_NewDocumentFragment(getter_AddRefs(frag), document->NodeInfoManager());
     NS_ENSURE_SUCCESS(rv, rv);
     
     nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode);
     NS_ASSERTION(contextAsContent, "Context node did not QI to nsIContent");
     
-    parser->ParseFragment(aFragment, frag, contextAsContent->Tag(), contextAsContent->GetNameSpaceID());
+    parser->ParseFragment(aFragment, 
+                          frag, 
+                          contextAsContent->Tag(), 
+                          contextAsContent->GetNameSpaceID(), 
+                          (document->GetCompatibilityMode() == eCompatibility_NavQuirks));
   
     NS_ADDREF(*aReturn = frag);
     return NS_OK;
   }
 
   nsAutoTArray<nsString, 32> tagStack;
   nsAutoString uriStr, nameStr;
   nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode);
--- a/content/html/parser/src/nsHtml5Parser.cpp
+++ b/content/html/parser/src/nsHtml5Parser.cpp
@@ -448,21 +448,22 @@ nsHtml5Parser::ParseFragment(const nsASt
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
                              nsISupports* aTargetNode,
                              nsIAtom* aContextLocalName,
-                             PRInt32 aContextNamespace)
+                             PRInt32 aContextNamespace,
+                             PRBool aQuirks)
 {
   nsCOMPtr<nsIContent> target = do_QueryInterface(aTargetNode);
   NS_ASSERTION(target, "Target did not QI to nsIContent");
-  mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace, target);
+  mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace, target, aQuirks);
   mFragmentMode = PR_TRUE;
   mCanInterruptParser = PR_FALSE;
   NS_ASSERTION((mLifeCycle == NOT_STARTED), "Tried to start parse without initializing the parser properly.");
   mTokenizer->start();
   mLifeCycle = PARSING;
   mParser = this;
   mNodeInfoManager = target->GetOwnerDoc()->NodeInfoManager();
 
--- a/content/html/parser/src/nsHtml5Parser.h
+++ b/content/html/parser/src/nsHtml5Parser.h
@@ -214,17 +214,18 @@ class nsHtml5Parser : public nsIParser,
                              nsTArray<nsString>& aTagStack,
                              PRBool aXMLMode,
                              const nsACString& aContentType,
                              nsDTDMode aMode = eDTDMode_autodetect);
 
     NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
                              nsISupports* aTargetNode,
                              nsIAtom* aContextLocalName,
-                             PRInt32 aContextNamespace);
+                             PRInt32 aContextNamespace,
+                             PRBool aQuirks);
 
     /**
      * This method gets called when the tokens have been consumed, and it's time
      * to build the model via the content sink.
      * @update	gess5/11/98
      * @return  YES if model building went well -- NO otherwise.
      */
     NS_IMETHOD BuildModel(void);
--- a/content/html/parser/src/nsHtml5TreeBuilder.cpp
+++ b/content/html/parser/src/nsHtml5TreeBuilder.cpp
@@ -868,17 +868,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 ; // fall through
             }
           }
           case NS_HTML5TREE_BUILDER_IN_BODY: {
             for (; ; ) {
               switch(group) {
                 case NS_HTML5TREE_BUILDER_HTML: {
 
-                  addAttributesToElement(stack[0]->node, attributes);
+                  addAttributesToHtml(attributes);
                   goto starttagloop_end;
                 }
                 case NS_HTML5TREE_BUILDER_BASE:
                 case NS_HTML5TREE_BUILDER_LINK:
                 case NS_HTML5TREE_BUILDER_META:
                 case NS_HTML5TREE_BUILDER_STYLE:
                 case NS_HTML5TREE_BUILDER_SCRIPT:
                 case NS_HTML5TREE_BUILDER_TITLE:
@@ -1026,20 +1026,18 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                   reconstructTheActiveFormattingElements();
                   appendToCurrentNodeAndPushElementMayFoster(kNameSpaceID_XHTML, elementName, attributes);
                   originalMode = mode;
                   mode = NS_HTML5TREE_BUILDER_IN_CDATA_RCDATA;
                   tokenizer->setContentModelFlag(NS_HTML5TOKENIZER_CDATA, elementName);
                   goto starttagloop_end;
                 }
                 case NS_HTML5TREE_BUILDER_TABLE: {
-                  PRInt32 rememberPos = currentPtr;
-                  implicitlyCloseP();
-                  if (rememberPos != currentPtr) {
-
+                  if (!quirks) {
+                    implicitlyCloseP();
                   }
                   appendToCurrentNodeAndPushElementMayFoster(kNameSpaceID_XHTML, elementName, attributes);
                   mode = NS_HTML5TREE_BUILDER_IN_TABLE;
                   goto starttagloop_end;
                 }
                 case NS_HTML5TREE_BUILDER_BR:
                 case NS_HTML5TREE_BUILDER_EMBED_OR_IMG:
                 case NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR: {
@@ -1247,17 +1245,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             }
             inbodyloop_end: ;
           }
           case NS_HTML5TREE_BUILDER_IN_HEAD: {
             for (; ; ) {
               switch(group) {
                 case NS_HTML5TREE_BUILDER_HTML: {
 
-                  addAttributesToElement(stack[0]->node, attributes);
+                  addAttributesToHtml(attributes);
                   goto starttagloop_end;
                 }
                 case NS_HTML5TREE_BUILDER_BASE:
                 case NS_HTML5TREE_BUILDER_COMMAND_OR_EVENT_SOURCE: {
                   appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, attributes);
                   selfClosing = PR_FALSE;
                   goto starttagloop_end;
                 }
@@ -1305,17 +1303,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               }
             }
             inheadloop_end: ;
           }
           case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_LINK: {
                 appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, attributes);
                 selfClosing = PR_FALSE;
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_META: {
@@ -1347,17 +1345,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 continue;
               }
             }
           }
           case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_COL: {
                 appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, attributes);
                 selfClosing = PR_FALSE;
                 goto starttagloop_end;
               }
               default: {
@@ -1386,17 +1384,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               default:
                 ; // fall through
             }
           }
           case NS_HTML5TREE_BUILDER_IN_SELECT: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_OPTION: {
                 if (isCurrent(nsHtml5Atoms::option)) {
                   pop();
                 }
                 appendToCurrentNodeAndPushElement(kNameSpaceID_XHTML, elementName, attributes);
                 goto starttagloop_end;
@@ -1444,17 +1442,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 goto starttagloop_end;
               }
             }
           }
           case NS_HTML5TREE_BUILDER_AFTER_BODY: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               default: {
 
                 mode = NS_HTML5TREE_BUILDER_IN_BODY;
                 continue;
               }
             }
@@ -1473,17 +1471,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               default:
                 ; // fall through
             }
           }
           case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_NOFRAMES: {
                 appendToCurrentNodeAndPushElement(kNameSpaceID_XHTML, elementName, attributes);
                 originalMode = mode;
                 mode = NS_HTML5TREE_BUILDER_IN_CDATA_RCDATA;
                 tokenizer->setContentModelFlag(NS_HTML5TOKENIZER_CDATA, elementName);
                 goto starttagloop_end;
@@ -1516,17 +1514,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 continue;
               }
             }
           }
           case NS_HTML5TREE_BUILDER_BEFORE_HEAD: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_HEAD: {
                 appendToCurrentNodeAndPushHeadElement(attributes);
                 mode = NS_HTML5TREE_BUILDER_IN_HEAD;
                 goto starttagloop_end;
               }
               default: {
@@ -1535,17 +1533,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 continue;
               }
             }
           }
           case NS_HTML5TREE_BUILDER_AFTER_HEAD: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               case NS_HTML5TREE_BUILDER_BODY: {
                 if (!attributes->getLength()) {
                   appendToCurrentNodeAndPushBodyElement();
                 } else {
                   appendToCurrentNodeAndPushBodyElement(attributes);
                 }
@@ -1620,17 +1618,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 continue;
               }
             }
           }
           case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: {
             switch(group) {
               case NS_HTML5TREE_BUILDER_HTML: {
 
-                addAttributesToElement(stack[0]->node, attributes);
+                addAttributesToHtml(attributes);
                 goto starttagloop_end;
               }
               default: {
 
 
                 mode = NS_HTML5TREE_BUILDER_IN_BODY;
                 continue;
               }
@@ -2677,16 +2675,17 @@ PRBool
 nsHtml5TreeBuilder::isSecondOnStackBody()
 {
   return currentPtr >= 1 && stack[1]->group == NS_HTML5TREE_BUILDER_BODY;
 }
 
 void 
 nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, PRBool html4SpecificAdditionalErrorChecks)
 {
+  quirks = (m == QUIRKS_MODE);
   if (!!documentModeHandler) {
     documentModeHandler->documentMode(m);
   }
 }
 
 PRBool 
 nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier)
 {
@@ -3162,16 +3161,22 @@ nsHtml5TreeBuilder::addAttributesToBody(
     nsHtml5StackNode* body = stack[1];
     if (body->group == NS_HTML5TREE_BUILDER_BODY) {
       addAttributesToElement(body->node, attributes);
     }
   }
 }
 
 void 
+nsHtml5TreeBuilder::addAttributesToHtml(nsHtml5HtmlAttributes* attributes)
+{
+  addAttributesToElement(stack[0]->node, attributes);
+}
+
+void 
 nsHtml5TreeBuilder::pushHeadPointerOntoStack()
 {
   flushCharacters();
 
   if (!headPointer) {
 
     push(stack[currentPtr]);
   } else {
@@ -3499,24 +3504,25 @@ nsHtml5TreeBuilder::accumulateCharacter(
 
 void 
 nsHtml5TreeBuilder::requestSuspension()
 {
   tokenizer->requestSuspension();
 }
 
 void 
-nsHtml5TreeBuilder::setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node)
+nsHtml5TreeBuilder::setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node, PRBool quirks)
 {
   this->contextName = context;
   nsHtml5Portability::retainLocal(context);
   this->contextNamespace = ns;
   this->contextNode = node;
   nsHtml5Portability::retainElement(node);
   this->fragment = (!!contextName);
+  this->quirks = quirks;
 }
 
 nsIContent* 
 nsHtml5TreeBuilder::currentNode()
 {
   return stack[currentPtr]->node;
 }
 
--- a/content/html/parser/src/nsHtml5TreeBuilder.h
+++ b/content/html/parser/src/nsHtml5TreeBuilder.h
@@ -85,16 +85,18 @@ class nsHtml5TreeBuilder
     PRInt32 currentPtr;
     jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements;
     PRInt32 listPtr;
     nsIContent* formPointer;
     nsIContent* headPointer;
   protected:
     jArray<PRUnichar,PRInt32> charBuffer;
     PRInt32 charBufferLen;
+  private:
+    PRBool quirks;
   public:
     void startTokenization(nsHtml5Tokenizer* self);
     void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, PRBool forceQuirks);
     void comment(PRUnichar* buf, PRInt32 start, PRInt32 length);
     void characters(PRUnichar* buf, PRInt32 start, PRInt32 length);
     void eof();
     void endTokenization();
     void startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, PRBool selfClosing);
@@ -143,16 +145,17 @@ class nsHtml5TreeBuilder
     void adoptionAgencyEndTag(nsIAtom* name);
     void insertIntoStack(nsHtml5StackNode* node, PRInt32 position);
     void insertIntoListOfActiveFormattingElements(nsHtml5StackNode* formattingClone, PRInt32 bookmark);
     PRInt32 findInListOfActiveFormattingElements(nsHtml5StackNode* node);
     PRInt32 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsIAtom* name);
     PRInt32 findLastOrRoot(nsIAtom* name);
     PRInt32 findLastOrRoot(PRInt32 group);
     void addAttributesToBody(nsHtml5HtmlAttributes* attributes);
+    void addAttributesToHtml(nsHtml5HtmlAttributes* attributes);
     void pushHeadPointerOntoStack();
     void reconstructTheActiveFormattingElements();
     void insertIntoFosterParent(nsIContent* child);
     PRBool isInStack(nsHtml5StackNode* node);
     void pop();
     void appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes* attributes);
     void appendHtmlElementToDocumentAndPush();
     void appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes* attributes);
@@ -188,17 +191,17 @@ class nsHtml5TreeBuilder
     void appendCommentToDocument(PRUnichar* buf, PRInt32 start, PRInt32 length);
     void addAttributesToElement(nsIContent* element, nsHtml5HtmlAttributes* attributes);
     void start(PRBool fragment);
     void end();
     void appendDoctypeToDocument(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier);
     void elementPushed(PRInt32 ns, nsIAtom* name, nsIContent* node);
     void elementPopped(PRInt32 ns, nsIAtom* name, nsIContent* node);
   public:
-    void setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node);
+    void setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node, PRBool quirks);
   protected:
     nsIContent* currentNode();
   public:
     PRBool isScriptingEnabled();
     void setScriptingEnabled(PRBool scriptingEnabled);
     void setDocumentModeHandler(nsHtml5Parser* documentModeHandler);
     PRBool inForeign();
   private:
--- a/parser/htmlparser/public/nsIParser.h
+++ b/parser/htmlparser/public/nsIParser.h
@@ -257,17 +257,18 @@ class nsIParser : public nsISupports {
                              nsTArray<nsString>& aTagStack,
                              PRBool aXMLMode,
                              const nsACString& aContentType,
                              nsDTDMode aMode = eDTDMode_autodetect) = 0;
 
     NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
                              nsISupports* aTargetNode,
                              nsIAtom* aContextLocalName,
-                             PRInt32 aContextNamespace) = 0;
+                             PRInt32 aContextNamespace,
+                             PRBool aQuirks) = 0;
 
     /**
      * This method gets called when the tokens have been consumed, and it's time
      * to build the model via the content sink.
      * @update	gess5/11/98
      * @return  error code -- 0 if model building went well .
      */
     NS_IMETHOD BuildModel(void) = 0;