LCOV - code coverage report
Current view: top level - dom/base - nsXMLContentSerializer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 807 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 51 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * nsIContentSerializer implementation that can be used with an
       9             :  * nsIDocumentEncoder to convert an XML DOM to an XML string that
      10             :  * could be parsed into more or less the original DOM.
      11             :  */
      12             : 
      13             : #include "nsXMLContentSerializer.h"
      14             : 
      15             : #include "nsGkAtoms.h"
      16             : #include "nsIDOMProcessingInstruction.h"
      17             : #include "nsIDOMComment.h"
      18             : #include "nsIDOMDocumentType.h"
      19             : #include "nsIContent.h"
      20             : #include "nsIContentInlines.h"
      21             : #include "nsIDocument.h"
      22             : #include "nsIDocumentEncoder.h"
      23             : #include "nsIParserService.h"
      24             : #include "nsNameSpaceManager.h"
      25             : #include "nsTextFragment.h"
      26             : #include "nsString.h"
      27             : #include "mozilla/Sprintf.h"
      28             : #include "nsUnicharUtils.h"
      29             : #include "nsCRT.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsAttrName.h"
      32             : #include "nsILineBreaker.h"
      33             : #include "mozilla/dom/Element.h"
      34             : #include "nsParserConstants.h"
      35             : #include "mozilla/Encoding.h"
      36             : 
      37             : using namespace mozilla;
      38             : using namespace mozilla::dom;
      39             : 
      40             : #define kXMLNS "xmlns"
      41             : 
      42             : // to be readable, we assume that an indented line contains
      43             : // at least this number of characters (arbitrary value here).
      44             : // This is a limit for the indentation.
      45             : #define MIN_INDENTED_LINE_LENGTH 15
      46             : 
      47             : // the string used to indent.
      48             : #define INDENT_STRING "  "
      49             : #define INDENT_STRING_LENGTH 2
      50             : 
      51             : nsresult
      52           0 : NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer)
      53             : {
      54           0 :   RefPtr<nsXMLContentSerializer> it = new nsXMLContentSerializer();
      55           0 :   it.forget(aSerializer);
      56           0 :   return NS_OK;
      57             : }
      58             : 
      59           0 : nsXMLContentSerializer::nsXMLContentSerializer()
      60             :   : mPrefixIndex(0),
      61             :     mColPos(0),
      62             :     mIndentOverflow(0),
      63             :     mIsIndentationAddedOnCurrentLine(false),
      64             :     mInAttribute(false),
      65             :     mAddNewlineForRootNode(false),
      66             :     mAddSpace(false),
      67             :     mMayIgnoreLineBreakSequence(false),
      68             :     mBodyOnly(false),
      69           0 :     mInBody(0)
      70             : {
      71           0 : }
      72             : 
      73           0 : nsXMLContentSerializer::~nsXMLContentSerializer()
      74             : {
      75           0 : }
      76             : 
      77           0 : NS_IMPL_ISUPPORTS(nsXMLContentSerializer, nsIContentSerializer)
      78             : 
      79             : NS_IMETHODIMP
      80           0 : nsXMLContentSerializer::Init(uint32_t aFlags,
      81             :                              uint32_t aWrapColumn,
      82             :                              const Encoding* aEncoding,
      83             :                              bool aIsCopying,
      84             :                              bool aRewriteEncodingDeclaration,
      85             :                              bool* aNeedsPreformatScanning)
      86             : {
      87           0 :   *aNeedsPreformatScanning = false;
      88           0 :   mPrefixIndex = 0;
      89           0 :   mColPos = 0;
      90           0 :   mIndentOverflow = 0;
      91           0 :   mIsIndentationAddedOnCurrentLine = false;
      92           0 :   mInAttribute = false;
      93           0 :   mAddNewlineForRootNode = false;
      94           0 :   mAddSpace = false;
      95           0 :   mMayIgnoreLineBreakSequence = false;
      96           0 :   mBodyOnly = false;
      97           0 :   mInBody = 0;
      98             : 
      99           0 :   if (aEncoding) {
     100           0 :     aEncoding->Name(mCharset);
     101             :   }
     102           0 :   mFlags = aFlags;
     103             : 
     104             :   // Set the line break character:
     105           0 :   if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak)
     106           0 :       && (mFlags & nsIDocumentEncoder::OutputLFLineBreak)) { // Windows
     107           0 :     mLineBreak.AssignLiteral("\r\n");
     108             :   }
     109           0 :   else if (mFlags & nsIDocumentEncoder::OutputCRLineBreak) { // Mac
     110           0 :     mLineBreak.Assign('\r');
     111             :   }
     112           0 :   else if (mFlags & nsIDocumentEncoder::OutputLFLineBreak) { // Unix/DOM
     113           0 :     mLineBreak.Assign('\n');
     114             :   }
     115             :   else {
     116           0 :     mLineBreak.AssignLiteral(NS_LINEBREAK);         // Platform/default
     117             :   }
     118             : 
     119           0 :   mDoRaw = !!(mFlags & nsIDocumentEncoder::OutputRaw);
     120             : 
     121           0 :   mDoFormat = (mFlags & nsIDocumentEncoder::OutputFormatted && !mDoRaw);
     122             : 
     123           0 :   mDoWrap = (mFlags & nsIDocumentEncoder::OutputWrap && !mDoRaw);
     124             : 
     125           0 :   mAllowLineBreaking = !(mFlags & nsIDocumentEncoder::OutputDisallowLineBreaking);
     126             : 
     127           0 :   if (!aWrapColumn) {
     128           0 :     mMaxColumn = 72;
     129             :   }
     130             :   else {
     131           0 :     mMaxColumn = aWrapColumn;
     132             :   }
     133             : 
     134           0 :   mPreLevel = 0;
     135           0 :   mIsIndentationAddedOnCurrentLine = false;
     136           0 :   return NS_OK;
     137             : }
     138             : 
     139             : nsresult
     140           0 : nsXMLContentSerializer::AppendTextData(nsIContent* aNode,
     141             :                                        int32_t aStartOffset,
     142             :                                        int32_t aEndOffset,
     143             :                                        nsAString& aStr,
     144             :                                        bool aTranslateEntities)
     145             : {
     146           0 :   nsIContent* content = aNode;
     147             :   const nsTextFragment* frag;
     148           0 :   if (!content || !(frag = content->GetText())) {
     149           0 :     return NS_ERROR_FAILURE;
     150             :   }
     151             : 
     152           0 :   int32_t fragLength = frag->GetLength();
     153           0 :   int32_t endoffset = (aEndOffset == -1) ? fragLength : std::min(aEndOffset, fragLength);
     154           0 :   int32_t length = endoffset - aStartOffset;
     155             : 
     156           0 :   NS_ASSERTION(aStartOffset >= 0, "Negative start offset for text fragment!");
     157           0 :   NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
     158             : 
     159           0 :   if (length <= 0) {
     160             :     // XXX Zero is a legal value, maybe non-zero values should be an
     161             :     // error.
     162           0 :     return NS_OK;
     163             :   }
     164             : 
     165           0 :   if (frag->Is2b()) {
     166           0 :     const char16_t *strStart = frag->Get2b() + aStartOffset;
     167           0 :     if (aTranslateEntities) {
     168           0 :       NS_ENSURE_TRUE(AppendAndTranslateEntities(Substring(strStart, strStart + length), aStr),
     169             :                      NS_ERROR_OUT_OF_MEMORY);
     170             :     }
     171             :     else {
     172           0 :       NS_ENSURE_TRUE(aStr.Append(Substring(strStart, strStart + length), mozilla::fallible),
     173             :                      NS_ERROR_OUT_OF_MEMORY);
     174             :     }
     175             :   }
     176             :   else {
     177           0 :     if (aTranslateEntities) {
     178           0 :       NS_ENSURE_TRUE(AppendAndTranslateEntities(NS_ConvertASCIItoUTF16(frag->Get1b()+aStartOffset, length), aStr),
     179             :                      NS_ERROR_OUT_OF_MEMORY);
     180             :     }
     181             :     else {
     182           0 :       NS_ENSURE_TRUE(aStr.Append(NS_ConvertASCIItoUTF16(frag->Get1b()+aStartOffset, length), mozilla::fallible),
     183             :                      NS_ERROR_OUT_OF_MEMORY);
     184             :     }
     185             :   }
     186             : 
     187           0 :   return NS_OK;
     188             : }
     189             : 
     190             : NS_IMETHODIMP
     191           0 : nsXMLContentSerializer::AppendText(nsIContent* aText,
     192             :                                    int32_t aStartOffset,
     193             :                                    int32_t aEndOffset,
     194             :                                    nsAString& aStr)
     195             : {
     196           0 :   NS_ENSURE_ARG(aText);
     197             : 
     198           0 :   nsAutoString data;
     199             :   nsresult rv;
     200             : 
     201           0 :   rv = AppendTextData(aText, aStartOffset, aEndOffset, data, true);
     202           0 :   if (NS_FAILED(rv))
     203           0 :     return NS_ERROR_FAILURE;
     204             : 
     205           0 :   if (mDoRaw || PreLevel() > 0) {
     206           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     207             :   }
     208           0 :   else if (mDoFormat) {
     209           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     210             :   }
     211           0 :   else if (mDoWrap) {
     212           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     213             :   }
     214             :   else {
     215           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     216             :   }
     217             : 
     218           0 :   return NS_OK;
     219             : }
     220             : 
     221             : NS_IMETHODIMP
     222           0 : nsXMLContentSerializer::AppendCDATASection(nsIContent* aCDATASection,
     223             :                                            int32_t aStartOffset,
     224             :                                            int32_t aEndOffset,
     225             :                                            nsAString& aStr)
     226             : {
     227           0 :   NS_ENSURE_ARG(aCDATASection);
     228             :   nsresult rv;
     229             : 
     230           0 :   NS_NAMED_LITERAL_STRING(cdata , "<![CDATA[");
     231             : 
     232           0 :   if (mDoRaw || PreLevel() > 0) {
     233           0 :     NS_ENSURE_TRUE(AppendToString(cdata, aStr), NS_ERROR_OUT_OF_MEMORY);
     234             :   }
     235           0 :   else if (mDoFormat) {
     236           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(cdata, aStr), NS_ERROR_OUT_OF_MEMORY);
     237             :   }
     238           0 :   else if (mDoWrap) {
     239           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(cdata, aStr), NS_ERROR_OUT_OF_MEMORY);
     240             :   }
     241             :   else {
     242           0 :     NS_ENSURE_TRUE(AppendToString(cdata, aStr), NS_ERROR_OUT_OF_MEMORY);
     243             :   }
     244             : 
     245           0 :   nsAutoString data;
     246           0 :   rv = AppendTextData(aCDATASection, aStartOffset, aEndOffset, data, false);
     247           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     248             : 
     249           0 :   NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     250             : 
     251           0 :   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("]]>"), aStr), NS_ERROR_OUT_OF_MEMORY);
     252             : 
     253           0 :   return NS_OK;
     254             : }
     255             : 
     256             : NS_IMETHODIMP
     257           0 : nsXMLContentSerializer::AppendProcessingInstruction(nsIContent* aPI,
     258             :                                                     int32_t aStartOffset,
     259             :                                                     int32_t aEndOffset,
     260             :                                                     nsAString& aStr)
     261             : {
     262           0 :   nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(aPI);
     263           0 :   NS_ENSURE_ARG(pi);
     264             :   nsresult rv;
     265           0 :   nsAutoString target, data, start;
     266             : 
     267           0 :   NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     268             : 
     269           0 :   rv = pi->GetTarget(target);
     270           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     271             : 
     272           0 :   rv = pi->GetData(data);
     273           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     274             : 
     275           0 :   NS_ENSURE_TRUE(start.AppendLiteral("<?", mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
     276           0 :   NS_ENSURE_TRUE(start.Append(target, mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
     277             : 
     278           0 :   if (mDoRaw || PreLevel() > 0) {
     279           0 :     NS_ENSURE_TRUE(AppendToString(start, aStr), NS_ERROR_OUT_OF_MEMORY);
     280             :   }
     281           0 :   else if (mDoFormat) {
     282           0 :     if (mAddSpace) {
     283           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     284             :     }
     285           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(start, aStr), NS_ERROR_OUT_OF_MEMORY);
     286             :   }
     287           0 :   else if (mDoWrap) {
     288           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(start, aStr), NS_ERROR_OUT_OF_MEMORY);
     289             :   }
     290             :   else {
     291           0 :     NS_ENSURE_TRUE(AppendToString(start, aStr), NS_ERROR_OUT_OF_MEMORY);
     292             :   }
     293             : 
     294           0 :   if (!data.IsEmpty()) {
     295           0 :     NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
     296           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     297             :   }
     298           0 :   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("?>"), aStr), NS_ERROR_OUT_OF_MEMORY);
     299             : 
     300           0 :   MaybeFlagNewlineForRootNode(aPI);
     301             : 
     302           0 :   return NS_OK;
     303             : }
     304             : 
     305             : NS_IMETHODIMP
     306           0 : nsXMLContentSerializer::AppendComment(nsIContent* aComment,
     307             :                                       int32_t aStartOffset,
     308             :                                       int32_t aEndOffset,
     309             :                                       nsAString& aStr)
     310             : {
     311           0 :   nsCOMPtr<nsIDOMComment> comment = do_QueryInterface(aComment);
     312           0 :   NS_ENSURE_ARG(comment);
     313             :   nsresult rv;
     314           0 :   nsAutoString data;
     315             : 
     316           0 :   rv = comment->GetData(data);
     317           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     318             : 
     319           0 :   int32_t dataLength = data.Length();
     320           0 :   if (aStartOffset || (aEndOffset != -1 && aEndOffset < dataLength)) {
     321             :     int32_t length =
     322           0 :       (aEndOffset == -1) ? dataLength : std::min(aEndOffset, dataLength);
     323           0 :     length -= aStartOffset;
     324             : 
     325           0 :     nsAutoString frag;
     326           0 :     if (length > 0) {
     327           0 :       data.Mid(frag, aStartOffset, length);
     328             :     }
     329           0 :     data.Assign(frag);
     330             :   }
     331             : 
     332           0 :   NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     333             : 
     334           0 :   NS_NAMED_LITERAL_STRING(startComment, "<!--");
     335             : 
     336           0 :   if (mDoRaw || PreLevel() > 0) {
     337           0 :     NS_ENSURE_TRUE(AppendToString(startComment, aStr), NS_ERROR_OUT_OF_MEMORY);
     338             :   }
     339           0 :   else if (mDoFormat) {
     340           0 :     if (mAddSpace) {
     341           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     342             :     }
     343           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(startComment, aStr), NS_ERROR_OUT_OF_MEMORY);
     344             :   }
     345           0 :   else if (mDoWrap) {
     346           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(startComment, aStr), NS_ERROR_OUT_OF_MEMORY);
     347             :   }
     348             :   else {
     349           0 :     NS_ENSURE_TRUE(AppendToString(startComment, aStr), NS_ERROR_OUT_OF_MEMORY);
     350             :   }
     351             : 
     352             :   // Even if mDoformat, we don't format the content because it
     353             :   // could have been preformated by the author
     354           0 :   NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     355           0 :   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("-->"), aStr), NS_ERROR_OUT_OF_MEMORY);
     356             : 
     357           0 :   MaybeFlagNewlineForRootNode(aComment);
     358             : 
     359           0 :   return NS_OK;
     360             : }
     361             : 
     362             : NS_IMETHODIMP
     363           0 : nsXMLContentSerializer::AppendDoctype(nsIContent* aDocType,
     364             :                                       nsAString& aStr)
     365             : {
     366           0 :   nsCOMPtr<nsIDOMDocumentType> docType = do_QueryInterface(aDocType);
     367           0 :   NS_ENSURE_ARG(docType);
     368             :   nsresult rv;
     369           0 :   nsAutoString name, publicId, systemId, internalSubset;
     370             : 
     371           0 :   rv = docType->GetName(name);
     372           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     373           0 :   rv = docType->GetPublicId(publicId);
     374           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     375           0 :   rv = docType->GetSystemId(systemId);
     376           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     377           0 :   rv = docType->GetInternalSubset(internalSubset);
     378           0 :   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
     379             : 
     380           0 :   NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     381             : 
     382           0 :   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("<!DOCTYPE "), aStr), NS_ERROR_OUT_OF_MEMORY);
     383           0 :   NS_ENSURE_TRUE(AppendToString(name, aStr), NS_ERROR_OUT_OF_MEMORY);
     384             : 
     385             :   char16_t quote;
     386           0 :   if (!publicId.IsEmpty()) {
     387           0 :     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" PUBLIC "), aStr), NS_ERROR_OUT_OF_MEMORY);
     388           0 :     if (publicId.FindChar(char16_t('"')) == -1) {
     389           0 :       quote = char16_t('"');
     390             :     }
     391             :     else {
     392           0 :       quote = char16_t('\'');
     393             :     }
     394           0 :     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     395           0 :     NS_ENSURE_TRUE(AppendToString(publicId, aStr), NS_ERROR_OUT_OF_MEMORY);
     396           0 :     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     397             : 
     398           0 :     if (!systemId.IsEmpty()) {
     399           0 :       NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
     400           0 :       if (systemId.FindChar(char16_t('"')) == -1) {
     401           0 :         quote = char16_t('"');
     402             :       }
     403             :       else {
     404           0 :         quote = char16_t('\'');
     405             :       }
     406           0 :       NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     407           0 :       NS_ENSURE_TRUE(AppendToString(systemId, aStr), NS_ERROR_OUT_OF_MEMORY);
     408           0 :       NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     409             :     }
     410             :   }
     411           0 :   else if (!systemId.IsEmpty()) {
     412           0 :     if (systemId.FindChar(char16_t('"')) == -1) {
     413           0 :       quote = char16_t('"');
     414             :     }
     415             :     else {
     416           0 :       quote = char16_t('\'');
     417             :     }
     418           0 :     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" SYSTEM "), aStr), NS_ERROR_OUT_OF_MEMORY);
     419           0 :     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     420           0 :     NS_ENSURE_TRUE(AppendToString(systemId, aStr), NS_ERROR_OUT_OF_MEMORY);
     421           0 :     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     422             :   }
     423             : 
     424           0 :   if (!internalSubset.IsEmpty()) {
     425           0 :     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" ["), aStr), NS_ERROR_OUT_OF_MEMORY);
     426           0 :     NS_ENSURE_TRUE(AppendToString(internalSubset, aStr), NS_ERROR_OUT_OF_MEMORY);
     427           0 :     NS_ENSURE_TRUE(AppendToString(char16_t(']'), aStr), NS_ERROR_OUT_OF_MEMORY);
     428             :   }
     429             : 
     430           0 :   NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
     431           0 :   MaybeFlagNewlineForRootNode(aDocType);
     432             : 
     433           0 :   return NS_OK;
     434             : }
     435             : 
     436             : nsresult
     437           0 : nsXMLContentSerializer::PushNameSpaceDecl(const nsAString& aPrefix,
     438             :                                           const nsAString& aURI,
     439             :                                           nsIContent* aOwner)
     440             : {
     441           0 :   NameSpaceDecl* decl = mNameSpaceStack.AppendElement();
     442           0 :   if (!decl) return NS_ERROR_OUT_OF_MEMORY;
     443             : 
     444           0 :   decl->mPrefix.Assign(aPrefix);
     445           0 :   decl->mURI.Assign(aURI);
     446             :   // Don't addref - this weak reference will be removed when
     447             :   // we pop the stack
     448           0 :   decl->mOwner = aOwner;
     449           0 :   return NS_OK;
     450             : }
     451             : 
     452             : void
     453           0 : nsXMLContentSerializer::PopNameSpaceDeclsFor(nsIContent* aOwner)
     454             : {
     455             :   int32_t index, count;
     456             : 
     457           0 :   count = mNameSpaceStack.Length();
     458           0 :   for (index = count - 1; index >= 0; index--) {
     459           0 :     if (mNameSpaceStack[index].mOwner != aOwner) {
     460           0 :       break;
     461             :     }
     462           0 :     mNameSpaceStack.RemoveElementAt(index);
     463             :   }
     464           0 : }
     465             : 
     466             : bool
     467           0 : nsXMLContentSerializer::ConfirmPrefix(nsAString& aPrefix,
     468             :                                       const nsAString& aURI,
     469             :                                       nsIContent* aElement,
     470             :                                       bool aIsAttribute)
     471             : {
     472           0 :   if (aPrefix.EqualsLiteral(kXMLNS)) {
     473           0 :     return false;
     474             :   }
     475             : 
     476           0 :   if (aURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")) {
     477             :     // The prefix must be xml for this namespace. We don't need to declare it,
     478             :     // so always just set the prefix to xml.
     479           0 :     aPrefix.AssignLiteral("xml");
     480             : 
     481           0 :     return false;
     482             :   }
     483             : 
     484             :   bool mustHavePrefix;
     485           0 :   if (aIsAttribute) {
     486           0 :     if (aURI.IsEmpty()) {
     487             :       // Attribute in the null namespace.  This just shouldn't have a prefix.
     488             :       // And there's no need to push any namespace decls
     489           0 :       aPrefix.Truncate();
     490           0 :       return false;
     491             :     }
     492             : 
     493             :     // Attribute not in the null namespace -- must have a prefix
     494           0 :     mustHavePrefix = true;
     495             :   } else {
     496             :     // Not an attribute, so doesn't _have_ to have a prefix
     497           0 :     mustHavePrefix = false;
     498             :   }
     499             : 
     500             :   // Keep track of the closest prefix that's bound to aURI and whether we've
     501             :   // found such a thing.  closestURIMatch holds the prefix, and uriMatch
     502             :   // indicates whether we actually have one.
     503           0 :   nsAutoString closestURIMatch;
     504           0 :   bool uriMatch = false;
     505             : 
     506             :   // Also keep track of whether we've seen aPrefix already.  If we have, that
     507             :   // means that it's already bound to a URI different from aURI, so even if we
     508             :   // later (so in a more outer scope) see it bound to aURI we can't reuse it.
     509           0 :   bool haveSeenOurPrefix = false;
     510             : 
     511           0 :   int32_t count = mNameSpaceStack.Length();
     512           0 :   int32_t index = count - 1;
     513           0 :   while (index >= 0) {
     514           0 :     NameSpaceDecl& decl = mNameSpaceStack.ElementAt(index);
     515             :     // Check if we've found a prefix match
     516           0 :     if (aPrefix.Equals(decl.mPrefix)) {
     517             : 
     518             :       // If the URIs match and aPrefix is not bound to any other URI, we can
     519             :       // use aPrefix
     520           0 :       if (!haveSeenOurPrefix && aURI.Equals(decl.mURI)) {
     521             :         // Just use our uriMatch stuff.  That will deal with an empty aPrefix
     522             :         // the right way.  We can break out of the loop now, though.
     523           0 :         uriMatch = true;
     524           0 :         closestURIMatch = aPrefix;
     525           0 :         break;
     526             :       }
     527             : 
     528           0 :       haveSeenOurPrefix = true;
     529             : 
     530             :       // If they don't, and either:
     531             :       // 1) We have a prefix (so we'd be redeclaring this prefix to point to a
     532             :       //    different namespace) or
     533             :       // 2) We're looking at an existing default namespace decl on aElement (so
     534             :       //    we can't create a new default namespace decl for this URI)
     535             :       // then generate a new prefix.  Note that we do NOT generate new prefixes
     536             :       // if we happen to have aPrefix == decl->mPrefix == "" and mismatching
     537             :       // URIs when |decl| doesn't have aElement as its owner.  In that case we
     538             :       // can simply push the new namespace URI as the default namespace for
     539             :       // aElement.
     540           0 :       if (!aPrefix.IsEmpty() || decl.mOwner == aElement) {
     541           0 :         NS_ASSERTION(!aURI.IsEmpty(),
     542             :                      "Not allowed to add a xmlns attribute with an empty "
     543             :                      "namespace name unless it declares the default "
     544             :                      "namespace.");
     545             : 
     546           0 :         GenerateNewPrefix(aPrefix);
     547             :         // Now we need to validate our new prefix/uri combination; check it
     548             :         // against the full namespace stack again.  Note that just restarting
     549             :         // the while loop is ok, since we haven't changed aURI, so the
     550             :         // closestURIMatch and uriMatch state is not affected.
     551           0 :         index = count - 1;
     552           0 :         haveSeenOurPrefix = false;
     553           0 :         continue;
     554             :       }
     555             :     }
     556             : 
     557             :     // If we've found a URI match, then record the first one
     558           0 :     if (!uriMatch && aURI.Equals(decl.mURI)) {
     559             :       // Need to check that decl->mPrefix is not declared anywhere closer to
     560             :       // us.  If it is, we can't use it.
     561           0 :       bool prefixOK = true;
     562             :       int32_t index2;
     563           0 :       for (index2 = count-1; index2 > index && prefixOK; --index2) {
     564           0 :         prefixOK = (mNameSpaceStack[index2].mPrefix != decl.mPrefix);
     565             :       }
     566             : 
     567           0 :       if (prefixOK) {
     568           0 :         uriMatch = true;
     569           0 :         closestURIMatch.Assign(decl.mPrefix);
     570             :       }
     571             :     }
     572             : 
     573           0 :     --index;
     574             :   }
     575             : 
     576             :   // At this point the following invariants hold:
     577             :   // 1) The prefix in closestURIMatch is mapped to aURI in our scope if
     578             :   //    uriMatch is set.
     579             :   // 2) There is nothing on the namespace stack that has aPrefix as the prefix
     580             :   //    and a _different_ URI, except for the case aPrefix.IsEmpty (and
     581             :   //    possible default namespaces on ancestors)
     582             : 
     583             :   // So if uriMatch is set it's OK to use the closestURIMatch prefix.  The one
     584             :   // exception is when closestURIMatch is actually empty (default namespace
     585             :   // decl) and we must have a prefix.
     586           0 :   if (uriMatch && (!mustHavePrefix || !closestURIMatch.IsEmpty())) {
     587           0 :     aPrefix.Assign(closestURIMatch);
     588           0 :     return false;
     589             :   }
     590             : 
     591           0 :   if (aPrefix.IsEmpty()) {
     592             :     // At this point, aPrefix is empty (which means we never had a prefix to
     593             :     // start with).  If we must have a prefix, just generate a new prefix and
     594             :     // then send it back through the namespace stack checks to make sure it's
     595             :     // OK.
     596           0 :     if (mustHavePrefix) {
     597           0 :       GenerateNewPrefix(aPrefix);
     598           0 :       return ConfirmPrefix(aPrefix, aURI, aElement, aIsAttribute);
     599             :     }
     600             : 
     601             :     // One final special case.  If aPrefix is empty and we never saw an empty
     602             :     // prefix (default namespace decl) on the namespace stack and we're in the
     603             :     // null namespace there is no reason to output an |xmlns=""| here.  It just
     604             :     // makes the output less readable.
     605           0 :     if (!haveSeenOurPrefix && aURI.IsEmpty()) {
     606           0 :       return false;
     607             :     }
     608             :   }
     609             : 
     610             :   // Now just set aURI as the new default namespace URI.  Indicate that we need
     611             :   // to create a namespace decl for the final prefix
     612           0 :   return true;
     613             : }
     614             : 
     615             : void
     616           0 : nsXMLContentSerializer::GenerateNewPrefix(nsAString& aPrefix)
     617             : {
     618           0 :   aPrefix.Assign('a');
     619             :   char buf[128];
     620           0 :   SprintfLiteral(buf, "%d", mPrefixIndex++);
     621           0 :   AppendASCIItoUTF16(buf, aPrefix);
     622           0 : }
     623             : 
     624             : bool
     625           0 : nsXMLContentSerializer::SerializeAttr(const nsAString& aPrefix,
     626             :                                       const nsAString& aName,
     627             :                                       const nsAString& aValue,
     628             :                                       nsAString& aStr,
     629             :                                       bool aDoEscapeEntities)
     630             : {
     631           0 :   nsAutoString attrString_;
     632             :   // For innerHTML we can do faster appending without
     633             :   // temporary strings.
     634           0 :   bool rawAppend = mDoRaw && aDoEscapeEntities;
     635           0 :   nsAString& attrString = (rawAppend) ? aStr : attrString_;
     636             : 
     637           0 :   NS_ENSURE_TRUE(attrString.Append(char16_t(' '), mozilla::fallible), false);
     638           0 :   if (!aPrefix.IsEmpty()) {
     639           0 :     NS_ENSURE_TRUE(attrString.Append(aPrefix, mozilla::fallible), false);
     640           0 :     NS_ENSURE_TRUE(attrString.Append(char16_t(':'), mozilla::fallible), false);
     641             :   }
     642           0 :   NS_ENSURE_TRUE(attrString.Append(aName, mozilla::fallible), false);
     643             : 
     644           0 :   if (aDoEscapeEntities) {
     645             :     // if problem characters are turned into character entity references
     646             :     // then there will be no problem with the value delimiter characters
     647           0 :     NS_ENSURE_TRUE(attrString.AppendLiteral("=\"", mozilla::fallible), false);
     648             : 
     649           0 :     mInAttribute = true;
     650           0 :     bool result = AppendAndTranslateEntities(aValue, attrString);
     651           0 :     mInAttribute = false;
     652           0 :     NS_ENSURE_TRUE(result, false);
     653             : 
     654           0 :     NS_ENSURE_TRUE(attrString.Append(char16_t('"'), mozilla::fallible), false);
     655           0 :     if (rawAppend) {
     656           0 :       return true;
     657             :     }
     658             :   }
     659             :   else {
     660             :     // Depending on whether the attribute value contains quotes or apostrophes we
     661             :     // need to select the delimiter character and escape characters using
     662             :     // character entity references, ignoring the value of aDoEscapeEntities.
     663             :     // See http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2.2 for
     664             :     // the standard on character entity references in values.  We also have to
     665             :     // make sure to escape any '&' characters.
     666             : 
     667           0 :     bool bIncludesSingle = false;
     668           0 :     bool bIncludesDouble = false;
     669           0 :     nsAString::const_iterator iCurr, iEnd;
     670           0 :     aValue.BeginReading(iCurr);
     671           0 :     aValue.EndReading(iEnd);
     672           0 :     for ( ; iCurr != iEnd; ++iCurr) {
     673           0 :       if (*iCurr == char16_t('\'')) {
     674           0 :         bIncludesSingle = true;
     675           0 :         if (bIncludesDouble) {
     676           0 :           break;
     677             :         }
     678           0 :       } else if (*iCurr == char16_t('"')) {
     679           0 :         bIncludesDouble = true;
     680           0 :         if (bIncludesSingle) {
     681           0 :           break;
     682             :         }
     683             :       }
     684             :     }
     685             : 
     686             :     // Delimiter and escaping is according to the following table
     687             :     //    bIncludesDouble     bIncludesSingle     Delimiter       Escape Double Quote
     688             :     //    FALSE               FALSE               "               FALSE
     689             :     //    FALSE               TRUE                "               FALSE
     690             :     //    TRUE                FALSE               '               FALSE
     691             :     //    TRUE                TRUE                "               TRUE
     692             :     char16_t cDelimiter =
     693           0 :         (bIncludesDouble && !bIncludesSingle) ? char16_t('\'') : char16_t('"');
     694           0 :     NS_ENSURE_TRUE(attrString.Append(char16_t('='), mozilla::fallible), false);
     695           0 :     NS_ENSURE_TRUE(attrString.Append(cDelimiter, mozilla::fallible), false);
     696           0 :     nsAutoString sValue(aValue);
     697           0 :     NS_ENSURE_TRUE(sValue.ReplaceSubstring(NS_LITERAL_STRING("&"),
     698             :                                            NS_LITERAL_STRING("&amp;"), mozilla::fallible), false);
     699           0 :     if (bIncludesDouble && bIncludesSingle) {
     700           0 :       NS_ENSURE_TRUE(sValue.ReplaceSubstring(NS_LITERAL_STRING("\""),
     701             :                                              NS_LITERAL_STRING("&quot;"), mozilla::fallible), false);
     702             :     }
     703           0 :     NS_ENSURE_TRUE(attrString.Append(sValue, mozilla::fallible), false);
     704           0 :     NS_ENSURE_TRUE(attrString.Append(cDelimiter, mozilla::fallible), false);
     705             :   }
     706           0 :   if (mDoRaw || PreLevel() > 0) {
     707           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(attrString, aStr), false);
     708             :   }
     709           0 :   else if (mDoFormat) {
     710           0 :     NS_ENSURE_TRUE(AppendToStringFormatedWrapped(attrString, aStr), false);
     711             :   }
     712           0 :   else if (mDoWrap) {
     713           0 :     NS_ENSURE_TRUE(AppendToStringWrapped(attrString, aStr), false);
     714             :   }
     715             :   else {
     716           0 :     NS_ENSURE_TRUE(AppendToStringConvertLF(attrString, aStr), false);
     717             :   }
     718             : 
     719           0 :   return true;
     720             : }
     721             : 
     722             : uint32_t
     723           0 : nsXMLContentSerializer::ScanNamespaceDeclarations(nsIContent* aContent,
     724             :                                                   nsIContent *aOriginalElement,
     725             :                                                   const nsAString& aTagNamespaceURI)
     726             : {
     727             :   uint32_t index, count;
     728           0 :   nsAutoString uriStr, valueStr;
     729             : 
     730           0 :   count = aContent->GetAttrCount();
     731             : 
     732             :   // First scan for namespace declarations, pushing each on the stack
     733           0 :   uint32_t skipAttr = count;
     734           0 :   for (index = 0; index < count; index++) {
     735             : 
     736           0 :     const BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
     737           0 :     const nsAttrName* name = info.mName;
     738             : 
     739           0 :     int32_t namespaceID = name->NamespaceID();
     740           0 :     nsIAtom *attrName = name->LocalName();
     741             : 
     742           0 :     if (namespaceID == kNameSpaceID_XMLNS ||
     743             :         // Also push on the stack attrs named "xmlns" in the null
     744             :         // namespace... because once we serialize those out they'll look like
     745             :         // namespace decls.  :(
     746             :         // XXXbz what if we have both "xmlns" in the null namespace and "xmlns"
     747             :         // in the xmlns namespace?
     748           0 :         (namespaceID == kNameSpaceID_None &&
     749           0 :          attrName == nsGkAtoms::xmlns)) {
     750           0 :       info.mValue->ToString(uriStr);
     751             : 
     752           0 :       if (!name->GetPrefix()) {
     753           0 :         if (aTagNamespaceURI.IsEmpty() && !uriStr.IsEmpty()) {
     754             :           // If the element is in no namespace we need to add a xmlns
     755             :           // attribute to declare that. That xmlns attribute must not have a
     756             :           // prefix (see http://www.w3.org/TR/REC-xml-names/#dt-prefix), ie it
     757             :           // must declare the default namespace. We just found an xmlns
     758             :           // attribute that declares the default namespace to something
     759             :           // non-empty. We're going to ignore this attribute, for children we
     760             :           // will detect that we need to add it again and attributes aren't
     761             :           // affected by the default namespace.
     762           0 :           skipAttr = index;
     763             :         }
     764             :         else {
     765             :           // Default NS attribute does not have prefix (and the name is "xmlns")
     766           0 :           PushNameSpaceDecl(EmptyString(), uriStr, aOriginalElement);
     767             :         }
     768             :       }
     769             :       else {
     770           0 :         PushNameSpaceDecl(nsDependentAtomString(attrName), uriStr,
     771           0 :                           aOriginalElement);
     772             :       }
     773             :     }
     774             :   }
     775           0 :   return skipAttr;
     776             : }
     777             : 
     778             : 
     779             : bool
     780           0 : nsXMLContentSerializer::IsJavaScript(nsIContent * aContent, nsIAtom* aAttrNameAtom,
     781             :                                      int32_t aAttrNamespaceID, const nsAString& aValueString)
     782             : {
     783           0 :   bool isHtml = aContent->IsHTMLElement();
     784           0 :   bool isXul = aContent->IsXULElement();
     785           0 :   bool isSvg = aContent->IsSVGElement();
     786             : 
     787           0 :   if (aAttrNamespaceID == kNameSpaceID_None &&
     788           0 :       (isHtml || isXul || isSvg) &&
     789           0 :       (aAttrNameAtom == nsGkAtoms::href ||
     790           0 :        aAttrNameAtom == nsGkAtoms::src)) {
     791             : 
     792             :     static const char kJavaScript[] = "javascript";
     793           0 :     int32_t pos = aValueString.FindChar(':');
     794           0 :     if (pos < (int32_t)(sizeof kJavaScript - 1))
     795           0 :         return false;
     796           0 :     nsAutoString scheme(Substring(aValueString, 0, pos));
     797           0 :     scheme.StripWhitespace();
     798           0 :     if ((scheme.Length() == (sizeof kJavaScript - 1)) &&
     799           0 :         scheme.EqualsIgnoreCase(kJavaScript))
     800           0 :       return true;
     801             :     else
     802           0 :       return false;
     803             :   }
     804             : 
     805           0 :   return aContent->IsEventAttributeName(aAttrNameAtom);
     806             : }
     807             : 
     808             : 
     809             : bool
     810           0 : nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
     811             :                                             nsIContent *aOriginalElement,
     812             :                                             nsAString& aTagPrefix,
     813             :                                             const nsAString& aTagNamespaceURI,
     814             :                                             nsIAtom* aTagName,
     815             :                                             nsAString& aStr,
     816             :                                             uint32_t aSkipAttr,
     817             :                                             bool aAddNSAttr)
     818             : {
     819             : 
     820           0 :   nsAutoString prefixStr, uriStr, valueStr;
     821           0 :   nsAutoString xmlnsStr;
     822           0 :   xmlnsStr.AssignLiteral(kXMLNS);
     823             :   uint32_t index, count;
     824             : 
     825             :   // If we had to add a new namespace declaration, serialize
     826             :   // and push it on the namespace stack
     827           0 :   if (aAddNSAttr) {
     828           0 :     if (aTagPrefix.IsEmpty()) {
     829             :       // Serialize default namespace decl
     830           0 :       NS_ENSURE_TRUE(SerializeAttr(EmptyString(), xmlnsStr, aTagNamespaceURI, aStr, true), false);
     831             :     }
     832             :     else {
     833             :       // Serialize namespace decl
     834           0 :       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, aTagPrefix, aTagNamespaceURI, aStr, true), false);
     835             :     }
     836           0 :     PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
     837             :   }
     838             : 
     839           0 :   count = aContent->GetAttrCount();
     840             : 
     841             :   // Now serialize each of the attributes
     842             :   // XXX Unfortunately we need a namespace manager to get
     843             :   // attribute URIs.
     844           0 :   for (index = 0; index < count; index++) {
     845           0 :     if (aSkipAttr == index) {
     846           0 :         continue;
     847             :     }
     848             : 
     849           0 :     const nsAttrName* name = aContent->GetAttrNameAt(index);
     850           0 :     int32_t namespaceID = name->NamespaceID();
     851           0 :     nsIAtom* attrName = name->LocalName();
     852           0 :     nsIAtom* attrPrefix = name->GetPrefix();
     853             : 
     854             :     // Filter out any attribute starting with [-|_]moz
     855           0 :     nsDependentAtomString attrNameStr(attrName);
     856           0 :     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
     857           0 :         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
     858           0 :       continue;
     859             :     }
     860             : 
     861           0 :     if (attrPrefix) {
     862           0 :       attrPrefix->ToString(prefixStr);
     863             :     }
     864             :     else {
     865           0 :       prefixStr.Truncate();
     866             :     }
     867             : 
     868           0 :     bool addNSAttr = false;
     869           0 :     if (kNameSpaceID_XMLNS != namespaceID) {
     870           0 :       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
     871           0 :       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     872             :     }
     873             : 
     874           0 :     aContent->GetAttr(namespaceID, attrName, valueStr);
     875             : 
     876           0 :     nsDependentAtomString nameStr(attrName);
     877           0 :     bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
     878             : 
     879           0 :     NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
     880             : 
     881           0 :     if (addNSAttr) {
     882           0 :       NS_ASSERTION(!prefixStr.IsEmpty(),
     883             :                    "Namespaced attributes must have a prefix");
     884           0 :       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false);
     885           0 :       PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement);
     886             :     }
     887             :   }
     888             : 
     889           0 :   return true;
     890             : }
     891             : 
     892             : NS_IMETHODIMP
     893           0 : nsXMLContentSerializer::AppendElementStart(Element* aElement,
     894             :                                            Element* aOriginalElement,
     895             :                                            nsAString& aStr)
     896             : {
     897           0 :   NS_ENSURE_ARG(aElement);
     898             : 
     899           0 :   nsIContent* content = aElement;
     900             : 
     901           0 :   bool forceFormat = false;
     902           0 :   nsresult rv = NS_OK;
     903           0 :   if (!CheckElementStart(content, forceFormat, aStr, rv)) {
     904             :     // When we go to AppendElementEnd for this element, we're going to
     905             :     // MaybeLeaveFromPreContent().  So make sure to MaybeEnterInPreContent()
     906             :     // now, so our PreLevel() doesn't get confused.
     907           0 :     MaybeEnterInPreContent(content);
     908           0 :     return rv;
     909             :   }
     910             : 
     911           0 :   NS_ENSURE_SUCCESS(rv, rv);
     912             : 
     913           0 :   nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
     914           0 :   aElement->NodeInfo()->GetPrefix(tagPrefix);
     915           0 :   aElement->NodeInfo()->GetName(tagLocalName);
     916           0 :   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
     917             : 
     918             :   uint32_t skipAttr = ScanNamespaceDeclarations(content,
     919           0 :                           aOriginalElement, tagNamespaceURI);
     920             : 
     921           0 :   nsIAtom *name = content->NodeInfo()->NameAtom();
     922           0 :   bool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);
     923             : 
     924           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     925           0 :     if (mColPos && lineBreakBeforeOpen) {
     926           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     927             :     }
     928             :     else {
     929           0 :       NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     930             :     }
     931           0 :     if (!mColPos) {
     932           0 :       NS_ENSURE_TRUE(AppendIndentation(aStr), NS_ERROR_OUT_OF_MEMORY);
     933             :     }
     934           0 :     else if (mAddSpace) {
     935           0 :       NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
     936           0 :       mAddSpace = false;
     937             :     }
     938             :   }
     939           0 :   else if (mAddSpace) {
     940           0 :     NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
     941           0 :     mAddSpace = false;
     942             :   }
     943             :   else {
     944           0 :     NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     945             :   }
     946             : 
     947             :   // Always reset to avoid false newlines in case MaybeAddNewlineForRootNode wasn't
     948             :   // called
     949           0 :   mAddNewlineForRootNode = false;
     950             : 
     951             :   bool addNSAttr;
     952             :   addNSAttr = ConfirmPrefix(tagPrefix, tagNamespaceURI, aOriginalElement,
     953           0 :                             false);
     954             : 
     955             :   // Serialize the qualified name of the element
     956           0 :   NS_ENSURE_TRUE(AppendToString(kLessThan, aStr), NS_ERROR_OUT_OF_MEMORY);
     957           0 :   if (!tagPrefix.IsEmpty()) {
     958           0 :     NS_ENSURE_TRUE(AppendToString(tagPrefix, aStr), NS_ERROR_OUT_OF_MEMORY);
     959           0 :     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(":"), aStr), NS_ERROR_OUT_OF_MEMORY);
     960             :   }
     961           0 :   NS_ENSURE_TRUE(AppendToString(tagLocalName, aStr), NS_ERROR_OUT_OF_MEMORY);
     962             : 
     963           0 :   MaybeEnterInPreContent(content);
     964             : 
     965           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     966           0 :     NS_ENSURE_TRUE(IncrIndentation(name), NS_ERROR_OUT_OF_MEMORY);
     967             :   }
     968             : 
     969           0 :   NS_ENSURE_TRUE(SerializeAttributes(content, aOriginalElement, tagPrefix, tagNamespaceURI,
     970             :                                      name, aStr, skipAttr, addNSAttr),
     971             :                  NS_ERROR_OUT_OF_MEMORY);
     972             : 
     973           0 :   NS_ENSURE_TRUE(AppendEndOfElementStart(aElement, aOriginalElement, aStr),
     974             :                  NS_ERROR_OUT_OF_MEMORY);
     975             : 
     976           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
     977           0 :     && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
     978           0 :     NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     979             :   }
     980             : 
     981           0 :   NS_ENSURE_TRUE(AfterElementStart(content, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
     982             : 
     983           0 :   return NS_OK;
     984             : }
     985             : 
     986             : // aElement is the actual element we're outputting.  aOriginalElement is the one
     987             : // in the original DOM, which is the one we have to test for kids.
     988             : static bool
     989           0 : ElementNeedsSeparateEndTag(Element* aElement, Element* aOriginalElement)
     990             : {
     991           0 :   if (aOriginalElement->GetChildCount()) {
     992             :     // We have kids, so we need a separate end tag.  This needs to be checked on
     993             :     // aOriginalElement because that's the one that's actually in the DOM and
     994             :     // might have kids.
     995           0 :     return true;
     996             :   }
     997             : 
     998           0 :   if (!aElement->IsHTMLElement()) {
     999             :     // Empty non-HTML elements can just skip a separate end tag.
    1000           0 :     return false;
    1001             :   }
    1002             : 
    1003             :   // HTML container tags should have a separate end tag even if empty, per spec.
    1004             :   // See
    1005             :   // https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
    1006           0 :   bool isHTMLContainer = true; // Default in case we get no parser service.
    1007           0 :   nsIParserService* parserService = nsContentUtils::GetParserService();
    1008           0 :   if (parserService) {
    1009           0 :     nsIAtom* localName = aElement->NodeInfo()->NameAtom();
    1010           0 :     parserService->IsContainer(
    1011           0 :       parserService->HTMLCaseSensitiveAtomTagToId(localName),
    1012           0 :       isHTMLContainer);
    1013             :   }
    1014           0 :   return isHTMLContainer;
    1015             : }
    1016             : 
    1017             : bool
    1018           0 : nsXMLContentSerializer::AppendEndOfElementStart(Element* aElement,
    1019             :                                                 Element* aOriginalElement,
    1020             :                                                 nsAString& aStr)
    1021             : {
    1022           0 :   if (ElementNeedsSeparateEndTag(aElement, aOriginalElement)) {
    1023           0 :     return AppendToString(kGreaterThan, aStr);
    1024             :   }
    1025             : 
    1026             :   // We don't need a separate end tag.  For HTML elements (which at this point
    1027             :   // must be non-containers), append a space before the '/', per spec.  See
    1028             :   // https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
    1029           0 :   if (aOriginalElement->IsHTMLElement()) {
    1030           0 :     if (!AppendToString(kSpace, aStr)) {
    1031           0 :       return false;
    1032             :     }
    1033             :   }
    1034             : 
    1035           0 :   return AppendToString(NS_LITERAL_STRING("/>"), aStr);
    1036             : }
    1037             : 
    1038             : NS_IMETHODIMP
    1039           0 : nsXMLContentSerializer::AppendElementEnd(Element* aElement,
    1040             :                                          nsAString& aStr)
    1041             : {
    1042           0 :   NS_ENSURE_ARG(aElement);
    1043             : 
    1044           0 :   nsIContent* content = aElement;
    1045             : 
    1046           0 :   bool forceFormat = false, outputElementEnd;
    1047           0 :   outputElementEnd = CheckElementEnd(aElement, forceFormat, aStr);
    1048             : 
    1049           0 :   nsIAtom *name = content->NodeInfo()->NameAtom();
    1050             : 
    1051           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
    1052           0 :     DecrIndentation(name);
    1053             :   }
    1054             : 
    1055           0 :   if (!outputElementEnd) {
    1056             :     // Keep this in sync with the cleanup at the end of this method.
    1057           0 :     PopNameSpaceDeclsFor(aElement);
    1058           0 :     MaybeLeaveFromPreContent(content);
    1059           0 :     MaybeFlagNewlineForRootNode(aElement);
    1060           0 :     AfterElementEnd(content, aStr);
    1061           0 :     return NS_OK;
    1062             :   }
    1063             : 
    1064           0 :   nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
    1065             : 
    1066           0 :   aElement->NodeInfo()->GetPrefix(tagPrefix);
    1067           0 :   aElement->NodeInfo()->GetName(tagLocalName);
    1068           0 :   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
    1069             : 
    1070             : #ifdef DEBUG
    1071             :   bool debugNeedToPushNamespace =
    1072             : #endif
    1073           0 :   ConfirmPrefix(tagPrefix, tagNamespaceURI, aElement, false);
    1074           0 :   NS_ASSERTION(!debugNeedToPushNamespace, "Can't push namespaces in closing tag!");
    1075             : 
    1076           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
    1077             : 
    1078           0 :     bool lineBreakBeforeClose = LineBreakBeforeClose(content->GetNameSpaceID(), name);
    1079             : 
    1080           0 :     if (mColPos && lineBreakBeforeClose) {
    1081           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
    1082             :     }
    1083           0 :     if (!mColPos) {
    1084           0 :       NS_ENSURE_TRUE(AppendIndentation(aStr), NS_ERROR_OUT_OF_MEMORY);
    1085             :     }
    1086           0 :     else if (mAddSpace) {
    1087           0 :       NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
    1088           0 :       mAddSpace = false;
    1089             :     }
    1090             :   }
    1091           0 :   else if (mAddSpace) {
    1092           0 :     NS_ENSURE_TRUE(AppendToString(char16_t(' '), aStr), NS_ERROR_OUT_OF_MEMORY);
    1093           0 :     mAddSpace = false;
    1094             :   }
    1095             : 
    1096           0 :   NS_ENSURE_TRUE(AppendToString(kEndTag, aStr), NS_ERROR_OUT_OF_MEMORY);
    1097           0 :   if (!tagPrefix.IsEmpty()) {
    1098           0 :     NS_ENSURE_TRUE(AppendToString(tagPrefix, aStr), NS_ERROR_OUT_OF_MEMORY);
    1099           0 :     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(":"), aStr), NS_ERROR_OUT_OF_MEMORY);
    1100             :   }
    1101           0 :   NS_ENSURE_TRUE(AppendToString(tagLocalName, aStr), NS_ERROR_OUT_OF_MEMORY);
    1102           0 :   NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
    1103             : 
    1104             :   // Keep what follows in sync with the cleanup in the !outputElementEnd case.
    1105           0 :   PopNameSpaceDeclsFor(aElement);
    1106             : 
    1107           0 :   MaybeLeaveFromPreContent(content);
    1108             : 
    1109           0 :   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
    1110           0 :       && LineBreakAfterClose(content->GetNameSpaceID(), name)) {
    1111           0 :     NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
    1112             :   }
    1113             :   else {
    1114           0 :     MaybeFlagNewlineForRootNode(aElement);
    1115             :   }
    1116             : 
    1117           0 :   AfterElementEnd(content, aStr);
    1118             : 
    1119           0 :   return NS_OK;
    1120             : }
    1121             : 
    1122             : NS_IMETHODIMP
    1123           0 : nsXMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
    1124             :                                             nsAString& aStr)
    1125             : {
    1126           0 :   NS_ENSURE_ARG_POINTER(aDocument);
    1127             : 
    1128           0 :   nsAutoString version, encoding, standalone;
    1129           0 :   aDocument->GetXMLDeclaration(version, encoding, standalone);
    1130             : 
    1131           0 :   if (version.IsEmpty())
    1132           0 :     return NS_OK; // A declaration must have version, or there is no decl
    1133             : 
    1134           0 :   NS_NAMED_LITERAL_STRING(endQuote, "\"");
    1135             : 
    1136           0 :   aStr += NS_LITERAL_STRING("<?xml version=\"") + version + endQuote;
    1137             : 
    1138           0 :   if (!mCharset.IsEmpty()) {
    1139           0 :     aStr += NS_LITERAL_STRING(" encoding=\"") +
    1140           0 :       NS_ConvertASCIItoUTF16(mCharset) + endQuote;
    1141             :   }
    1142             :   // Otherwise just don't output an encoding attr.  Not that we expect
    1143             :   // mCharset to ever be empty.
    1144             : #ifdef DEBUG
    1145             :   else {
    1146           0 :     NS_WARNING("Empty mCharset?  How come?");
    1147             :   }
    1148             : #endif
    1149             : 
    1150           0 :   if (!standalone.IsEmpty()) {
    1151           0 :     aStr += NS_LITERAL_STRING(" standalone=\"") + standalone + endQuote;
    1152             :   }
    1153             : 
    1154           0 :   NS_ENSURE_TRUE(aStr.AppendLiteral("?>", mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
    1155           0 :   mAddNewlineForRootNode = true;
    1156             : 
    1157           0 :   return NS_OK;
    1158             : }
    1159             : 
    1160             : bool
    1161           0 : nsXMLContentSerializer::CheckElementStart(nsIContent * aContent,
    1162             :                                           bool & aForceFormat,
    1163             :                                           nsAString& aStr,
    1164             :                                           nsresult& aResult)
    1165             : {
    1166           0 :   aResult = NS_OK;
    1167           0 :   aForceFormat = false;
    1168           0 :   return true;
    1169             : }
    1170             : 
    1171             : bool
    1172           0 : nsXMLContentSerializer::CheckElementEnd(Element* aElement,
    1173             :                                         bool& aForceFormat,
    1174             :                                         nsAString& aStr)
    1175             : {
    1176             :   // We don't output a separate end tag for empty element
    1177           0 :   aForceFormat = false;
    1178             : 
    1179             :   // XXXbz this is a bit messed up, but by now we don't have our fixed-up
    1180             :   // version of aElement anymore.  Let's hope fixup never changes the localName
    1181             :   // or namespace...
    1182           0 :   return ElementNeedsSeparateEndTag(aElement, aElement);
    1183             : }
    1184             : 
    1185             : bool
    1186           0 : nsXMLContentSerializer::AppendToString(const char16_t aChar,
    1187             :                                        nsAString& aOutputStr)
    1188             : {
    1189           0 :   if (mBodyOnly && !mInBody) {
    1190           0 :     return true;
    1191             :   }
    1192           0 :   mColPos += 1;
    1193           0 :   return aOutputStr.Append(aChar, mozilla::fallible);
    1194             : }
    1195             : 
    1196             : bool
    1197           0 : nsXMLContentSerializer::AppendToString(const nsAString& aStr,
    1198             :                                        nsAString& aOutputStr)
    1199             : {
    1200           0 :   if (mBodyOnly && !mInBody) {
    1201           0 :     return true;
    1202             :   }
    1203           0 :   mColPos += aStr.Length();
    1204           0 :   return aOutputStr.Append(aStr, mozilla::fallible);
    1205             : }
    1206             : 
    1207             : 
    1208             : static const uint16_t kGTVal = 62;
    1209             : 
    1210             : #define _ 0
    1211             : 
    1212             : // This table indexes into kEntityStrings[].
    1213             : static const uint8_t kEntities[] = {
    1214             :   _, _, _, _, _, _, _, _, _, _,
    1215             :   _, _, _, _, _, _, _, _, _, _,
    1216             :   _, _, _, _, _, _, _, _, _, _,
    1217             :   _, _, _, _, _, _, _, _, 2, _,
    1218             :   _, _, _, _, _, _, _, _, _, _,
    1219             :   _, _, _, _, _, _, _, _, _, _,
    1220             :   3, _, 4
    1221             : };
    1222             : 
    1223             : // This table indexes into kEntityStrings[].
    1224             : static const uint8_t kAttrEntities[] = {
    1225             :   _, _, _, _, _, _, _, _, _, _,
    1226             :   _, _, _, _, _, _, _, _, _, _,
    1227             :   _, _, _, _, _, _, _, _, _, _,
    1228             :   _, _, _, _, 1, _, _, _, 2, _,
    1229             :   _, _, _, _, _, _, _, _, _, _,
    1230             :   _, _, _, _, _, _, _, _, _, _,
    1231             :   3, _, 4
    1232             : };
    1233             : 
    1234             : #undef _
    1235             : 
    1236             : static const char* const kEntityStrings[] = {
    1237             :   /* 0 */ nullptr,
    1238             :   /* 1 */ "&quot;",
    1239             :   /* 2 */ "&amp;",
    1240             :   /* 3 */ "&lt;",
    1241             :   /* 4 */ "&gt;",
    1242             : };
    1243             : 
    1244             : bool
    1245           0 : nsXMLContentSerializer::AppendAndTranslateEntities(const nsAString& aStr,
    1246             :                                                    nsAString& aOutputStr)
    1247             : {
    1248           0 :   nsReadingIterator<char16_t> done_reading;
    1249           0 :   aStr.EndReading(done_reading);
    1250             : 
    1251             :   // for each chunk of |aString|...
    1252           0 :   uint32_t advanceLength = 0;
    1253           0 :   nsReadingIterator<char16_t> iter;
    1254             : 
    1255           0 :   const uint8_t* entityTable = mInAttribute ? kAttrEntities : kEntities;
    1256             : 
    1257           0 :   for (aStr.BeginReading(iter);
    1258             :        iter != done_reading;
    1259           0 :        iter.advance(int32_t(advanceLength))) {
    1260           0 :     uint32_t fragmentLength = done_reading - iter;
    1261           0 :     const char16_t* c = iter.get();
    1262           0 :     const char16_t* fragmentStart = c;
    1263           0 :     const char16_t* fragmentEnd = c + fragmentLength;
    1264           0 :     const char* entityText = nullptr;
    1265             : 
    1266           0 :     advanceLength = 0;
    1267             :     // for each character in this chunk, check if it
    1268             :     // needs to be replaced
    1269           0 :     for (; c < fragmentEnd; c++, advanceLength++) {
    1270           0 :       char16_t val = *c;
    1271           0 :       if ((val <= kGTVal) && entityTable[val]) {
    1272           0 :         entityText = kEntityStrings[entityTable[val]];
    1273           0 :         break;
    1274             :       }
    1275             :     }
    1276             : 
    1277           0 :     NS_ENSURE_TRUE(aOutputStr.Append(fragmentStart, advanceLength, mozilla::fallible), false);
    1278           0 :     if (entityText) {
    1279           0 :       NS_ENSURE_TRUE(AppendASCIItoUTF16(entityText, aOutputStr, mozilla::fallible), false);
    1280           0 :       advanceLength++;
    1281             :     }
    1282             :   }
    1283             : 
    1284           0 :   return true;
    1285             : }
    1286             : 
    1287             : bool
    1288           0 : nsXMLContentSerializer::MaybeAddNewlineForRootNode(nsAString& aStr)
    1289             : {
    1290           0 :   if (mAddNewlineForRootNode) {
    1291           0 :     return AppendNewLineToString(aStr);
    1292             :   }
    1293             : 
    1294           0 :   return true;
    1295             : }
    1296             : 
    1297             : void
    1298           0 : nsXMLContentSerializer::MaybeFlagNewlineForRootNode(nsINode* aNode)
    1299             : {
    1300           0 :   nsINode* parent = aNode->GetParentNode();
    1301           0 :   if (parent) {
    1302           0 :     mAddNewlineForRootNode = parent->IsNodeOfType(nsINode::eDOCUMENT);
    1303             :   }
    1304           0 : }
    1305             : 
    1306             : void
    1307           0 : nsXMLContentSerializer::MaybeEnterInPreContent(nsIContent* aNode)
    1308             : {
    1309             :   // support of the xml:space attribute
    1310           0 :   if (ShouldMaintainPreLevel() &&
    1311           0 :       aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
    1312           0 :     nsAutoString space;
    1313           0 :     aNode->GetAttr(kNameSpaceID_XML, nsGkAtoms::space, space);
    1314           0 :     if (space.EqualsLiteral("preserve"))
    1315           0 :       ++PreLevel();
    1316             :   }
    1317           0 : }
    1318             : 
    1319             : void
    1320           0 : nsXMLContentSerializer::MaybeLeaveFromPreContent(nsIContent* aNode)
    1321             : {
    1322             :   // support of the xml:space attribute
    1323           0 :   if (ShouldMaintainPreLevel() &&
    1324           0 :       aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
    1325           0 :     nsAutoString space;
    1326           0 :     aNode->GetAttr(kNameSpaceID_XML, nsGkAtoms::space, space);
    1327           0 :     if (space.EqualsLiteral("preserve"))
    1328           0 :       --PreLevel();
    1329             :   }
    1330           0 : }
    1331             : 
    1332             : bool
    1333           0 : nsXMLContentSerializer::AppendNewLineToString(nsAString& aStr)
    1334             : {
    1335           0 :   bool result = AppendToString(mLineBreak, aStr);
    1336           0 :   mMayIgnoreLineBreakSequence = true;
    1337           0 :   mColPos = 0;
    1338           0 :   mAddSpace = false;
    1339           0 :   mIsIndentationAddedOnCurrentLine = false;
    1340           0 :   return result;
    1341             : }
    1342             : 
    1343             : bool
    1344           0 : nsXMLContentSerializer::AppendIndentation(nsAString& aStr)
    1345             : {
    1346           0 :   mIsIndentationAddedOnCurrentLine = true;
    1347           0 :   bool result = AppendToString(mIndent, aStr);
    1348           0 :   mAddSpace = false;
    1349           0 :   mMayIgnoreLineBreakSequence = false;
    1350           0 :   return result;
    1351             : }
    1352             : 
    1353             : bool
    1354           0 : nsXMLContentSerializer::IncrIndentation(nsIAtom* aName)
    1355             : {
    1356             :   // we want to keep the source readable
    1357           0 :   if (mDoWrap &&
    1358           0 :       mIndent.Length() >= uint32_t(mMaxColumn) - MIN_INDENTED_LINE_LENGTH) {
    1359           0 :     ++mIndentOverflow;
    1360             :   }
    1361             :   else {
    1362           0 :     return mIndent.AppendLiteral(INDENT_STRING, mozilla::fallible);
    1363             :   }
    1364             : 
    1365           0 :   return true;
    1366             : }
    1367             : 
    1368             : void
    1369           0 : nsXMLContentSerializer::DecrIndentation(nsIAtom* aName)
    1370             : {
    1371           0 :   if(mIndentOverflow)
    1372           0 :     --mIndentOverflow;
    1373             :   else
    1374           0 :     mIndent.Cut(0, INDENT_STRING_LENGTH);
    1375           0 : }
    1376             : 
    1377             : bool
    1378           0 : nsXMLContentSerializer::LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName)
    1379             : {
    1380           0 :   return mAddSpace;
    1381             : }
    1382             : 
    1383             : bool
    1384           0 : nsXMLContentSerializer::LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName)
    1385             : {
    1386           0 :   return false;
    1387             : }
    1388             : 
    1389             : bool
    1390           0 : nsXMLContentSerializer::LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName)
    1391             : {
    1392           0 :   return mAddSpace;
    1393             : }
    1394             : 
    1395             : bool
    1396           0 : nsXMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName)
    1397             : {
    1398           0 :   return false;
    1399             : }
    1400             : 
    1401             : bool
    1402           0 : nsXMLContentSerializer::AppendToStringConvertLF(const nsAString& aStr,
    1403             :                                                 nsAString& aOutputStr)
    1404             : {
    1405           0 :   if (mBodyOnly && !mInBody) {
    1406           0 :     return true;
    1407             :   }
    1408             : 
    1409           0 :   if (mDoRaw) {
    1410           0 :     NS_ENSURE_TRUE(AppendToString(aStr, aOutputStr), false);
    1411             :   }
    1412             :   else {
    1413             :     // Convert line-endings to mLineBreak
    1414           0 :     uint32_t start = 0;
    1415           0 :     uint32_t theLen = aStr.Length();
    1416           0 :     while (start < theLen) {
    1417           0 :       int32_t eol = aStr.FindChar('\n', start);
    1418           0 :       if (eol == kNotFound) {
    1419           0 :         nsDependentSubstring dataSubstring(aStr, start, theLen - start);
    1420           0 :         NS_ENSURE_TRUE(AppendToString(dataSubstring, aOutputStr), false);
    1421           0 :         start = theLen;
    1422             :         // if there was a line break before this substring
    1423             :         // AppendNewLineToString was called, so we should reverse
    1424             :         // this flag
    1425           0 :         mMayIgnoreLineBreakSequence = false;
    1426             :       }
    1427             :       else {
    1428           0 :         nsDependentSubstring dataSubstring(aStr, start, eol - start);
    1429           0 :         NS_ENSURE_TRUE(AppendToString(dataSubstring, aOutputStr), false);
    1430           0 :         NS_ENSURE_TRUE(AppendNewLineToString(aOutputStr), false);
    1431           0 :         start = eol + 1;
    1432             :       }
    1433             :     }
    1434             :   }
    1435             : 
    1436           0 :   return true;
    1437             : }
    1438             : 
    1439             : bool
    1440           0 : nsXMLContentSerializer::AppendFormatedWrapped_WhitespaceSequence(
    1441             :                         nsAString::const_char_iterator &aPos,
    1442             :                         const nsAString::const_char_iterator aEnd,
    1443             :                         const nsAString::const_char_iterator aSequenceStart,
    1444             :                         bool &aMayIgnoreStartOfLineWhitespaceSequence,
    1445             :                         nsAString &aOutputStr)
    1446             : {
    1447             :   // Handle the complete sequence of whitespace.
    1448             :   // Continue to iterate until we find the first non-whitespace char.
    1449             :   // Updates "aPos" to point to the first unhandled char.
    1450             :   // Also updates the aMayIgnoreStartOfLineWhitespaceSequence flag,
    1451             :   // as well as the other "global" state flags.
    1452             : 
    1453           0 :   bool sawBlankOrTab = false;
    1454           0 :   bool leaveLoop = false;
    1455             : 
    1456           0 :   do {
    1457           0 :     switch (*aPos) {
    1458             :       case ' ':
    1459             :       case '\t':
    1460           0 :         sawBlankOrTab = true;
    1461             :         MOZ_FALLTHROUGH;
    1462             :       case '\n':
    1463           0 :         ++aPos;
    1464             :         // do not increase mColPos,
    1465             :         // because we will reduce the whitespace to a single char
    1466           0 :         break;
    1467             :       default:
    1468           0 :         leaveLoop = true;
    1469           0 :         break;
    1470             :     }
    1471           0 :   } while (!leaveLoop && aPos < aEnd);
    1472             : 
    1473           0 :   if (mAddSpace) {
    1474             :     // if we had previously been asked to add space,
    1475             :     // our situation has not changed
    1476             :   }
    1477           0 :   else if (!sawBlankOrTab && mMayIgnoreLineBreakSequence) {
    1478             :     // nothing to do in the case where line breaks have already been added
    1479             :     // before the call of AppendToStringWrapped
    1480             :     // and only if we found line break in the sequence
    1481           0 :     mMayIgnoreLineBreakSequence = false;
    1482             :   }
    1483           0 :   else if (aMayIgnoreStartOfLineWhitespaceSequence) {
    1484             :     // nothing to do
    1485           0 :     aMayIgnoreStartOfLineWhitespaceSequence = false;
    1486             :   }
    1487             :   else {
    1488           0 :     if (sawBlankOrTab) {
    1489           0 :       if (mDoWrap && mColPos + 1 >= mMaxColumn) {
    1490             :         // no much sense in delaying, we only have one slot left,
    1491             :         // let's write a break now
    1492           0 :         bool result = aOutputStr.Append(mLineBreak, mozilla::fallible);
    1493           0 :         mColPos = 0;
    1494           0 :         mIsIndentationAddedOnCurrentLine = false;
    1495           0 :         mMayIgnoreLineBreakSequence = true;
    1496           0 :         NS_ENSURE_TRUE(result, false);
    1497             :       }
    1498             :       else {
    1499             :         // do not write out yet, we may write out either a space or a linebreak
    1500             :         // let's delay writing it out until we know more
    1501           0 :         mAddSpace = true;
    1502           0 :         ++mColPos; // eat a slot of available space
    1503             :       }
    1504             :     }
    1505             :     else {
    1506             :       // Asian text usually does not contain spaces, therefore we should not
    1507             :       // transform a linebreak into a space.
    1508             :       // Since we only saw linebreaks, but no spaces or tabs,
    1509             :       // let's write a linebreak now.
    1510           0 :       NS_ENSURE_TRUE(AppendNewLineToString(aOutputStr), false);
    1511             :     }
    1512             :   }
    1513             : 
    1514           0 :   return true;
    1515             : }
    1516             : 
    1517             : bool
    1518           0 : nsXMLContentSerializer::AppendWrapped_NonWhitespaceSequence(
    1519             :                         nsAString::const_char_iterator &aPos,
    1520             :                         const nsAString::const_char_iterator aEnd,
    1521             :                         const nsAString::const_char_iterator aSequenceStart,
    1522             :                         bool &aMayIgnoreStartOfLineWhitespaceSequence,
    1523             :                         bool &aSequenceStartAfterAWhiteSpace,
    1524             :                         nsAString& aOutputStr)
    1525             : {
    1526           0 :   mMayIgnoreLineBreakSequence = false;
    1527           0 :   aMayIgnoreStartOfLineWhitespaceSequence = false;
    1528             : 
    1529             :   // Handle the complete sequence of non-whitespace in this block
    1530             :   // Iterate until we find the first whitespace char or an aEnd condition
    1531             :   // Updates "aPos" to point to the first unhandled char.
    1532             :   // Also updates the aMayIgnoreStartOfLineWhitespaceSequence flag,
    1533             :   // as well as the other "global" state flags.
    1534             : 
    1535           0 :   bool thisSequenceStartsAtBeginningOfLine = !mColPos;
    1536           0 :   bool onceAgainBecauseWeAddedBreakInFront = false;
    1537             :   bool foundWhitespaceInLoop;
    1538             :   uint32_t length, colPos;
    1539             : 
    1540           0 :   do {
    1541             : 
    1542           0 :     if (mColPos) {
    1543           0 :       colPos = mColPos;
    1544             :     }
    1545             :     else {
    1546           0 :       if (mDoFormat && !mDoRaw && !PreLevel() && !onceAgainBecauseWeAddedBreakInFront) {
    1547           0 :         colPos = mIndent.Length();
    1548             :       }
    1549             :       else
    1550           0 :         colPos = 0;
    1551             :     }
    1552           0 :     foundWhitespaceInLoop = false;
    1553           0 :     length = 0;
    1554             :     // we iterate until the next whitespace character
    1555             :     // or until we reach the maximum of character per line
    1556             :     // or until the end of the string to add.
    1557           0 :     do {
    1558           0 :       if (*aPos == ' ' || *aPos == '\t' || *aPos == '\n') {
    1559           0 :         foundWhitespaceInLoop = true;
    1560           0 :         break;
    1561             :       }
    1562             : 
    1563           0 :       ++aPos;
    1564           0 :       ++length;
    1565           0 :     } while ( (!mDoWrap || colPos + length < mMaxColumn) && aPos < aEnd);
    1566             : 
    1567             :     // in the case we don't reached the end of the string, but we reached the maxcolumn,
    1568             :     // we see if there is a whitespace after the maxcolumn
    1569             :     // if yes, then we can append directly the string instead of
    1570             :     // appending a new line etc.
    1571           0 :     if (*aPos == ' ' || *aPos == '\t' || *aPos == '\n') {
    1572           0 :       foundWhitespaceInLoop = true;
    1573             :     }
    1574             : 
    1575           0 :     if (aPos == aEnd || foundWhitespaceInLoop) {
    1576             :       // there is enough room for the complete block we found
    1577           0 :       if (mDoFormat && !mColPos) {
    1578           0 :         NS_ENSURE_TRUE(AppendIndentation(aOutputStr), false);
    1579             :       }
    1580           0 :       else if (mAddSpace) {
    1581           0 :         bool result = aOutputStr.Append(char16_t(' '), mozilla::fallible);
    1582           0 :         mAddSpace = false;
    1583           0 :         NS_ENSURE_TRUE(result, false);
    1584             :       }
    1585             : 
    1586           0 :       mColPos += length;
    1587           0 :       NS_ENSURE_TRUE(aOutputStr.Append(aSequenceStart, aPos - aSequenceStart, mozilla::fallible), false);
    1588             : 
    1589             :       // We have not yet reached the max column, we will continue to
    1590             :       // fill the current line in the next outer loop iteration
    1591             :       // (this one in AppendToStringWrapped)
    1592             :       // make sure we return in this outer loop
    1593           0 :       onceAgainBecauseWeAddedBreakInFront = false;
    1594             :     }
    1595             :     else { // we reach the max column
    1596           0 :       if (!thisSequenceStartsAtBeginningOfLine &&
    1597           0 :           (mAddSpace || (!mDoFormat && aSequenceStartAfterAWhiteSpace))) {
    1598             :           // when !mDoFormat, mAddSpace is not used, mAddSpace is always false
    1599             :           // so, in the case where mDoWrap && !mDoFormat, if we want to enter in this condition...
    1600             : 
    1601             :         // We can avoid to wrap. We try to add the whole block
    1602             :         // in an empty new line
    1603             : 
    1604           0 :         NS_ENSURE_TRUE(AppendNewLineToString(aOutputStr), false);
    1605           0 :         aPos = aSequenceStart;
    1606           0 :         thisSequenceStartsAtBeginningOfLine = true;
    1607           0 :         onceAgainBecauseWeAddedBreakInFront = true;
    1608             :       }
    1609             :       else {
    1610             :         // we must wrap
    1611           0 :         onceAgainBecauseWeAddedBreakInFront = false;
    1612           0 :         bool foundWrapPosition = false;
    1613           0 :         int32_t wrapPosition = 0;
    1614             : 
    1615           0 :         if (mAllowLineBreaking) {
    1616           0 :           nsILineBreaker *lineBreaker = nsContentUtils::LineBreaker();
    1617             : 
    1618           0 :           wrapPosition = lineBreaker->Prev(aSequenceStart,
    1619           0 :                                            (aEnd - aSequenceStart),
    1620           0 :                                            (aPos - aSequenceStart) + 1);
    1621           0 :           if (wrapPosition != NS_LINEBREAKER_NEED_MORE_TEXT) {
    1622           0 :             foundWrapPosition = true;
    1623             :           }
    1624             :           else {
    1625           0 :             wrapPosition = lineBreaker->Next(aSequenceStart,
    1626           0 :                                              (aEnd - aSequenceStart),
    1627           0 :                                              (aPos - aSequenceStart));
    1628           0 :             if (wrapPosition != NS_LINEBREAKER_NEED_MORE_TEXT) {
    1629           0 :               foundWrapPosition = true;
    1630             :             }
    1631             :           }
    1632             :         }
    1633             : 
    1634           0 :         if (foundWrapPosition) {
    1635           0 :           if (!mColPos && mDoFormat) {
    1636           0 :             NS_ENSURE_TRUE(AppendIndentation(aOutputStr), false);
    1637             :           }
    1638           0 :           else if (mAddSpace) {
    1639           0 :             bool result = aOutputStr.Append(char16_t(' '), mozilla::fallible);
    1640           0 :             mAddSpace = false;
    1641           0 :             NS_ENSURE_TRUE(result, false);
    1642             :           }
    1643           0 :           NS_ENSURE_TRUE(aOutputStr.Append(aSequenceStart, wrapPosition, mozilla::fallible), false);
    1644             : 
    1645           0 :           NS_ENSURE_TRUE(AppendNewLineToString(aOutputStr), false);
    1646           0 :           aPos = aSequenceStart + wrapPosition;
    1647           0 :           aMayIgnoreStartOfLineWhitespaceSequence = true;
    1648             :         }
    1649             :         else {
    1650             :           // try some simple fallback logic
    1651             :           // go forward up to the next whitespace position,
    1652             :           // in the worst case this will be all the rest of the data
    1653             : 
    1654             :           // we update the mColPos variable with the length of
    1655             :           // the part already parsed.
    1656           0 :           mColPos += length;
    1657             : 
    1658             :           // now try to find the next whitespace
    1659           0 :           do {
    1660           0 :             if (*aPos == ' ' || *aPos == '\t' || *aPos == '\n') {
    1661             :               break;
    1662             :             }
    1663             : 
    1664           0 :             ++aPos;
    1665           0 :             ++mColPos;
    1666           0 :           } while (aPos < aEnd);
    1667             : 
    1668           0 :           if (mAddSpace) {
    1669           0 :             bool result = aOutputStr.Append(char16_t(' '), mozilla::fallible);
    1670           0 :             mAddSpace = false;
    1671           0 :             NS_ENSURE_TRUE(result, false);
    1672             :           }
    1673           0 :           NS_ENSURE_TRUE(aOutputStr.Append(aSequenceStart, aPos - aSequenceStart, mozilla::fallible), false);
    1674             :         }
    1675             :       }
    1676           0 :       aSequenceStartAfterAWhiteSpace = false;
    1677             :     }
    1678             :   } while (onceAgainBecauseWeAddedBreakInFront);
    1679             : 
    1680           0 :   return true;
    1681             : }
    1682             : 
    1683             : bool
    1684           0 : nsXMLContentSerializer::AppendToStringFormatedWrapped(const nsAString& aStr,
    1685             :                                                       nsAString& aOutputStr)
    1686             : {
    1687           0 :   if (mBodyOnly && !mInBody) {
    1688           0 :     return true;
    1689             :   }
    1690             : 
    1691             :   nsAString::const_char_iterator pos, end, sequenceStart;
    1692             : 
    1693           0 :   aStr.BeginReading(pos);
    1694           0 :   aStr.EndReading(end);
    1695             : 
    1696           0 :   bool sequenceStartAfterAWhitespace = false;
    1697           0 :   if (pos < end) {
    1698             :     nsAString::const_char_iterator end2;
    1699           0 :     aOutputStr.EndReading(end2);
    1700           0 :     --end2;
    1701           0 :     if (*end2 == ' ' || *end2 == '\n' || *end2 == '\t') {
    1702           0 :       sequenceStartAfterAWhitespace = true;
    1703             :     }
    1704             :   }
    1705             : 
    1706             :   // if the current line already has text on it, such as a tag,
    1707             :   // leading whitespace is significant
    1708             :   bool mayIgnoreStartOfLineWhitespaceSequence =
    1709           0 :     (!mColPos || (mIsIndentationAddedOnCurrentLine &&
    1710           0 :                   sequenceStartAfterAWhitespace &&
    1711           0 :                   uint32_t(mColPos) == mIndent.Length()));
    1712             : 
    1713           0 :   while (pos < end) {
    1714           0 :     sequenceStart = pos;
    1715             : 
    1716             :     // if beginning of a whitespace sequence
    1717           0 :     if (*pos == ' ' || *pos == '\n' || *pos == '\t') {
    1718           0 :       NS_ENSURE_TRUE(AppendFormatedWrapped_WhitespaceSequence(pos, end, sequenceStart,
    1719             :         mayIgnoreStartOfLineWhitespaceSequence, aOutputStr), false);
    1720             :     }
    1721             :     else { // any other non-whitespace char
    1722           0 :       NS_ENSURE_TRUE(AppendWrapped_NonWhitespaceSequence(pos, end, sequenceStart,
    1723             :         mayIgnoreStartOfLineWhitespaceSequence, sequenceStartAfterAWhitespace,
    1724             :         aOutputStr), false);
    1725             :     }
    1726             :   }
    1727             : 
    1728           0 :   return true;
    1729             : }
    1730             : 
    1731             : bool
    1732           0 : nsXMLContentSerializer::AppendWrapped_WhitespaceSequence(
    1733             :                         nsAString::const_char_iterator &aPos,
    1734             :                         const nsAString::const_char_iterator aEnd,
    1735             :                         const nsAString::const_char_iterator aSequenceStart,
    1736             :                         nsAString &aOutputStr)
    1737             : {
    1738             :   // Handle the complete sequence of whitespace.
    1739             :   // Continue to iterate until we find the first non-whitespace char.
    1740             :   // Updates "aPos" to point to the first unhandled char.
    1741           0 :   mAddSpace = false;
    1742           0 :   mIsIndentationAddedOnCurrentLine = false;
    1743             : 
    1744           0 :   bool leaveLoop = false;
    1745           0 :   nsAString::const_char_iterator lastPos = aPos;
    1746             : 
    1747           0 :   do {
    1748           0 :     switch (*aPos) {
    1749             :       case ' ':
    1750             :       case '\t':
    1751             :         // if there are too many spaces on a line, we wrap
    1752           0 :         if (mColPos >= mMaxColumn) {
    1753           0 :           if (lastPos != aPos) {
    1754           0 :             NS_ENSURE_TRUE(aOutputStr.Append(lastPos, aPos - lastPos, mozilla::fallible), false);
    1755             :           }
    1756           0 :           NS_ENSURE_TRUE(AppendToString(mLineBreak, aOutputStr), false);
    1757           0 :           mColPos = 0;
    1758           0 :           lastPos = aPos;
    1759             :         }
    1760             : 
    1761           0 :         ++mColPos;
    1762           0 :         ++aPos;
    1763           0 :         break;
    1764             :       case '\n':
    1765           0 :         if (lastPos != aPos) {
    1766           0 :           NS_ENSURE_TRUE(aOutputStr.Append(lastPos, aPos - lastPos, mozilla::fallible), false);
    1767             :         }
    1768           0 :         NS_ENSURE_TRUE(AppendToString(mLineBreak, aOutputStr), false);
    1769           0 :         mColPos = 0;
    1770           0 :         ++aPos;
    1771           0 :         lastPos = aPos;
    1772           0 :         break;
    1773             :       default:
    1774           0 :         leaveLoop = true;
    1775           0 :         break;
    1776             :     }
    1777           0 :   } while (!leaveLoop && aPos < aEnd);
    1778             : 
    1779           0 :   if (lastPos != aPos) {
    1780           0 :     NS_ENSURE_TRUE(aOutputStr.Append(lastPos, aPos - lastPos, mozilla::fallible), false);
    1781             :   }
    1782             : 
    1783           0 :   return true;
    1784             : }
    1785             : 
    1786             : bool
    1787           0 : nsXMLContentSerializer::AppendToStringWrapped(const nsAString& aStr,
    1788             :                                               nsAString& aOutputStr)
    1789             : {
    1790           0 :   if (mBodyOnly && !mInBody) {
    1791           0 :     return true;
    1792             :   }
    1793             : 
    1794             :   nsAString::const_char_iterator pos, end, sequenceStart;
    1795             : 
    1796           0 :   aStr.BeginReading(pos);
    1797           0 :   aStr.EndReading(end);
    1798             : 
    1799             :   // not used in this case, but needed by AppendWrapped_NonWhitespaceSequence
    1800           0 :   bool mayIgnoreStartOfLineWhitespaceSequence = false;
    1801           0 :   mMayIgnoreLineBreakSequence = false;
    1802             : 
    1803           0 :   bool sequenceStartAfterAWhitespace = false;
    1804           0 :   if (pos < end && !aOutputStr.IsEmpty()) {
    1805             :     nsAString::const_char_iterator end2;
    1806           0 :     aOutputStr.EndReading(end2);
    1807           0 :     --end2;
    1808           0 :     if (*end2 == ' ' || *end2 == '\n' || *end2 == '\t') {
    1809           0 :       sequenceStartAfterAWhitespace = true;
    1810             :     }
    1811             :   }
    1812             : 
    1813           0 :   while (pos < end) {
    1814           0 :     sequenceStart = pos;
    1815             : 
    1816             :     // if beginning of a whitespace sequence
    1817           0 :     if (*pos == ' ' || *pos == '\n' || *pos == '\t') {
    1818           0 :       sequenceStartAfterAWhitespace = true;
    1819           0 :       NS_ENSURE_TRUE(AppendWrapped_WhitespaceSequence(pos, end,
    1820             :         sequenceStart, aOutputStr), false);
    1821             :     }
    1822             :     else { // any other non-whitespace char
    1823           0 :       NS_ENSURE_TRUE(AppendWrapped_NonWhitespaceSequence(pos, end, sequenceStart,
    1824             :         mayIgnoreStartOfLineWhitespaceSequence,
    1825             :         sequenceStartAfterAWhitespace, aOutputStr), false);
    1826             :     }
    1827             :   }
    1828             : 
    1829           0 :   return true;
    1830             : }
    1831             : 
    1832             : bool
    1833           0 : nsXMLContentSerializer::ShouldMaintainPreLevel() const
    1834             : {
    1835             :   // Only attempt to maintain the pre level for consumers who care about it.
    1836           0 :   return !mDoRaw || (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre);
    1837             : }

Generated by: LCOV version 1.13