LCOV - code coverage report
Current view: directory - content/base/src - nsXMLContentSerializer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 764 641 83.9 %
Date: 2012-06-02 Functions: 49 48 98.0 %

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

Generated by: LCOV version 1.7