void nsHTMLContentSerializer::SerializeAttributes(nsIContent* aContent, nsIDOMElement *aOriginalElement, nsAString& aTagPrefix, const nsAString& aTagNamespaceURI, nsIAtom* aTagName, nsAString& aStr) { PRInt32 count = aContent->GetAttrCount(); if (!count) return; nsresult rv; nsAutoString nameStr, valueStr; NS_NAMED_LITERAL_STRING(_mozStr, "_moz"); // HTML5 parser stored them in the order they were parsed so we want to // loop forward in that case. nsIDocument* doc = aContent->GetOwnerDocument(); PRBool caseSensitive = doc && doc->IsCaseSensitive(); PRBool loopForward = PR_FALSE; if (!caseSensitive) { nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc)); if (htmlDoc) { loopForward = nsHtml5Module::sEnabled; } } PRInt32 index, limit, step; if (loopForward) { index = 0; limit = count; step = 1; } else { // Loop backward over the attributes, since the order they are stored in is // the opposite of the order they were parsed in (see bug 213347 for reason). index = count - 1; limit = -1; step = -1; } for (; index != limit; index += step) { const nsAttrName* name = aContent->GetAttrNameAt(index); PRInt32 namespaceID = name->NamespaceID(); nsIAtom* attrName = name->LocalName(); // Filter out any attribute starting with [-|_]moz const char* sharedName; attrName->GetUTF8String(&sharedName); if ((('_' == *sharedName) || ('-' == *sharedName)) && !nsCRT::strncmp(sharedName+1, kMozStr, PRUint32(sizeof(kMozStr)-1))) { 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 && StringBeginsWith(valueStr, _mozStr)) { continue; } if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) && (attrName == nsGkAtoms::value)){ // This is handled separately in SerializeLIValueAttribute() continue; } PRBool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr); if (((attrName == nsGkAtoms::href) || (attrName == nsGkAtoms::src))) { // 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) { nsAutoString absURI; rv = NS_MakeAbsoluteURI(absURI, valueStr, uri); if (NS_SUCCEEDED(rv)) { valueStr = absURI; } } } // 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) { // 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); } } attrName->ToString(nameStr); // Expand shorthand attribute. if (IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) { valueStr = nameStr; } SerializeAttr(EmptyString(), nameStr, valueStr, aStr, !isJS); } }
NS_IMETHODIMP nsXMLContentSerializer::AppendElementStart(nsIDOMElement *aElement, nsIDOMElement *aOriginalElement, nsAString& aStr) { NS_ENSURE_ARG(aElement); nsAutoString tagPrefix, tagLocalName, tagNamespaceURI; nsAutoString xmlnsStr; xmlnsStr.AssignLiteral(kXMLNS); nsCOMPtr<nsIContent> content(do_QueryInterface(aElement)); if (!content) return NS_ERROR_FAILURE; aElement->GetPrefix(tagPrefix); aElement->GetLocalName(tagLocalName); aElement->GetNamespaceURI(tagNamespaceURI); PRUint32 index, count; nsAutoString nameStr, prefixStr, uriStr, valueStr; count = content->GetAttrCount(); // First scan for namespace declarations, pushing each on the stack PRUint32 skipAttr = count; for (index = 0; index < count; index++) { const nsAttrName* name = content->GetAttrNameAt(index); PRInt32 namespaceID = name->NamespaceID(); nsIAtom *attrName = name->LocalName(); if (namespaceID == kNameSpaceID_XMLNS || // Also push on the stack attrs named "xmlns" in the null // namespace... because once we serialize those out they'll look like // namespace decls. :( // XXXbz what if we have both "xmlns" in the null namespace and "xmlns" // in the xmlns namespace? (namespaceID == kNameSpaceID_None && attrName == nsGkAtoms::xmlns)) { content->GetAttr(namespaceID, attrName, uriStr); if (!name->GetPrefix()) { if (tagNamespaceURI.IsEmpty() && !uriStr.IsEmpty()) { // If the element is in no namespace we need to add a xmlns // attribute to declare that. That xmlns attribute must not have a // prefix (see http://www.w3.org/TR/REC-xml-names/#dt-prefix), ie it // must declare the default namespace. We just found an xmlns // attribute that declares the default namespace to something // non-empty. We're going to ignore this attribute, for children we // will detect that we need to add it again and attributes aren't // affected by the default namespace. skipAttr = index; } else { // Default NS attribute does not have prefix (and the name is "xmlns") PushNameSpaceDecl(EmptyString(), uriStr, aOriginalElement); } } else { attrName->ToString(nameStr); PushNameSpaceDecl(nameStr, uriStr, aOriginalElement); } } } PRBool addNSAttr; MaybeAddNewline(aStr); addNSAttr = ConfirmPrefix(tagPrefix, tagNamespaceURI, aOriginalElement, PR_FALSE); // Serialize the qualified name of the element AppendToString(NS_LITERAL_STRING("<"), aStr); if (!tagPrefix.IsEmpty()) { AppendToString(tagPrefix, aStr); AppendToString(NS_LITERAL_STRING(":"), aStr); } AppendToString(tagLocalName, aStr); // If we had to add a new namespace declaration, serialize // and push it on the namespace stack if (addNSAttr) { if (tagPrefix.IsEmpty()) { // Serialize default namespace decl SerializeAttr(EmptyString(), xmlnsStr, tagNamespaceURI, aStr, PR_TRUE); } else { // Serialize namespace decl SerializeAttr(xmlnsStr, tagPrefix, tagNamespaceURI, aStr, PR_TRUE); } PushNameSpaceDecl(tagPrefix, tagNamespaceURI, aOriginalElement); } // Now serialize each of the attributes // XXX Unfortunately we need a namespace manager to get // attribute URIs. for (index = 0; index < count; index++) { if (skipAttr == index) { continue; } const nsAttrName* name = content->GetAttrNameAt(index); PRInt32 namespaceID = name->NamespaceID(); nsIAtom* attrName = name->LocalName(); nsIAtom* attrPrefix = name->GetPrefix(); if (attrPrefix) { attrPrefix->ToString(prefixStr); } else { prefixStr.Truncate(); } addNSAttr = PR_FALSE; if (kNameSpaceID_XMLNS != namespaceID) { nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr); addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, PR_TRUE); } content->GetAttr(namespaceID, attrName, valueStr); attrName->ToString(nameStr); // XXX Hack to get around the fact that MathML can add // attributes starting with '-', which makes them // invalid XML. if (!nameStr.IsEmpty() && nameStr.First() == '-') continue; if (namespaceID == kNameSpaceID_None) { if (content->GetNameSpaceID() == kNameSpaceID_XHTML) { if (IsShorthandAttr(attrName, content->Tag()) && valueStr.IsEmpty()) { valueStr = nameStr; } } } SerializeAttr(prefixStr, nameStr, valueStr, aStr, PR_TRUE); if (addNSAttr) { NS_ASSERTION(!prefixStr.IsEmpty(), "Namespaced attributes must have a prefix"); SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, PR_TRUE); PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement); } } // We don't output a separate end tag for empty element PRBool hasChildren; if (NS_FAILED(aOriginalElement->HasChildNodes(&hasChildren)) || !hasChildren) { AppendToString(NS_LITERAL_STRING("/>"), aStr); MaybeFlagNewline(aElement); } else { AppendToString(NS_LITERAL_STRING(">"), aStr); } return NS_OK; }
bool nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent, nsIContent *aOriginalElement, nsAString& aTagPrefix, const nsAString& aTagNamespaceURI, nsIAtom* aTagName, nsAString& aStr, uint32_t aSkipAttr, bool aAddNSAttr) { nsresult rv; uint32_t index, count; nsAutoString prefixStr, uriStr, valueStr; nsAutoString xmlnsStr; xmlnsStr.AssignLiteral(kXMLNS); int32_t contentNamespaceID = aContent->GetNameSpaceID(); // this method is not called by nsHTMLContentSerializer // so we don't have to check HTML element, just XHTML if (mIsCopying && kNameSpaceID_XHTML == contentNamespaceID) { // Need to keep track of OL and LI elements in order to get ordinal number // for the LI. if (aTagName == nsGkAtoms::ol) { // We are copying and current node is an OL; // Store its start attribute value in olState->startVal. nsAutoString start; int32_t startAttrVal = 0; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start); if (!start.IsEmpty()) { nsresult rv = NS_OK; startAttrVal = start.ToInteger(&rv); //If OL has "start" attribute, first LI element has to start with that value //Therefore subtracting 1 as all the LI elements are incrementing it before using it; //In failure of ToInteger(), default StartAttrValue to 0. if (NS_SUCCEEDED(rv)) --startAttrVal; else startAttrVal = 0; } olState state (startAttrVal, true); mOLStateStack.AppendElement(state); } else if (aTagName == nsGkAtoms::li) { mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement); if (mIsFirstChildOfOL) { // If OL is parent of this LI, serialize attributes in different manner. NS_ENSURE_TRUE(SerializeLIValueAttribute(aContent, aStr), false); } } } // If we had to add a new namespace declaration, serialize // and push it on the namespace stack if (aAddNSAttr) { if (aTagPrefix.IsEmpty()) { // Serialize default namespace decl NS_ENSURE_TRUE(SerializeAttr(EmptyString(), xmlnsStr, aTagNamespaceURI, aStr, true), false); } else { // Serialize namespace decl NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, aTagPrefix, aTagNamespaceURI, aStr, true), false); } PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement); } NS_NAMED_LITERAL_STRING(_mozStr, "_moz"); count = aContent->GetAttrCount(); // Now serialize each of the attributes // XXX Unfortunately we need a namespace manager to get // attribute URIs. for (index = 0; index < count; index++) { if (aSkipAttr == index) { continue; } mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index); const nsAttrName* name = info.mName; int32_t namespaceID = name->NamespaceID(); nsIAtom* attrName = name->LocalName(); nsIAtom* attrPrefix = name->GetPrefix(); // Filter out any attribute starting with [-|_]moz nsDependentAtomString attrNameStr(attrName); if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) || StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) { continue; } if (attrPrefix) { attrPrefix->ToString(prefixStr); } else { prefixStr.Truncate(); } bool addNSAttr = false; if (kNameSpaceID_XMLNS != namespaceID) { nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr); addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true); } info.mValue->ToString(valueStr); nsDependentAtomString nameStr(attrName); bool isJS = false; if (kNameSpaceID_XHTML == contentNamespaceID) { // // Filter out special case of <br type="_moz"> or <br _moz*>, // used by the editor. Bug 16988. Yuck. // if (namespaceID == kNameSpaceID_None && aTagName == nsGkAtoms::br && attrName == nsGkAtoms::type && StringBeginsWith(valueStr, _mozStr)) { continue; } if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) && (attrName == nsGkAtoms::value)) { // This is handled separately in SerializeLIValueAttribute() continue; } isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr); if (namespaceID == kNameSpaceID_None && ((attrName == nsGkAtoms::href) || (attrName == nsGkAtoms::src))) { // Make all links absolute when converting only the selection: if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) { // Would be nice to handle OBJECT 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) { nsAutoString absURI; rv = NS_MakeAbsoluteURI(absURI, valueStr, uri); if (NS_SUCCEEDED(rv)) { valueStr = absURI; } } } } if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta && attrName == nsGkAtoms::content) { // 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); } } // Expand shorthand attribute. if (namespaceID == kNameSpaceID_None && IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) { valueStr = nameStr; } } else { isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr); } NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false); if (addNSAttr) { NS_ASSERTION(!prefixStr.IsEmpty(), "Namespaced attributes must have a prefix"); NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false); PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement); } } return true; }
void nsHTMLContentSerializer::SerializeAttributes(nsIContent* aContent, nsIAtom* aTagName, nsAString& aStr) { nsresult rv; PRUint32 index, count; nsAutoString nameStr, valueStr; count = aContent->GetAttrCount(); NS_NAMED_LITERAL_STRING(_mozStr, "_moz"); // Loop backward over the attributes, since the order they are stored in is // the opposite of the order they were parsed in (see bug 213347 for reason). // index is unsigned, hence index >= 0 is always true. for (index = count; index > 0; ) { --index; const nsAttrName* name = aContent->GetAttrNameAt(index); PRInt32 namespaceID = name->NamespaceID(); nsIAtom* attrName = name->LocalName(); // Filter out any attribute starting with [-|_]moz const char* sharedName; attrName->GetUTF8String(&sharedName); if ((('_' == *sharedName) || ('-' == *sharedName)) && !nsCRT::strncmp(sharedName+1, kMozStr, PRUint32(sizeof(kMozStr)-1))) { 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 && StringBeginsWith(valueStr, _mozStr)) { continue; } if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) && (attrName == nsGkAtoms::value)) { // This is handled separately in SerializeLIValueAttribute() continue; } PRBool isJS = IsJavaScript(attrName, valueStr); if (((attrName == nsGkAtoms::href) || (attrName == nsGkAtoms::src))) { // 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) { nsAutoString absURI; rv = NS_MakeAbsoluteURI(absURI, valueStr, uri); if (NS_SUCCEEDED(rv)) { valueStr = absURI; } } } // Need to escape URI. nsAutoString tempURI(valueStr); if (!isJS && NS_FAILED(EscapeURI(tempURI, valueStr))) valueStr = tempURI; } if (mIsWholeDocument && aTagName == nsGkAtoms::meta && attrName == nsGkAtoms::content) { // 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); } } attrName->ToString(nameStr); /*If we already crossed the MaxColumn limit or * if this attr name-value pair(including a space,=,opening and closing quotes) is greater than MaxColumn limit * then start the attribute from a new line. */ if (mDoFormat && (mColPos >= mMaxColumn || ((PRInt32)(mColPos + nameStr.Length() + valueStr.Length() + 4) > mMaxColumn))) { aStr.Append(mLineBreak); mColPos = 0; } // Expand shorthand attribute. if (IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) { valueStr = nameStr; } SerializeAttr(EmptyString(), nameStr, valueStr, aStr, !isJS); } }