NS_IMETHODIMP nsXMLContentSerializer::AppendComment(nsIDOMComment* aComment, PRInt32 aStartOffset, PRInt32 aEndOffset, nsAString& aStr) { NS_ENSURE_ARG(aComment); nsresult rv; nsAutoString data; rv = aComment->GetData(data); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; MaybeAddNewline(aStr); AppendToString(NS_LITERAL_STRING("<!--"), aStr); if (aStartOffset || (aEndOffset != -1)) { PRInt32 length = (aEndOffset == -1) ? data.Length() : aEndOffset; length -= aStartOffset; nsAutoString frag; data.Mid(frag, aStartOffset, length); AppendToString(frag, aStr); } else { AppendToString(data, aStr); } AppendToString(NS_LITERAL_STRING("-->"), aStr); MaybeFlagNewline(aComment); return NS_OK; }
NS_IMETHODIMP nsXMLContentSerializer::AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI, PRInt32 aStartOffset, PRInt32 aEndOffset, nsAString& aStr) { NS_ENSURE_ARG(aPI); nsresult rv; nsAutoString target, data; MaybeAddNewline(aStr); rv = aPI->GetTarget(target); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = aPI->GetData(data); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; AppendToString(NS_LITERAL_STRING("<?"), aStr); AppendToString(target, aStr); if (!data.IsEmpty()) { AppendToString(NS_LITERAL_STRING(" "), aStr); AppendToString(data, aStr); } AppendToString(NS_LITERAL_STRING("?>"), aStr); MaybeFlagNewline(aPI); return NS_OK; }
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; }
NS_IMETHODIMP nsXMLContentSerializer::AppendDoctype(nsIDOMDocumentType *aDoctype, nsAString& aStr) { NS_ENSURE_ARG(aDoctype); nsresult rv; nsAutoString name, publicId, systemId, internalSubset; rv = aDoctype->GetName(name); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = aDoctype->GetPublicId(publicId); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = aDoctype->GetSystemId(systemId); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = aDoctype->GetInternalSubset(internalSubset); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; MaybeAddNewline(aStr); AppendToString(NS_LITERAL_STRING("<!DOCTYPE "), aStr); AppendToString(name, aStr); PRUnichar quote; if (!publicId.IsEmpty()) { AppendToString(NS_LITERAL_STRING(" PUBLIC "), aStr); if (publicId.FindChar(PRUnichar('"')) == -1) { quote = PRUnichar('"'); } else { quote = PRUnichar('\''); } AppendToString(quote, aStr); AppendToString(publicId, aStr); AppendToString(quote, aStr); if (!systemId.IsEmpty()) { AppendToString(PRUnichar(' '), aStr); if (systemId.FindChar(PRUnichar('"')) == -1) { quote = PRUnichar('"'); } else { quote = PRUnichar('\''); } AppendToString(quote, aStr); AppendToString(systemId, aStr); AppendToString(quote, aStr); } } else if (!systemId.IsEmpty()) { if (systemId.FindChar(PRUnichar('"')) == -1) { quote = PRUnichar('"'); } else { quote = PRUnichar('\''); } AppendToString(NS_LITERAL_STRING(" SYSTEM "), aStr); AppendToString(quote, aStr); AppendToString(systemId, aStr); AppendToString(quote, aStr); } if (!internalSubset.IsEmpty()) { AppendToString(NS_LITERAL_STRING(" ["), aStr); AppendToString(internalSubset, aStr); AppendToString(PRUnichar(']'), aStr); } AppendToString(PRUnichar('>'), aStr); MaybeFlagNewline(aDoctype); return NS_OK; }
NS_IMETHODIMP nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement, nsIDOMElement *aOriginalElement, nsAString& aStr) { NS_ENSURE_ARG(aElement); nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); if (!content) return NS_ERROR_FAILURE; // The _moz_dirty attribute is emitted by the editor to // indicate that this element should be pretty printed // even if we're not in pretty printing mode PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty); nsIAtom *name = content->Tag(); if (name == nsGkAtoms::br && mPreLevel > 0 && (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; return NS_OK; } if (name == nsGkAtoms::body) { mInBody = PR_TRUE; } if (LineBreakBeforeOpen(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; mAddSpace = PR_FALSE; } else if (mAddSpace) { AppendToString(PRUnichar(' '), aStr); mAddSpace = PR_FALSE; } else { MaybeAddNewline(aStr); } // Always reset to avoid false newlines in case MaybeAddNewline wasn't // called mAddNewline = PR_FALSE; StartIndentation(name, hasDirtyAttr, aStr); if (name == nsGkAtoms::pre || name == nsGkAtoms::script || name == nsGkAtoms::style) { mPreLevel++; } AppendToString(kLessThan, aStr); nsAutoString nameStr; name->ToString(nameStr); AppendToString(nameStr.get(), -1, aStr); // Need to keep track of OL and LI elements in order to get ordinal number // for the LI. if (mIsCopying && name == nsGkAtoms::ol) { // We are copying and current node is an OL; // Store it's start attribute value in olState->startVal. nsAutoString start; PRInt32 startAttrVal = 0; aElement->GetAttribute(NS_LITERAL_STRING("start"), start); if (!start.IsEmpty()) { PRInt32 rv = 0; 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 = new olState(startAttrVal, PR_TRUE); if (state) mOLStateStack.AppendElement(state); } if (mIsCopying && name == nsGkAtoms::li) { 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". SerializeAttributes(content, name, aStr); AppendToString(kGreaterThan, aStr); if (LineBreakAfterOpen(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; } if (name == nsGkAtoms::script || name == nsGkAtoms::style || name == nsGkAtoms::noscript || name == nsGkAtoms::noframes) { mInCDATA = PR_TRUE; } if (mIsWholeDocument && name == nsGkAtoms::head) { // Check if there already are any content-type meta children. // If there are, they will be modified to use the correct charset. // If there aren't, we'll insert one here. PRBool hasMeta = PR_FALSE; PRUint32 i, childCount = content->GetChildCount(); for (i = 0; i < childCount; ++i) { nsIContent* child = content->GetChildAt(i); if (child->IsNodeOfType(nsINode::eHTML) && child->Tag() == nsGkAtoms::meta && child->HasAttr(kNameSpaceID_None, nsGkAtoms::content)) { nsAutoString header; child->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header); if (header.LowerCaseEqualsLiteral("content-type")) { hasMeta = PR_TRUE; break; } } } if (!hasMeta) { AppendToString(mLineBreak, aStr); AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""), aStr); AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr); AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr); AppendToString(NS_LITERAL_STRING("\">"), aStr); } } return NS_OK; }
NS_IMETHODIMP nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement, PRBool aHasChildren, nsAString& aStr) { NS_ENSURE_ARG(aElement); nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); if (!content) return NS_ERROR_FAILURE; // The _moz_dirty attribute is emitted by the editor to // indicate that this element should be pretty printed // even if we're not in pretty printing mode PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None, nsLayoutAtoms::mozdirty); nsIAtom *name = content->Tag(); if (name == nsHTMLAtoms::br && mPreLevel > 0 && (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; return NS_OK; } if (name == nsHTMLAtoms::body) { mInBody = PR_TRUE; } if (LineBreakBeforeOpen(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; mAddSpace = PR_FALSE; } else if (mAddSpace) { AppendToString(PRUnichar(' '), aStr); mAddSpace = PR_FALSE; } else { MaybeAddNewline(aStr); } // Always reset to avoid false newlines in case MaybeAddNewline wasn't // called mAddNewline = PR_FALSE; StartIndentation(name, hasDirtyAttr, aStr); if (name == nsHTMLAtoms::pre || name == nsHTMLAtoms::script || name == nsHTMLAtoms::style) { mPreLevel++; } AppendToString(kLessThan, aStr); nsAutoString nameStr; name->ToString(nameStr); AppendToString(nameStr.get(), -1, aStr); // Need to keep track of OL and LI elements in order to get ordinal number // for the LI. if (mIsCopying && name == nsHTMLAtoms::ol){ // We are copying and current node is an OL; // Store it's start attribute value in olState->startVal. nsAutoString start; PRInt32 startAttrVal = 0; aElement->GetAttribute(NS_LITERAL_STRING("start"), start); if (!start.IsEmpty()){ PRInt32 rv = 0; 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 = new olState(startAttrVal, PR_TRUE); if (state) mOLStateStack.AppendElement(state); } if (mIsCopying && name == nsHTMLAtoms::li) { mIsFirstChildOfOL = IsFirstChildOfOL(aElement); 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". SerializeAttributes(content, name, aStr); AppendToString(kGreaterThan, aStr); if (LineBreakAfterOpen(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mMayIgnoreLineBreakSequence = PR_TRUE; mColPos = 0; } if (name == nsHTMLAtoms::script || name == nsHTMLAtoms::style || name == nsHTMLAtoms::noscript || name == nsHTMLAtoms::noframes) { mInCDATA = PR_TRUE; } return NS_OK; }