LCOV - app.info - content/base/src/nsXMLContentSerializer.cpp

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-07-07 | 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