Bug 650001 - Make the HTML serializer pay attention to namespaces. r=bzbarsky.
authorHenri Sivonen <hsivonen@iki.fi>
Mon, 09 May 2011 09:48:46 +0300
changeset 69375 7299264c520460f89d1f47b5c221ad5d18df8c83
parent 69374 34e7b390a99bd4cf400171c42cd2161cac46eab1
child 69376 dfcfa00eb188b14330b3d2fbbcd8485a7e3eaa6a
push id76
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:00:57 +0000
treeherdermozilla-beta@d3a2732c35f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs650001
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 650001 - Make the HTML serializer pay attention to namespaces. r=bzbarsky.
content/base/src/nsHTMLContentSerializer.cpp
content/base/src/nsHTMLContentSerializer.h
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -85,20 +85,21 @@ nsresult NS_NewHTMLContentSerializer(nsI
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return CallQueryInterface(it, aSerializer);
 }
 
 static
 PRBool
-IsInvisibleBreak(nsIContent *aNode, nsIAtom *aTag) {
+IsInvisibleBreak(nsIContent *aNode, nsIAtom *aTag, PRInt32 aNamespace) {
   // xxxehsan: we should probably figure out a way to determine
   // if a BR node is visible without using the editor.
-  if (aTag != nsGkAtoms::br || !aNode->IsEditable()) {
+  if (!(aTag == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML) ||
+      !aNode->IsEditable()) {
     return PR_FALSE;
   }
 
   // Grab the editor associated with the document
   nsIDocument *doc = aNode->GetCurrentDoc();
   if (doc) {
     nsPIDOMWindow *window = doc->GetWindow();
     if (window) {
@@ -140,16 +141,17 @@ nsHTMLContentSerializer::AppendDocumentS
 }
 
 void 
 nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
                                                  nsIContent *aOriginalElement,
                                                  nsAString& aTagPrefix,
                                                  const nsAString& aTagNamespaceURI,
                                                  nsIAtom* aTagName,
+                                                 PRInt32 aNamespace,
                                                  nsAString& aStr)
 {
   PRInt32 count = aContent->GetAttrCount();
   if (!count)
     return;
 
   nsresult rv;
   nsAutoString valueStr;
@@ -168,30 +170,34 @@ nsHTMLContentSerializer::SerializeHTMLAt
       continue;
     }
     aContent->GetAttr(namespaceID, attrName, valueStr);
 
     // 
     // Filter out special case of <br type="_moz"> or <br _moz*>,
     // used by the editor.  Bug 16988.  Yuck.
     //
-    if (aTagName == nsGkAtoms::br && attrName == nsGkAtoms::type &&
+    if (aTagName == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML &&
+        attrName == nsGkAtoms::type && namespaceID == kNameSpaceID_None &&
         StringBeginsWith(valueStr, _mozStr)) {
       continue;
     }
 
-    if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) && 
-        (attrName == nsGkAtoms::value)){
+    if (mIsCopying && mIsFirstChildOfOL &&
+        aTagName == nsGkAtoms::li && aNamespace == kNameSpaceID_XHTML &&
+        attrName == nsGkAtoms::value && namespaceID == kNameSpaceID_None){
       // This is handled separately in SerializeLIValueAttribute()
       continue;
     }
     PRBool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
     
-    if (((attrName == nsGkAtoms::href) || 
-         (attrName == nsGkAtoms::src))) {
+    if (((attrName == nsGkAtoms::href &&
+          (namespaceID == kNameSpaceID_None ||
+           namespaceID == kNameSpaceID_XLink)) ||
+         (attrName == nsGkAtoms::src && namespaceID == kNameSpaceID_None))) {
       // Make all links absolute when converting only the selection:
       if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
         // Would be nice to handle OBJECT and APPLET tags,
         // but that gets more complicated since we have to
         // search the tag list for CODEBASE as well.
         // For now, just leave them relative.
         nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
         if (uri) {
@@ -204,34 +210,44 @@ nsHTMLContentSerializer::SerializeHTMLAt
       }
       // Need to escape URI.
       nsAutoString tempURI(valueStr);
       if (!isJS && NS_FAILED(EscapeURI(aContent, tempURI, valueStr)))
         valueStr = tempURI;
     }
 
     if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&
-        attrName == nsGkAtoms::content) {
+        aNamespace == kNameSpaceID_XHTML && attrName == nsGkAtoms::content
+        && namespaceID == kNameSpaceID_None) {
       // If we're serializing a <meta http-equiv="content-type">,
       // use the proper value, rather than what's in the document.
       nsAutoString header;
       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
       if (header.LowerCaseEqualsLiteral("content-type")) {
         valueStr = NS_LITERAL_STRING("text/html; charset=") +
           NS_ConvertASCIItoUTF16(mCharset);
       }
     }
 
     nsDependentAtomString nameStr(attrName);
+    nsAutoString prefix;
+    if (namespaceID == kNameSpaceID_XML) {
+      prefix.Assign(NS_LITERAL_STRING("xml"));
+    } else if (namespaceID == kNameSpaceID_XLink) {
+      prefix.Assign(NS_LITERAL_STRING("xlink"));
+    }
 
     // Expand shorthand attribute.
-    if (IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) {
+    if (aNamespace == kNameSpaceID_XHTML &&
+        namespaceID == kNameSpaceID_None &&
+        IsShorthandAttr(attrName, aTagName) &&
+        valueStr.IsEmpty()) {
       valueStr = nameStr;
     }
-    SerializeAttr(EmptyString(), nameStr, valueStr, aStr, !isJS);
+    SerializeAttr(prefix, nameStr, valueStr, aStr, !isJS);
   }
 }
 
 NS_IMETHODIMP
 nsHTMLContentSerializer::AppendElementStart(Element* aElement,
                                             Element* aOriginalElement,
                                             nsAString& aStr)
 {
@@ -240,23 +256,24 @@ nsHTMLContentSerializer::AppendElementSt
   nsIContent* content = aElement;
 
   PRBool forceFormat = PR_FALSE;
   if (!CheckElementStart(content, forceFormat, aStr)) {
     return NS_OK;
   }
 
   nsIAtom *name = content->Tag();
+  PRInt32 ns = content->GetNameSpaceID();
 
   if ((mFlags & nsIDocumentEncoder::OutputPreformatted) &&
-      IsInvisibleBreak(content, name)) {
+      IsInvisibleBreak(content, name, ns)) {
     return NS_OK;
   }
 
-  PRBool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);
+  PRBool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
 
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
     if (mColPos && lineBreakBeforeOpen) {
       AppendNewLineToString(aStr);
     }
     else {
       MaybeAddNewlineForRootNode(aStr);
     }
@@ -286,17 +303,17 @@ nsHTMLContentSerializer::AppendElementSt
   MaybeEnterInPreContent(content);
 
   // for block elements, we increase the indentation
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw)
     IncrIndentation(name);
 
   // Need to keep track of OL and LI elements in order to get ordinal number 
   // for the LI.
-  if (mIsCopying && name == nsGkAtoms::ol){
+  if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML){
     // We are copying and current node is an OL;
     // Store its start attribute value in olState->startVal.
     nsAutoString start;
     PRInt32 startAttrVal = 0;
 
     aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
     if (!start.IsEmpty()){
       PRInt32 rv = 0;
@@ -307,40 +324,47 @@ nsHTMLContentSerializer::AppendElementSt
       if (NS_SUCCEEDED(rv))
         startAttrVal--; 
       else
         startAttrVal = 0;
     }
     mOLStateStack.AppendElement(olState(startAttrVal, PR_TRUE));
   }
 
-  if (mIsCopying && name == nsGkAtoms::li) {
+  if (mIsCopying && name == nsGkAtoms::li && ns == kNameSpaceID_XHTML) {
     mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
     if (mIsFirstChildOfOL){
       // If OL is parent of this LI, serialize attributes in different manner.
       SerializeLIValueAttribute(aElement, aStr);
     }
   }
 
   // Even LI passed above have to go through this 
   // for serializing attributes other than "value".
   nsAutoString dummyPrefix;
-  SerializeHTMLAttributes(content, aOriginalElement, dummyPrefix, EmptyString(), name, aStr);
+  SerializeHTMLAttributes(content,
+                          aOriginalElement,
+                          dummyPrefix,
+                          EmptyString(),
+                          name,
+                          ns,
+                          aStr);
 
   AppendToString(kGreaterThan, aStr);
 
-  if (name == nsGkAtoms::script ||
-      name == nsGkAtoms::style ||
-      name == nsGkAtoms::noscript ||
-      name == nsGkAtoms::noframes) {
+  if (ns == kNameSpaceID_XHTML &&
+      (name == nsGkAtoms::script ||
+       name == nsGkAtoms::style ||
+       name == nsGkAtoms::noscript ||
+       name == nsGkAtoms::noframes)) {
     ++mDisableEntityEncoding;
   }
 
   if ((mDoFormat || forceFormat) && !mPreLevel &&
-    !mDoRaw && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
+    !mDoRaw && LineBreakAfterOpen(ns, name)) {
     AppendNewLineToString(aStr);
   }
 
   AfterElementStart(content, aOriginalElement, aStr);
 
   return NS_OK;
 }
   
@@ -348,21 +372,23 @@ NS_IMETHODIMP
 nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
                                           nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
   nsIContent* content = aElement;
 
   nsIAtom *name = content->Tag();
+  PRInt32 ns = content->GetNameSpaceID();
 
-  if (name == nsGkAtoms::script ||
-      name == nsGkAtoms::style ||
-      name == nsGkAtoms::noscript ||
-      name == nsGkAtoms::noframes) {
+  if (ns == kNameSpaceID_XHTML &&
+      (name == nsGkAtoms::script ||
+       name == nsGkAtoms::style ||
+       name == nsGkAtoms::noscript ||
+       name == nsGkAtoms::noframes)) {
     --mDisableEntityEncoding;
   }
 
   PRBool forceFormat = content->HasAttr(kNameSpaceID_None,
                                         nsGkAtoms::mozdirty);
 
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
     DecrIndentation(name);
@@ -374,40 +400,43 @@ nsHTMLContentSerializer::AppendElementEn
     if (script && script->IsMalformed()) {
       // We're looking at a malformed script tag. This means that the end tag
       // was missing in the source. Imitate that here by not serializing the end
       // tag.
       --mPreLevel;
       return NS_OK;
     }
   }
-  else if (mIsCopying && name == nsGkAtoms::ol) {
+  else if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML) {
     NS_ASSERTION((!mOLStateStack.IsEmpty()), "Cannot have an empty OL Stack");
     /* Though at this point we must always have an state to be deleted as all 
     the OL opening tags are supposed to push an olState object to the stack*/
     if (!mOLStateStack.IsEmpty()) {
       mOLStateStack.RemoveElementAt(mOLStateStack.Length() -1);
     }
   }
   
-  nsIParserService* parserService = nsContentUtils::GetParserService();
+  if (ns == kNameSpaceID_XHTML) {
+    nsIParserService* parserService = nsContentUtils::GetParserService();
 
-  if (parserService) {
-    PRBool isContainer;
+    if (parserService) {
+      PRBool isContainer;
 
-    parserService->
-      IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
-                  isContainer);
-    if (!isContainer)
-      return NS_OK;
+      parserService->
+        IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
+                    isContainer);
+      if (!isContainer) {
+        return NS_OK;
+      }
+    }
   }
 
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
 
-    PRBool lineBreakBeforeClose = LineBreakBeforeClose(content->GetNameSpaceID(), name);
+    PRBool lineBreakBeforeClose = LineBreakBeforeClose(ns, name);
 
     if (mColPos && lineBreakBeforeClose) {
       AppendNewLineToString(aStr);
     }
     if (!mColPos) {
       AppendIndentation(aStr);
     }
     else if (mAddSpace) {
@@ -422,24 +451,24 @@ nsHTMLContentSerializer::AppendElementEn
 
   AppendToString(kEndTag, aStr);
   AppendToString(nsDependentAtomString(name), aStr);
   AppendToString(kGreaterThan, aStr);
 
   MaybeLeaveFromPreContent(content);
 
   if ((mDoFormat || forceFormat) && !mPreLevel
-      && !mDoRaw && LineBreakAfterClose(content->GetNameSpaceID(), name)) {
+      && !mDoRaw && LineBreakAfterClose(ns, name)) {
     AppendNewLineToString(aStr);
   }
   else {
     MaybeFlagNewlineForRootNode(aElement);
   }
 
-  if (name == nsGkAtoms::body) {
+  if (name == nsGkAtoms::body && ns == kNameSpaceID_XHTML) {
     --mInBody;
   }
 
   return NS_OK;
 }
 
 static const PRUint16 kValNBSP = 160;
 static const char* kEntities[] = {
--- a/content/base/src/nsHTMLContentSerializer.h
+++ b/content/base/src/nsHTMLContentSerializer.h
@@ -68,16 +68,17 @@ class nsHTMLContentSerializer : public n
                                  nsAString& aStr);
  protected:
 
   virtual void SerializeHTMLAttributes(nsIContent* aContent,
                                        nsIContent *aOriginalElement,
                                        nsAString& aTagPrefix,
                                        const nsAString& aTagNamespaceURI,
                                        nsIAtom* aTagName,
+                                       PRInt32 aNamespace,
                                        nsAString& aStr);
 
   virtual void AppendAndTranslateEntities(const nsAString& aStr,
                                           nsAString& aOutputStr);
 
 };
 
 nsresult