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

LCOV - code coverage report
| Current view: | directory - content/base/src - nsDocumentEncoder.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 876 | 211 | 24.1 %
| Date: | 2012-07-07 | Functions: | 67 | 25 | 37.3 %

           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                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
          24                 :  *   Mats Palmgren <matpal@gmail.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : /*
          41                 :  * Object that can be used to serialize selections, ranges, or nodes
          42                 :  * to strings in a gazillion different ways.
          43                 :  */
          44                 :
          45                 : #include "nsIDocumentEncoder.h"
          46                 :
          47                 : #include "nscore.h"
          48                 : #include "nsIFactory.h"
          49                 : #include "nsISupports.h"
          50                 : #include "nsIComponentManager.h"
          51                 : #include "nsIServiceManager.h"
          52                 : #include "nsIDocument.h"
          53                 : #include "nsIHTMLDocument.h"
          54                 : #include "nsCOMPtr.h"
          55                 : #include "nsIContentSerializer.h"
          56                 : #include "nsIUnicodeEncoder.h"
          57                 : #include "nsIOutputStream.h"
          58                 : #include "nsIDOMElement.h"
          59                 : #include "nsIDOMText.h"
          60                 : #include "nsIDOMCDATASection.h"
          61                 : #include "nsIDOMComment.h"
          62                 : #include "nsIDOMProcessingInstruction.h"
          63                 : #include "nsIDOMDocumentType.h"
          64                 : #include "nsIDOMNodeList.h"
          65                 : #include "nsRange.h"
          66                 : #include "nsIDOMRange.h"
          67                 : #include "nsIDOMDocument.h"
          68                 : #include "nsICharsetConverterManager.h"
          69                 : #include "nsGkAtoms.h"
          70                 : #include "nsIContent.h"
          71                 : #include "nsIEnumerator.h"
          72                 : #include "nsIParserService.h"
          73                 : #include "nsIScriptContext.h"
          74                 : #include "nsIScriptGlobalObject.h"
          75                 : #include "nsIScriptSecurityManager.h"
          76                 : #include "nsISelection.h"
          77                 : #include "nsISelectionPrivate.h"
          78                 : #include "nsITransferable.h" // for kUnicodeMime
          79                 : #include "nsContentUtils.h"
          80                 : #include "nsUnicharUtils.h"
          81                 : #include "nsReadableUtils.h"
          82                 : #include "nsTArray.h"
          83                 : #include "nsIFrame.h"
          84                 : #include "nsStringBuffer.h"
          85                 : #include "mozilla/dom/Element.h"
          86                 : #include "nsIEditorDocShell.h"
          87                 : #include "nsIEditor.h"
          88                 : #include "nsIHTMLEditor.h"
          89                 : #include "nsIDocShell.h"
          90                 :
          91                 : using namespace mozilla;
          92                 : using namespace mozilla::dom;
          93                 :
          94                 : nsresult NS_NewDomSelection(nsISelection **aDomSelection);
          95                 :
          96                 : enum nsRangeIterationDirection {
          97                 :   kDirectionOut = -1,
          98                 :   kDirectionIn = 1
          99                 : };
         100                 :
         101                 : class nsDocumentEncoder : public nsIDocumentEncoder
         102                 : {
         103                 : public:
         104                 :   nsDocumentEncoder();
         105                 :   virtual ~nsDocumentEncoder();
         106                 :
         107               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
         108            5098 :   NS_DECL_CYCLE_COLLECTION_CLASS(nsDocumentEncoder)
         109                 :   NS_DECL_NSIDOCUMENTENCODER
         110                 :
         111                 : protected:
         112                 :   void Initialize(bool aClearCachedSerializer = true);
         113                 :   nsresult SerializeNodeStart(nsINode* aNode, PRInt32 aStartOffset,
         114                 :                               PRInt32 aEndOffset, nsAString& aStr,
         115                 :                               nsINode* aOriginalNode = nsnull);
         116                 :   nsresult SerializeToStringRecursive(nsINode* aNode,
         117                 :                                       nsAString& aStr,
         118                 :                                       bool aDontSerializeRoot);
         119                 :   nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr);
         120                 :   // This serializes the content of aNode.
         121                 :   nsresult SerializeToStringIterative(nsINode* aNode,
         122                 :                                       nsAString& aStr);
         123                 :   nsresult SerializeRangeToString(nsRange *aRange,
         124                 :                                   nsAString& aOutputString);
         125                 :   nsresult SerializeRangeNodes(nsRange* aRange,
         126                 :                                nsINode* aNode,
         127                 :                                nsAString& aString,
         128                 :                                PRInt32 aDepth);
         129                 :   nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
         130                 :                                       nsAString& aString);
         131                 :   nsresult SerializeRangeContextEnd(const nsTArray<nsINode*>& aAncestorArray,
         132                 :                                     nsAString& aString);
         133                 :
         134                 :   nsresult FlushText(nsAString& aString, bool aForce);
         135                 :
         136            6480 :   bool IsVisibleNode(nsINode* aNode)
         137                 :   {
         138            6480 :     NS_PRECONDITION(aNode, "");
         139                 :
         140            6480 :     if (mFlags & SkipInvisibleContent) {
         141               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
         142               0 :       if (content) {
         143               0 :         nsIFrame* frame = content->GetPrimaryFrame();
         144               0 :         if (!frame) {
         145               0 :           if (aNode->IsNodeOfType(nsINode::eTEXT)) {
         146                 :             // We have already checked that our parent is visible.
         147               0 :             return true;
         148                 :           }
         149               0 :           return false;
         150                 :         }
         151               0 :         bool isVisible = frame->GetStyleVisibility()->IsVisible();
         152               0 :         if (!isVisible && aNode->IsNodeOfType(nsINode::eTEXT))
         153               0 :           return false;
         154                 :       }
         155                 :     }
         156            6480 :     return true;
         157                 :   }
         158                 :
         159                 :   static bool IsTag(nsIContent* aContent, nsIAtom* aAtom);
         160                 :
         161                 :   virtual bool IncludeInContext(nsINode *aNode);
         162                 :
         163                 :   nsCOMPtr<nsIDocument>          mDocument;
         164                 :   nsCOMPtr<nsISelection>         mSelection;
         165                 :   nsRefPtr<nsRange>              mRange;
         166                 :   nsCOMPtr<nsINode>              mNode;
         167                 :   nsCOMPtr<nsIOutputStream>      mStream;
         168                 :   nsCOMPtr<nsIContentSerializer> mSerializer;
         169                 :   nsCOMPtr<nsIUnicodeEncoder>    mUnicodeEncoder;
         170                 :   nsCOMPtr<nsINode>              mCommonParent;
         171                 :   nsCOMPtr<nsIDocumentEncoderNodeFixup> mNodeFixup;
         172                 :   nsCOMPtr<nsICharsetConverterManager> mCharsetConverterManager;
         173                 :
         174                 :   nsString          mMimeType;
         175                 :   nsCString         mCharset;
         176                 :   PRUint32          mFlags;
         177                 :   PRUint32          mWrapColumn;
         178                 :   PRUint32          mStartDepth;
         179                 :   PRUint32          mEndDepth;
         180                 :   PRInt32           mStartRootIndex;
         181                 :   PRInt32           mEndRootIndex;
         182                 :   nsAutoTArray<nsINode*, 8>    mCommonAncestors;
         183                 :   nsAutoTArray<nsIContent*, 8> mStartNodes;
         184                 :   nsAutoTArray<PRInt32, 8>     mStartOffsets;
         185                 :   nsAutoTArray<nsIContent*, 8> mEndNodes;
         186                 :   nsAutoTArray<PRInt32, 8>     mEndOffsets;
         187                 :   bool              mHaltRangeHint;
         188                 :   bool              mIsCopying;  // Set to true only while copying
         189                 :   bool              mNodeIsContainer;
         190                 :   nsStringBuffer*   mCachedBuffer;
         191                 : };
         192                 :
         193            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocumentEncoder)
         194                 :
         195            1817 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocumentEncoder)
         196            1817 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDocumentEncoder)
         197                 :
         198            2551 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocumentEncoder)
         199            1203 :    NS_INTERFACE_MAP_ENTRY(nsIDocumentEncoder)
         200              70 :    NS_INTERFACE_MAP_ENTRY(nsISupports)
         201              60 : NS_INTERFACE_MAP_END
         202                 :
         203               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocumentEncoder)
         204               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
         205               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSelection)
         206               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRange)
         207               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNode)
         208               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCommonParent)
         209               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
         210                 :
         211               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocumentEncoder)
         212               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
         213               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSelection)
         214               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRange, nsIDOMRange)
         215               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNode)
         216               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCommonParent)
         217               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
         218                 :
         219             459 : nsDocumentEncoder::nsDocumentEncoder() : mCachedBuffer(nsnull)
         220                 : {
         221             459 :   Initialize();
         222             459 :   mMimeType.AssignLiteral("text/plain");
         223                 :
         224             459 : }
         225                 :
         226             920 : void nsDocumentEncoder::Initialize(bool aClearCachedSerializer)
         227                 : {
         228             920 :   mFlags = 0;
         229             920 :   mWrapColumn = 72;
         230             920 :   mStartDepth = 0;
         231             920 :   mEndDepth = 0;
         232             920 :   mStartRootIndex = 0;
         233             920 :   mEndRootIndex = 0;
         234             920 :   mHaltRangeHint = false;
         235             920 :   mNodeIsContainer = false;
         236             920 :   if (aClearCachedSerializer) {
         237             684 :     mSerializer = nsnull;
         238                 :   }
         239             920 : }
         240                 :
         241            1377 : nsDocumentEncoder::~nsDocumentEncoder()
         242                 : {
         243             459 :   if (mCachedBuffer) {
         244             446 :     mCachedBuffer->Release();
         245                 :   }
         246            1836 : }
         247                 :
         248                 : NS_IMETHODIMP
         249             461 : nsDocumentEncoder::Init(nsIDOMDocument* aDocument,
         250                 :                         const nsAString& aMimeType,
         251                 :                         PRUint32 aFlags)
         252                 : {
         253             461 :   if (!aDocument)
         254               0 :     return NS_ERROR_INVALID_ARG;
         255                 :
         256             922 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
         257             461 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
         258                 :
         259             461 :   return NativeInit(doc, aMimeType, aFlags);
         260                 : }
         261                 :
         262                 : NS_IMETHODIMP
         263             461 : nsDocumentEncoder::NativeInit(nsIDocument* aDocument,
         264                 :                               const nsAString& aMimeType,
         265                 :                               PRUint32 aFlags)
         266                 : {
         267             461 :   if (!aDocument)
         268               0 :     return NS_ERROR_INVALID_ARG;
         269                 :
         270             461 :   Initialize(!mMimeType.Equals(aMimeType));
         271                 :
         272             461 :   mDocument = aDocument;
         273                 :
         274             461 :   mMimeType = aMimeType;
         275                 :
         276             461 :   mFlags = aFlags;
         277             461 :   mIsCopying = false;
         278                 :
         279             461 :   return NS_OK;
         280                 : }
         281                 :
         282                 : NS_IMETHODIMP
         283             236 : nsDocumentEncoder::SetWrapColumn(PRUint32 aWC)
         284                 : {
         285             236 :   mWrapColumn = aWC;
         286             236 :   return NS_OK;
         287                 : }
         288                 :
         289                 : NS_IMETHODIMP
         290               0 : nsDocumentEncoder::SetSelection(nsISelection* aSelection)
         291                 : {
         292               0 :   mSelection = aSelection;
         293               0 :   return NS_OK;
         294                 : }
         295                 :
         296                 : NS_IMETHODIMP
         297               0 : nsDocumentEncoder::SetRange(nsIDOMRange* aRange)
         298                 : {
         299               0 :   mRange = static_cast<nsRange*>(aRange);
         300               0 :   return NS_OK;
         301                 : }
         302                 :
         303                 : NS_IMETHODIMP
         304             155 : nsDocumentEncoder::SetNode(nsIDOMNode* aNode)
         305                 : {
         306             155 :   mNodeIsContainer = false;
         307             155 :   mNode = do_QueryInterface(aNode);
         308             155 :   return NS_OK;
         309                 : }
         310                 :
         311                 : NS_IMETHODIMP
         312               0 : nsDocumentEncoder::SetNativeNode(nsINode* aNode)
         313                 : {
         314               0 :   mNodeIsContainer = false;
         315               0 :   mNode = aNode;
         316               0 :   return NS_OK;
         317                 : }
         318                 :
         319                 : NS_IMETHODIMP
         320               0 : nsDocumentEncoder::SetContainerNode(nsIDOMNode *aContainer)
         321                 : {
         322               0 :   mNodeIsContainer = true;
         323               0 :   mNode = do_QueryInterface(aContainer);
         324               0 :   return NS_OK;
         325                 : }
         326                 :
         327                 : NS_IMETHODIMP
         328               0 : nsDocumentEncoder::SetNativeContainerNode(nsINode* aContainer)
         329                 : {
         330               0 :   mNodeIsContainer = true;
         331               0 :   mNode = aContainer;
         332               0 :   return NS_OK;
         333                 : }
         334                 :
         335                 : NS_IMETHODIMP
         336             226 : nsDocumentEncoder::SetCharset(const nsACString& aCharset)
         337                 : {
         338             226 :   mCharset = aCharset;
         339             226 :   return NS_OK;
         340                 : }
         341                 :
         342                 : NS_IMETHODIMP
         343               0 : nsDocumentEncoder::GetMimeType(nsAString& aMimeType)
         344                 : {
         345               0 :   aMimeType = mMimeType;
         346               0 :   return NS_OK;
         347                 : }
         348                 :
         349                 :
         350                 : bool
         351               0 : nsDocumentEncoder::IncludeInContext(nsINode *aNode)
         352                 : {
         353               0 :   return false;
         354                 : }
         355                 :
         356                 : static
         357                 : bool
         358               0 : IsInvisibleBreak(nsINode *aNode) {
         359                 :   // xxxehsan: we should probably figure out a way to determine
         360                 :   // if a BR node is visible without using the editor.
         361               0 :   Element* elt = aNode->AsElement();
         362               0 :   if (!elt->IsHTML(nsGkAtoms::br) ||
         363               0 :       !aNode->IsEditable()) {
         364               0 :     return false;
         365                 :   }
         366                 :
         367                 :   // Grab the editor associated with the document
         368               0 :   nsIDocument *doc = aNode->GetCurrentDoc();
         369               0 :   if (doc) {
         370               0 :     nsPIDOMWindow *window = doc->GetWindow();
         371               0 :     if (window) {
         372               0 :       nsIDocShell *docShell = window->GetDocShell();
         373               0 :       if (docShell) {
         374               0 :         nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
         375               0 :         if (editorDocShell) {
         376               0 :           nsCOMPtr<nsIEditor> editor;
         377               0 :           editorDocShell->GetEditor(getter_AddRefs(editor));
         378               0 :           nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
         379               0 :           if (htmlEditor) {
         380               0 :             bool isVisible = false;
         381               0 :             nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
         382               0 :             htmlEditor->BreakIsVisible(domNode, &isVisible);
         383               0 :             return !isVisible;
         384                 :           }
         385                 :         }
         386                 :       }
         387                 :     }
         388                 :   }
         389               0 :   return false;
         390                 : }
         391                 :
         392                 : nsresult
         393            2160 : nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
         394                 :                                       PRInt32 aStartOffset,
         395                 :                                       PRInt32 aEndOffset,
         396                 :                                       nsAString& aStr,
         397                 :                                       nsINode* aOriginalNode)
         398                 : {
         399            2160 :   if (!IsVisibleNode(aNode))
         400               0 :     return NS_OK;
         401                 :
         402            2160 :   nsINode* node = nsnull;
         403            4320 :   nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
         404                 :
         405                 :   // Caller didn't do fixup, so we'll do it ourselves
         406            2160 :   if (!aOriginalNode) {
         407               0 :     aOriginalNode = aNode;
         408               0 :     if (mNodeFixup) {
         409                 :       bool dummy;
         410               0 :       nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aNode);
         411               0 :       nsCOMPtr<nsIDOMNode> domNodeOut;
         412               0 :       mNodeFixup->FixupNode(domNodeIn, &dummy, getter_AddRefs(domNodeOut));
         413               0 :       fixedNodeKungfuDeathGrip = do_QueryInterface(domNodeOut);
         414               0 :       node = fixedNodeKungfuDeathGrip;
         415                 :     }
         416                 :   }
         417                 :
         418                 :   // Either there was no fixed-up node,
         419                 :   // or the caller did fixup themselves and aNode is already fixed
         420            2160 :   if (!node)
         421            2160 :     node = aNode;
         422                 :
         423            2160 :   if (node->IsElement()) {
         424            1297 :     if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
         425                 :                    nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
         426               0 :         IsInvisibleBreak(node)) {
         427               0 :       return NS_OK;
         428                 :     }
         429                 :     Element* originalElement =
         430            1297 :       aOriginalNode && aOriginalNode->IsElement() ?
         431            2594 :         aOriginalNode->AsElement() : nsnull;
         432            1297 :     mSerializer->AppendElementStart(node->AsElement(),
         433            1297 :                                     originalElement, aStr);
         434            1297 :     return NS_OK;
         435                 :   }
         436                 :
         437             863 :   switch (node->NodeType()) {
         438                 :     case nsIDOMNode::TEXT_NODE:
         439                 :     {
         440             509 :       mSerializer->AppendText(static_cast<nsIContent*>(node),
         441             509 :                               aStartOffset, aEndOffset, aStr);
         442             509 :       break;
         443                 :     }
         444                 :     case nsIDOMNode::CDATA_SECTION_NODE:
         445                 :     {
         446               0 :       mSerializer->AppendCDATASection(static_cast<nsIContent*>(node),
         447               0 :                                       aStartOffset, aEndOffset, aStr);
         448               0 :       break;
         449                 :     }
         450                 :     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
         451                 :     {
         452              12 :       mSerializer->AppendProcessingInstruction(static_cast<nsIContent*>(node),
         453              12 :                                                aStartOffset, aEndOffset, aStr);
         454              12 :       break;
         455                 :     }
         456                 :     case nsIDOMNode::COMMENT_NODE:
         457                 :     {
         458              24 :       mSerializer->AppendComment(static_cast<nsIContent*>(node),
         459              24 :                                  aStartOffset, aEndOffset, aStr);
         460              24 :       break;
         461                 :     }
         462                 :     case nsIDOMNode::DOCUMENT_TYPE_NODE:
         463                 :     {
         464               9 :       mSerializer->AppendDoctype(static_cast<nsIContent*>(node), aStr);
         465               9 :       break;
         466                 :     }
         467                 :   }
         468                 :
         469             863 :   return NS_OK;
         470                 : }
         471                 :
         472                 : nsresult
         473            2160 : nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
         474                 :                                     nsAString& aStr)
         475                 : {
         476            2160 :   if (!IsVisibleNode(aNode))
         477               0 :     return NS_OK;
         478                 :
         479            2160 :   if (aNode->IsElement()) {
         480            1297 :     mSerializer->AppendElementEnd(aNode->AsElement(), aStr);
         481                 :   }
         482            2160 :   return NS_OK;
         483                 : }
         484                 :
         485                 : nsresult
         486            2160 : nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
         487                 :                                               nsAString& aStr,
         488                 :                                               bool aDontSerializeRoot)
         489                 : {
         490            2160 :   if (!IsVisibleNode(aNode))
         491               0 :     return NS_OK;
         492                 :
         493            2160 :   nsresult rv = NS_OK;
         494            2160 :   bool serializeClonedChildren = false;
         495            2160 :   nsINode* maybeFixedNode = nsnull;
         496                 :
         497                 :   // Keep the node from FixupNode alive.
         498            4320 :   nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
         499            2160 :   if (mNodeFixup) {
         500               0 :     nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aNode);
         501               0 :     nsCOMPtr<nsIDOMNode> domNodeOut;
         502               0 :     mNodeFixup->FixupNode(domNodeIn, &serializeClonedChildren, getter_AddRefs(domNodeOut));
         503               0 :     fixedNodeKungfuDeathGrip = do_QueryInterface(domNodeOut);
         504               0 :     maybeFixedNode = fixedNodeKungfuDeathGrip;
         505                 :   }
         506                 :
         507            2160 :   if (!maybeFixedNode)
         508            2160 :     maybeFixedNode = aNode;
         509                 :
         510            2160 :   if (mFlags & SkipInvisibleContent) {
         511               0 :     if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
         512               0 :       nsIFrame* frame = static_cast<nsIContent*>(aNode)->GetPrimaryFrame();
         513               0 :       if (frame) {
         514                 :         bool isSelectable;
         515               0 :         frame->IsSelectable(&isSelectable, nsnull);
         516               0 :         if (!isSelectable){
         517               0 :           aDontSerializeRoot = true;
         518                 :         }
         519                 :       }
         520                 :     }
         521                 :   }
         522                 :
         523            2160 :   if (!aDontSerializeRoot) {
         524            2160 :     rv = SerializeNodeStart(maybeFixedNode, 0, -1, aStr, aNode);
         525            2160 :     NS_ENSURE_SUCCESS(rv, rv);
         526                 :   }
         527                 :
         528            2160 :   nsINode* node = serializeClonedChildren ? maybeFixedNode : aNode;
         529                 :
         530            3856 :   for (nsINode* child = node->GetFirstChild(); child;
         531            1696 :        child = child->GetNextSibling()) {
         532            1696 :     rv = SerializeToStringRecursive(child, aStr, false);
         533            1696 :     NS_ENSURE_SUCCESS(rv, rv);
         534                 :   }
         535                 :
         536            2160 :   if (!aDontSerializeRoot) {
         537            2160 :     rv = SerializeNodeEnd(node, aStr);
         538            2160 :     NS_ENSURE_SUCCESS(rv, rv);
         539                 :   }
         540                 :
         541            2160 :   return FlushText(aStr, false);
         542                 : }
         543                 :
         544                 : nsresult
         545               0 : nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode,
         546                 :                                               nsAString& aStr)
         547                 : {
         548                 :   nsresult rv;
         549                 :
         550               0 :   nsINode* node = aNode->GetFirstChild();
         551               0 :   while (node) {
         552               0 :     nsINode* current = node;
         553               0 :     rv = SerializeNodeStart(current, 0, -1, aStr, current);
         554               0 :     NS_ENSURE_SUCCESS(rv, rv);
         555               0 :     node = current->GetFirstChild();
         556               0 :     while (!node && current && current != aNode) {
         557               0 :       rv = SerializeNodeEnd(current, aStr);
         558               0 :       NS_ENSURE_SUCCESS(rv, rv);
         559                 :       // Check if we have siblings.
         560               0 :       node = current->GetNextSibling();
         561               0 :       if (!node) {
         562                 :         // Perhaps parent node has siblings.
         563               0 :         current = current->GetNodeParent();
         564                 :       }
         565                 :     }
         566                 :   }
         567                 :
         568               0 :   return NS_OK;
         569                 : }
         570                 :
         571                 : bool
         572               0 : nsDocumentEncoder::IsTag(nsIContent* aContent, nsIAtom* aAtom)
         573                 : {
         574               0 :   return aContent && aContent->Tag() == aAtom;
         575                 : }
         576                 :
         577                 : static nsresult
         578             176 : ConvertAndWrite(const nsAString& aString,
         579                 :                 nsIOutputStream* aStream,
         580                 :                 nsIUnicodeEncoder* aEncoder)
         581                 : {
         582             176 :   NS_ENSURE_ARG_POINTER(aStream);
         583             176 :   NS_ENSURE_ARG_POINTER(aEncoder);
         584                 :   nsresult rv;
         585                 :   PRInt32 charLength, startCharLength;
         586             352 :   const nsPromiseFlatString& flat = PromiseFlatString(aString);
         587             176 :   const PRUnichar* unicodeBuf = flat.get();
         588             176 :   PRInt32 unicodeLength = aString.Length();
         589             176 :   PRInt32 startLength = unicodeLength;
         590                 :
         591             176 :   rv = aEncoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
         592             176 :   startCharLength = charLength;
         593             176 :   NS_ENSURE_SUCCESS(rv, rv);
         594                 :
         595             352 :   nsCAutoString charXferString;
         596             176 :   if (!EnsureStringLength(charXferString, charLength))
         597               0 :     return NS_ERROR_OUT_OF_MEMORY;
         598                 :
         599             176 :   char* charXferBuf = charXferString.BeginWriting();
         600             176 :   nsresult convert_rv = NS_OK;
         601                 :
         602             176 :   do {
         603             176 :     unicodeLength = startLength;
         604             176 :     charLength = startCharLength;
         605                 :
         606             176 :     convert_rv = aEncoder->Convert(unicodeBuf, &unicodeLength, charXferBuf, &charLength);
         607             176 :     NS_ENSURE_SUCCESS(convert_rv, convert_rv);
         608                 :
         609                 :     // Make sure charXferBuf is null-terminated before we call
         610                 :     // Write().
         611                 :
         612             176 :     charXferBuf[charLength] = '\0';
         613                 :
         614                 :     PRUint32 written;
         615             176 :     rv = aStream->Write(charXferBuf, charLength, &written);
         616             176 :     NS_ENSURE_SUCCESS(rv, rv);
         617                 :
         618                 :     // If the converter couldn't convert a chraacer we replace the
         619                 :     // character with a characre entity.
         620             176 :     if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
         621                 :       // Finishes the conversion.
         622                 :       // The converter has the possibility to write some extra data and flush its final state.
         623                 :       char finish_buf[33];
         624               0 :       charLength = sizeof(finish_buf) - 1;
         625               0 :       rv = aEncoder->Finish(finish_buf, &charLength);
         626               0 :       NS_ENSURE_SUCCESS(rv, rv);
         627                 :
         628                 :       // Make sure finish_buf is null-terminated before we call
         629                 :       // Write().
         630                 :
         631               0 :       finish_buf[charLength] = '\0';
         632                 :
         633               0 :       rv = aStream->Write(finish_buf, charLength, &written);
         634               0 :       NS_ENSURE_SUCCESS(rv, rv);
         635                 :
         636               0 :       nsCAutoString entString("&#");
         637               0 :       if (NS_IS_HIGH_SURROGATE(unicodeBuf[unicodeLength - 1]) &&
         638               0 :           unicodeLength < startLength && NS_IS_LOW_SURROGATE(unicodeBuf[unicodeLength]))  {
         639               0 :         entString.AppendInt(SURROGATE_TO_UCS4(unicodeBuf[unicodeLength - 1],
         640               0 :                                               unicodeBuf[unicodeLength]));
         641               0 :         unicodeLength += 1;
         642                 :       }
         643                 :       else
         644               0 :         entString.AppendInt(unicodeBuf[unicodeLength - 1]);
         645               0 :       entString.Append(';');
         646                 :
         647                 :       // Since entString is an nsCAutoString we know entString.get()
         648                 :       // returns a null-terminated string, so no need for extra
         649                 :       // null-termination before calling Write() here.
         650                 :
         651               0 :       rv = aStream->Write(entString.get(), entString.Length(), &written);
         652               0 :       NS_ENSURE_SUCCESS(rv, rv);
         653                 :
         654               0 :       unicodeBuf += unicodeLength;
         655               0 :       startLength -= unicodeLength;
         656                 :     }
         657                 :   } while (convert_rv == NS_ERROR_UENC_NOMAPPING);
         658                 :
         659             176 :   return rv;
         660                 : }
         661                 :
         662                 : nsresult
         663            2329 : nsDocumentEncoder::FlushText(nsAString& aString, bool aForce)
         664                 : {
         665            2329 :   if (!mStream)
         666            1810 :     return NS_OK;
         667                 :
         668             519 :   nsresult rv = NS_OK;
         669                 :
         670             519 :   if (aString.Length() > 1024 || aForce) {
         671             176 :     rv = ConvertAndWrite(aString, mStream, mUnicodeEncoder);
         672                 :
         673             176 :     aString.Truncate();
         674                 :   }
         675                 :
         676             519 :   return rv;
         677                 : }
         678                 :
         679                 : #if 0 // This code is really fast at serializing a range, but unfortunately
         680                 :       // there are problems with it so we don't use it now, maybe later...
         681                 : static nsresult ChildAt(nsIDOMNode* aNode, PRInt32 aIndex, nsIDOMNode*& aChild)
         682                 : {
         683                 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
         684                 :
         685                 :   aChild = nsnull;
         686                 :
         687                 :   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
         688                 :
         689                 :   nsIContent *child = content->GetChildAt(aIndex);
         690                 :
         691                 :   if (child)
         692                 :     return CallQueryInterface(child, &aChild);
         693                 :
         694                 :   return NS_OK;
         695                 : }
         696                 :
         697                 : static PRInt32 IndexOf(nsIDOMNode* aParent, nsIDOMNode* aChild)
         698                 : {
         699                 :   nsCOMPtr<nsIContent> parent(do_QueryInterface(aParent));
         700                 :   nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
         701                 :
         702                 :   if (!parent)
         703                 :     return -1;
         704                 :
         705                 :   return parent->IndexOf(child);
         706                 : }
         707                 :
         708                 : static inline PRInt32 GetIndex(nsTArray<PRInt32>& aIndexArray)
         709                 : {
         710                 :   PRInt32 count = aIndexArray.Length();
         711                 :
         712                 :   if (count) {
         713                 :     return aIndexArray.ElementAt(count - 1);
         714                 :   }
         715                 :
         716                 :   return 0;
         717                 : }
         718                 :
         719                 : static nsresult GetNextNode(nsIDOMNode* aNode, nsTArray<PRInt32>& aIndexArray,
         720                 :                             nsIDOMNode*& aNextNode,
         721                 :                             nsRangeIterationDirection& aDirection)
         722                 : {
         723                 :   bool hasChildren;
         724                 :
         725                 :   aNextNode = nsnull;
         726                 :
         727                 :   aNode->HasChildNodes(&hasChildren);
         728                 :
         729                 :   if (hasChildren && aDirection == kDirectionIn) {
         730                 :     ChildAt(aNode, 0, aNextNode);
         731                 :     NS_ENSURE_TRUE(aNextNode, NS_ERROR_FAILURE);
         732                 :
         733                 :     aIndexArray.AppendElement(0);
         734                 :
         735                 :     aDirection = kDirectionIn;
         736                 :   } else if (aDirection == kDirectionIn) {
         737                 :     aNextNode = aNode;
         738                 :
         739                 :     NS_ADDREF(aNextNode);
         740                 :
         741                 :     aDirection = kDirectionOut;
         742                 :   } else {
         743                 :     nsCOMPtr<nsIDOMNode> parent;
         744                 :
         745                 :     aNode->GetParentNode(getter_AddRefs(parent));
         746                 :     NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
         747                 :
         748                 :     PRInt32 count = aIndexArray.Length();
         749                 :
         750                 :     if (count) {
         751                 :       PRInt32 indx = aIndexArray.ElementAt(count - 1);
         752                 :
         753                 :       ChildAt(parent, indx + 1, aNextNode);
         754                 :
         755                 :       if (aNextNode)
         756                 :         aIndexArray.ElementAt(count - 1) = indx + 1;
         757                 :       else
         758                 :         aIndexArray.RemoveElementAt(count - 1);
         759                 :     } else {
         760                 :       PRInt32 indx = IndexOf(parent, aNode);
         761                 :
         762                 :       if (indx >= 0) {
         763                 :         ChildAt(parent, indx + 1, aNextNode);
         764                 :
         765                 :         if (aNextNode)
         766                 :           aIndexArray.AppendElement(indx + 1);
         767                 :       }
         768                 :     }
         769                 :
         770                 :     if (aNextNode) {
         771                 :       aDirection = kDirectionIn;
         772                 :     } else {
         773                 :       aDirection = kDirectionOut;
         774                 :
         775                 :       aNextNode = parent;
         776                 :
         777                 :       NS_ADDREF(aNextNode);
         778                 :     }
         779                 :   }
         780                 :
         781                 :   return NS_OK;
         782                 : }
         783                 : #endif
         784                 :
         785               0 : static bool IsTextNode(nsINode *aNode)
         786                 : {
         787               0 :   return aNode && aNode->IsNodeOfType(nsINode::eTEXT);
         788                 : }
         789                 :
         790               0 : static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
         791                 : {
         792               0 :   aCount = 0;
         793               0 :   if (!aNode) { return NS_ERROR_NULL_POINTER; }
         794               0 :   nsresult result=NS_OK;
         795               0 :   nsCOMPtr<nsIDOMCharacterData>nodeAsChar;
         796               0 :   nodeAsChar = do_QueryInterface(aNode);
         797               0 :   if (nodeAsChar) {
         798               0 :     nodeAsChar->GetLength(&aCount);
         799                 :   }
         800                 :   else
         801                 :   {
         802                 :     bool hasChildNodes;
         803               0 :     aNode->HasChildNodes(&hasChildNodes);
         804               0 :     if (true==hasChildNodes)
         805                 :     {
         806               0 :       nsCOMPtr<nsIDOMNodeList>nodeList;
         807               0 :       result = aNode->GetChildNodes(getter_AddRefs(nodeList));
         808               0 :       if (NS_SUCCEEDED(result) && nodeList) {
         809               0 :         nodeList->GetLength(&aCount);
         810                 :       }
         811                 :     }
         812                 :   }
         813               0 :   return result;
         814                 : }
         815                 :
         816                 : nsresult
         817               0 : nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
         818                 :                                        nsINode* aNode,
         819                 :                                        nsAString& aString,
         820                 :                                        PRInt32 aDepth)
         821                 : {
         822               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
         823               0 :   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
         824                 :
         825               0 :   if (!IsVisibleNode(aNode))
         826               0 :     return NS_OK;
         827                 :
         828               0 :   nsresult rv = NS_OK;
         829                 :
         830                 :   // get start and end nodes for this recursion level
         831               0 :   nsCOMPtr<nsIContent> startNode, endNode;
         832                 :   {
         833               0 :     PRInt32 start = mStartRootIndex - aDepth;
         834               0 :     if (start >= 0 && (PRUint32)start <= mStartNodes.Length())
         835               0 :       startNode = mStartNodes[start];
         836                 :
         837               0 :     PRInt32 end = mEndRootIndex - aDepth;
         838               0 :     if (end >= 0 && (PRUint32)end <= mEndNodes.Length())
         839               0 :       endNode = mEndNodes[end];
         840                 :   }
         841                 :
         842               0 :   if (startNode != content && endNode != content)
         843                 :   {
         844                 :     // node is completely contained in range.  Serialize the whole subtree
         845                 :     // rooted by this node.
         846               0 :     rv = SerializeToStringRecursive(aNode, aString, false);
         847               0 :     NS_ENSURE_SUCCESS(rv, rv);
         848                 :   }
         849                 :   else
         850                 :   {
         851                 :     // due to implementation it is impossible for text node to be both start and end of
         852                 :     // range.  We would have handled that case without getting here.
         853                 :     //XXXsmaug What does this all mean?
         854               0 :     if (IsTextNode(aNode))
         855                 :     {
         856               0 :       if (startNode == content)
         857                 :       {
         858               0 :         PRInt32 startOffset = aRange->StartOffset();
         859               0 :         rv = SerializeNodeStart(aNode, startOffset, -1, aString);
         860               0 :         NS_ENSURE_SUCCESS(rv, rv);
         861                 :       }
         862                 :       else
         863                 :       {
         864               0 :         PRInt32 endOffset = aRange->EndOffset();
         865               0 :         rv = SerializeNodeStart(aNode, 0, endOffset, aString);
         866               0 :         NS_ENSURE_SUCCESS(rv, rv);
         867                 :       }
         868                 :     }
         869                 :     else
         870                 :     {
         871               0 :       if (aNode != mCommonParent)
         872                 :       {
         873               0 :         if (IncludeInContext(aNode))
         874                 :         {
         875                 :           // halt the incrementing of mStartDepth/mEndDepth.  This is
         876                 :           // so paste client will include this node in paste.
         877               0 :           mHaltRangeHint = true;
         878                 :         }
         879               0 :         if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
         880               0 :         if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
         881                 :
         882                 :         // serialize the start of this node
         883               0 :         rv = SerializeNodeStart(aNode, 0, -1, aString);
         884               0 :         NS_ENSURE_SUCCESS(rv, rv);
         885                 :       }
         886                 :
         887                 :       // do some calculations that will tell us which children of this
         888                 :       // node are in the range.
         889               0 :       nsIContent* childAsNode = nsnull;
         890               0 :       PRInt32 startOffset = 0, endOffset = -1;
         891               0 :       if (startNode == content && mStartRootIndex >= aDepth)
         892               0 :         startOffset = mStartOffsets[mStartRootIndex - aDepth];
         893               0 :       if (endNode == content && mEndRootIndex >= aDepth)
         894               0 :         endOffset = mEndOffsets[mEndRootIndex - aDepth];
         895                 :       // generated content will cause offset values of -1 to be returned.
         896                 :       PRInt32 j;
         897               0 :       PRUint32 childCount = content->GetChildCount();
         898                 :
         899               0 :       if (startOffset == -1) startOffset = 0;
         900               0 :       if (endOffset == -1) endOffset = childCount;
         901                 :       else
         902                 :       {
         903                 :         // if we are at the "tip" of the selection, endOffset is fine.
         904                 :         // otherwise, we need to add one.  This is because of the semantics
         905                 :         // of the offset list created by GetAncestorsAndOffsets().  The
         906                 :         // intermediate points on the list use the endOffset of the
         907                 :         // location of the ancestor, rather than just past it.  So we need
         908                 :         // to add one here in order to include it in the children we serialize.
         909               0 :         if (aNode != aRange->GetEndParent())
         910                 :         {
         911               0 :           endOffset++;
         912                 :         }
         913                 :       }
         914                 :       // serialize the children of this node that are in the range
         915               0 :       for (j=startOffset; j<endOffset; j++)
         916                 :       {
         917               0 :         childAsNode = content->GetChildAt(j);
         918                 :
         919               0 :         if ((j==startOffset) || (j==endOffset-1))
         920               0 :           rv = SerializeRangeNodes(aRange, childAsNode, aString, aDepth+1);
         921                 :         else
         922               0 :           rv = SerializeToStringRecursive(childAsNode, aString, false);
         923                 :
         924               0 :         NS_ENSURE_SUCCESS(rv, rv);
         925                 :       }
         926                 :
         927                 :       // serialize the end of this node
         928               0 :       if (aNode != mCommonParent)
         929                 :       {
         930               0 :         rv = SerializeNodeEnd(aNode, aString);
         931               0 :         NS_ENSURE_SUCCESS(rv, rv);
         932                 :       }
         933                 :     }
         934                 :   }
         935               0 :   return NS_OK;
         936                 : }
         937                 :
         938                 : nsresult
         939               0 : nsDocumentEncoder::SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
         940                 :                                               nsAString& aString)
         941                 : {
         942               0 :   PRInt32 i = aAncestorArray.Length();
         943               0 :   nsresult rv = NS_OK;
         944                 :
         945               0 :   while (i > 0) {
         946               0 :     nsINode *node = aAncestorArray.ElementAt(--i);
         947                 :
         948               0 :     if (!node)
         949               0 :       break;
         950                 :
         951               0 :     if (IncludeInContext(node)) {
         952               0 :       rv = SerializeNodeStart(node, 0, -1, aString);
         953                 :
         954               0 :       if (NS_FAILED(rv))
         955               0 :         break;
         956                 :     }
         957                 :   }
         958                 :
         959               0 :   return rv;
         960                 : }
         961                 :
         962                 : nsresult
         963               0 : nsDocumentEncoder::SerializeRangeContextEnd(const nsTArray<nsINode*>& aAncestorArray,
         964                 :                                             nsAString& aString)
         965                 : {
         966               0 :   PRInt32 i = 0;
         967               0 :   PRInt32 count = aAncestorArray.Length();
         968               0 :   nsresult rv = NS_OK;
         969                 :
         970               0 :   while (i < count) {
         971               0 :     nsINode *node = aAncestorArray.ElementAt(i++);
         972                 :
         973               0 :     if (!node)
         974               0 :       break;
         975                 :
         976               0 :     if (IncludeInContext(node)) {
         977               0 :       rv = SerializeNodeEnd(node, aString);
         978                 :
         979               0 :       if (NS_FAILED(rv))
         980               0 :         break;
         981                 :     }
         982                 :   }
         983                 :
         984               0 :   return rv;
         985                 : }
         986                 :
         987                 : nsresult
         988               0 : nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
         989                 :                                           nsAString& aOutputString)
         990                 : {
         991               0 :   if (!aRange || aRange->Collapsed())
         992               0 :     return NS_OK;
         993                 :
         994               0 :   mCommonParent = aRange->GetCommonAncestor();
         995                 :
         996               0 :   if (!mCommonParent)
         997               0 :     return NS_OK;
         998                 :
         999               0 :   nsINode* startParent = aRange->GetStartParent();
        1000               0 :   NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
        1001               0 :   PRInt32 startOffset = aRange->StartOffset();
        1002                 :
        1003               0 :   nsINode* endParent = aRange->GetEndParent();
        1004               0 :   NS_ENSURE_TRUE(endParent, NS_ERROR_FAILURE);
        1005               0 :   PRInt32 endOffset = aRange->EndOffset();
        1006                 :
        1007               0 :   mCommonAncestors.Clear();
        1008               0 :   mStartNodes.Clear();
        1009               0 :   mStartOffsets.Clear();
        1010               0 :   mEndNodes.Clear();
        1011               0 :   mEndOffsets.Clear();
        1012                 :
        1013               0 :   nsContentUtils::GetAncestors(mCommonParent, mCommonAncestors);
        1014               0 :   nsCOMPtr<nsIDOMNode> sp = do_QueryInterface(startParent);
        1015                 :   nsContentUtils::GetAncestorsAndOffsets(sp, startOffset,
        1016               0 :                                          &mStartNodes, &mStartOffsets);
        1017               0 :   nsCOMPtr<nsIDOMNode> ep = do_QueryInterface(endParent);
        1018                 :   nsContentUtils::GetAncestorsAndOffsets(ep, endOffset,
        1019               0 :                                          &mEndNodes, &mEndOffsets);
        1020                 :
        1021               0 :   nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
        1022               0 :   mStartRootIndex = mStartNodes.IndexOf(commonContent);
        1023               0 :   mEndRootIndex = mEndNodes.IndexOf(commonContent);
        1024                 :
        1025               0 :   nsresult rv = NS_OK;
        1026                 :
        1027               0 :   rv = SerializeRangeContextStart(mCommonAncestors, aOutputString);
        1028               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1029                 :
        1030               0 :   if ((startParent == endParent) && IsTextNode(startParent))
        1031                 :   {
        1032               0 :     if (mFlags & SkipInvisibleContent) {
        1033                 :       // Check that the parent is visible if we don't a frame.
        1034                 :       // IsVisibleNode() will do it when there's a frame.
        1035               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(startParent);
        1036               0 :       if (content && !content->GetPrimaryFrame()) {
        1037               0 :         nsIContent* parent = content->GetParent();
        1038               0 :         if (!parent || !IsVisibleNode(parent))
        1039               0 :           return NS_OK;
        1040                 :       }
        1041                 :     }
        1042               0 :     rv = SerializeNodeStart(startParent, startOffset, endOffset, aOutputString);
        1043               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1044                 :   }
        1045                 :   else
        1046                 :   {
        1047               0 :     rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
        1048               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1049                 :   }
        1050               0 :   rv = SerializeRangeContextEnd(mCommonAncestors, aOutputString);
        1051               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1052                 :
        1053               0 :   return rv;
        1054                 : }
        1055                 :
        1056                 : NS_IMETHODIMP
        1057             464 : nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
        1058                 : {
        1059             464 :   if (!mDocument)
        1060               0 :     return NS_ERROR_NOT_INITIALIZED;
        1061                 :
        1062             464 :   aOutputString.Truncate();
        1063                 :
        1064             928 :   nsString output;
        1065                 :   static const size_t bufferSize = 2048;
        1066             464 :   if (!mCachedBuffer) {
        1067             461 :     mCachedBuffer = nsStringBuffer::Alloc(bufferSize);
        1068                 :   }
        1069             464 :   NS_ASSERTION(!mCachedBuffer->IsReadonly(),
        1070                 :                "DocumentEncoder shouldn't keep reference to non-readonly buffer!");
        1071             464 :   static_cast<PRUnichar*>(mCachedBuffer->Data())[0] = PRUnichar(0);
        1072             464 :   mCachedBuffer->ToString(0, output, true);
        1073                 :   // output owns the buffer now!
        1074             464 :   mCachedBuffer = nsnull;
        1075                 :
        1076                 :
        1077             464 :   if (!mSerializer) {
        1078             918 :     nsCAutoString progId(NS_CONTENTSERIALIZER_CONTRACTID_PREFIX);
        1079             459 :     AppendUTF16toUTF8(mMimeType, progId);
        1080                 :
        1081             459 :     mSerializer = do_CreateInstance(progId.get());
        1082             459 :     NS_ENSURE_TRUE(mSerializer, NS_ERROR_NOT_IMPLEMENTED);
        1083                 :   }
        1084                 :
        1085             464 :   nsresult rv = NS_OK;
        1086                 :
        1087             928 :   nsCOMPtr<nsIAtom> charsetAtom;
        1088             464 :   if (!mCharset.IsEmpty()) {
        1089             230 :     if (!mCharsetConverterManager) {
        1090              56 :       mCharsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
        1091              56 :       NS_ENSURE_SUCCESS(rv, rv);
        1092                 :     }
        1093                 :   }
        1094                 :
        1095             464 :   bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration);
        1096             464 :   mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, rewriteEncodingDeclaration);
        1097                 :
        1098             464 :   if (mSelection) {
        1099               0 :     nsCOMPtr<nsIDOMRange> range;
        1100               0 :     PRInt32 i, count = 0;
        1101                 :
        1102               0 :     rv = mSelection->GetRangeCount(&count);
        1103               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1104                 :
        1105               0 :     nsCOMPtr<nsIDOMNode> node, prevNode;
        1106               0 :     for (i = 0; i < count; i++) {
        1107               0 :       mSelection->GetRangeAt(i, getter_AddRefs(range));
        1108                 :
        1109                 :       // Bug 236546: newlines not added when copying table cells into clipboard
        1110                 :       // Each selected cell shows up as a range containing a row with a single cell
        1111                 :       // get the row, compare it to previous row and emit </tr><tr> as needed
        1112               0 :       range->GetStartContainer(getter_AddRefs(node));
        1113               0 :       NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
        1114               0 :       if (node != prevNode) {
        1115               0 :         if (prevNode) {
        1116               0 :           nsCOMPtr<nsINode> p = do_QueryInterface(prevNode);
        1117               0 :           rv = SerializeNodeEnd(p, output);
        1118               0 :           NS_ENSURE_SUCCESS(rv, rv);
        1119               0 :           prevNode = nsnull;
        1120                 :         }
        1121               0 :         nsCOMPtr<nsIContent> content = do_QueryInterface(node);
        1122               0 :         if (content && content->Tag() == nsGkAtoms::tr) {
        1123               0 :           nsCOMPtr<nsINode> n = do_QueryInterface(node);
        1124               0 :           rv = SerializeNodeStart(n, 0, -1, output);
        1125               0 :           NS_ENSURE_SUCCESS(rv, rv);
        1126               0 :           prevNode = node;
        1127                 :         }
        1128                 :       }
        1129                 :
        1130               0 :       nsRange* r = static_cast<nsRange*>(range.get());
        1131               0 :       rv = SerializeRangeToString(r, output);
        1132               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1133                 :     }
        1134               0 :     if (prevNode) {
        1135               0 :       nsCOMPtr<nsINode> p = do_QueryInterface(prevNode);
        1136               0 :       rv = SerializeNodeEnd(p, output);
        1137               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1138                 :     }
        1139                 :
        1140               0 :     mSelection = nsnull;
        1141             464 :   } else if (mRange) {
        1142               0 :       rv = SerializeRangeToString(mRange, output);
        1143                 :
        1144               0 :       mRange = nsnull;
        1145             464 :   } else if (mNode) {
        1146             155 :     if (!mNodeFixup && !(mFlags & SkipInvisibleContent) && !mStream &&
        1147                 :         mNodeIsContainer) {
        1148               0 :       rv = SerializeToStringIterative(mNode, output);
        1149                 :     } else {
        1150             155 :       rv = SerializeToStringRecursive(mNode, output, mNodeIsContainer);
        1151                 :     }
        1152             155 :     mNode = nsnull;
        1153                 :   } else {
        1154             309 :     rv = mSerializer->AppendDocumentStart(mDocument, output);
        1155                 :
        1156             309 :     if (NS_SUCCEEDED(rv)) {
        1157             309 :       rv = SerializeToStringRecursive(mDocument, output, false);
        1158                 :     }
        1159                 :   }
        1160                 :
        1161             464 :   NS_ENSURE_SUCCESS(rv, rv);
        1162             464 :   rv = mSerializer->Flush(output);
        1163                 :
        1164             464 :   mCachedBuffer = nsStringBuffer::FromString(output);
        1165                 :   // We have to be careful how we set aOutputString, because we don't
        1166                 :   // want it to end up sharing mCachedBuffer if we plan to reuse it.
        1167             464 :   bool setOutput = false;
        1168                 :   // Try to cache the buffer.
        1169             464 :   if (mCachedBuffer) {
        1170             911 :     if (mCachedBuffer->StorageSize() == bufferSize &&
        1171             449 :         !mCachedBuffer->IsReadonly()) {
        1172             449 :       mCachedBuffer->AddRef();
        1173                 :     } else {
        1174              13 :       if (NS_SUCCEEDED(rv)) {
        1175              13 :         mCachedBuffer->ToString(output.Length(), aOutputString);
        1176              13 :         setOutput = true;
        1177                 :       }
        1178              13 :       mCachedBuffer = nsnull;
        1179                 :     }
        1180                 :   }
        1181                 :
        1182             464 :   if (!setOutput && NS_SUCCEEDED(rv)) {
        1183             451 :     aOutputString.Append(output.get(), output.Length());
        1184                 :   }
        1185                 :
        1186             464 :   return rv;
        1187                 : }
        1188                 :
        1189                 : NS_IMETHODIMP
        1190             169 : nsDocumentEncoder::EncodeToStream(nsIOutputStream* aStream)
        1191                 : {
        1192             169 :   nsresult rv = NS_OK;
        1193                 :
        1194             169 :   if (!mDocument)
        1195               0 :     return NS_ERROR_NOT_INITIALIZED;
        1196                 :
        1197             169 :   if (!mCharsetConverterManager) {
        1198             169 :     mCharsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
        1199             169 :     NS_ENSURE_SUCCESS(rv, rv);
        1200                 :   }
        1201                 :
        1202             169 :   rv = mCharsetConverterManager->GetUnicodeEncoder(mCharset.get(),
        1203             169 :                                                    getter_AddRefs(mUnicodeEncoder));
        1204             169 :   NS_ENSURE_SUCCESS(rv, rv);
        1205                 :
        1206             169 :   if (mMimeType.LowerCaseEqualsLiteral("text/plain")) {
        1207               0 :     rv = mUnicodeEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nsnull, '?');
        1208               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1209                 :   }
        1210                 :
        1211             169 :   mStream = aStream;
        1212                 :
        1213             338 :   nsAutoString buf;
        1214                 :
        1215             169 :   rv = EncodeToString(buf);
        1216                 :
        1217                 :   // Force a flush of the last chunk of data.
        1218             169 :   FlushText(buf, true);
        1219                 :
        1220             169 :   mStream = nsnull;
        1221             169 :   mUnicodeEncoder = nsnull;
        1222                 :
        1223             169 :   return rv;
        1224                 : }
        1225                 :
        1226                 : NS_IMETHODIMP
        1227               0 : nsDocumentEncoder::EncodeToStringWithContext(nsAString& aContextString,
        1228                 :                                              nsAString& aInfoString,
        1229                 :                                              nsAString& aEncodedString)
        1230                 : {
        1231               0 :   return NS_ERROR_NOT_IMPLEMENTED;
        1232                 : }
        1233                 :
        1234                 : NS_IMETHODIMP
        1235               0 : nsDocumentEncoder::SetNodeFixup(nsIDocumentEncoderNodeFixup *aFixup)
        1236                 : {
        1237               0 :   mNodeFixup = aFixup;
        1238               0 :   return NS_OK;
        1239                 : }
        1240                 :
        1241                 :
        1242                 : nsresult NS_NewTextEncoder(nsIDocumentEncoder** aResult); // make mac compiler happy
        1243                 :
        1244                 : nsresult
        1245             459 : NS_NewTextEncoder(nsIDocumentEncoder** aResult)
        1246                 : {
        1247             459 :   *aResult = new nsDocumentEncoder;
        1248             459 :   if (!*aResult)
        1249               0 :     return NS_ERROR_OUT_OF_MEMORY;
        1250             459 :  NS_ADDREF(*aResult);
        1251             459 :  return NS_OK;
        1252                 : }
        1253                 :
        1254                 : class nsHTMLCopyEncoder : public nsDocumentEncoder
        1255                 : {
        1256                 : public:
        1257                 :
        1258                 :   nsHTMLCopyEncoder();
        1259                 :   virtual ~nsHTMLCopyEncoder();
        1260                 :
        1261                 :   NS_IMETHOD Init(nsIDOMDocument* aDocument, const nsAString& aMimeType, PRUint32 aFlags);
        1262                 :
        1263                 :   // overridden methods from nsDocumentEncoder
        1264                 :   NS_IMETHOD SetSelection(nsISelection* aSelection);
        1265                 :   NS_IMETHOD EncodeToStringWithContext(nsAString& aContextString,
        1266                 :                                        nsAString& aInfoString,
        1267                 :                                        nsAString& aEncodedString);
        1268                 :
        1269                 : protected:
        1270                 :
        1271                 :   enum Endpoint
        1272                 :   {
        1273                 :     kStart,
        1274                 :     kEnd
        1275                 :   };
        1276                 :
        1277                 :   nsresult PromoteRange(nsIDOMRange *inRange);
        1278                 :   nsresult PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
        1279                 :                                 PRInt32 *ioStartOffset,
        1280                 :                                 PRInt32 *ioEndOffset);
        1281                 :   nsresult GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
        1282                 :                             nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset, nsIDOMNode *aCommon);
        1283                 :   nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset);
        1284                 :   bool IsMozBR(nsIDOMNode* aNode);
        1285                 :   nsresult GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset);
        1286                 :   bool IsRoot(nsIDOMNode* aNode);
        1287                 :   bool IsFirstNode(nsIDOMNode *aNode);
        1288                 :   bool IsLastNode(nsIDOMNode *aNode);
        1289                 :   bool IsEmptyTextContent(nsIDOMNode* aNode);
        1290                 :   virtual bool IncludeInContext(nsINode *aNode);
        1291                 :
        1292                 :   bool mIsTextWidget;
        1293                 : };
        1294                 :
        1295               0 : nsHTMLCopyEncoder::nsHTMLCopyEncoder()
        1296                 : {
        1297               0 :   mIsTextWidget = false;
        1298               0 : }
        1299                 :
        1300               0 : nsHTMLCopyEncoder::~nsHTMLCopyEncoder()
        1301                 : {
        1302               0 : }
        1303                 :
        1304                 : NS_IMETHODIMP
        1305               0 : nsHTMLCopyEncoder::Init(nsIDOMDocument* aDocument,
        1306                 :                         const nsAString& aMimeType,
        1307                 :                         PRUint32 aFlags)
        1308                 : {
        1309               0 :   if (!aDocument)
        1310               0 :     return NS_ERROR_INVALID_ARG;
        1311                 :
        1312               0 :   mIsTextWidget = false;
        1313               0 :   Initialize();
        1314                 :
        1315               0 :   mIsCopying = true;
        1316               0 :   mDocument = do_QueryInterface(aDocument);
        1317               0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
        1318                 :
        1319                 :   // Hack, hack! Traditionally, the caller passes text/unicode, which is
        1320                 :   // treated as "guess text/html or text/plain" in this context. (It has a
        1321                 :   // different meaning in other contexts. Sigh.) From now on, "text/plain"
        1322                 :   // means forcing text/plain instead of guessing.
        1323               0 :   if (aMimeType.EqualsLiteral("text/plain")) {
        1324               0 :     mMimeType.AssignLiteral("text/plain");
        1325                 :   } else {
        1326               0 :     mMimeType.AssignLiteral("text/html");
        1327                 :   }
        1328                 :
        1329                 :   // Make all links absolute when copying
        1330                 :   // (see related bugs #57296, #41924, #58646, #32768)
        1331               0 :   mFlags = aFlags | OutputAbsoluteLinks;
        1332                 :
        1333               0 :   if (!mDocument->IsScriptEnabled())
        1334               0 :     mFlags |= OutputNoScriptContent;
        1335                 :
        1336               0 :   return NS_OK;
        1337                 : }
        1338                 :
        1339                 : NS_IMETHODIMP
        1340               0 : nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
        1341                 : {
        1342                 :   // check for text widgets: we need to recognize these so that
        1343                 :   // we don't tweak the selection to be outside of the magic
        1344                 :   // div that ender-lite text widgets are embedded in.
        1345                 :
        1346               0 :   if (!aSelection)
        1347               0 :     return NS_ERROR_NULL_POINTER;
        1348                 :
        1349               0 :   nsCOMPtr<nsIDOMRange> range;
        1350               0 :   nsCOMPtr<nsIDOMNode> commonParent;
        1351               0 :   PRInt32 count = 0;
        1352                 :
        1353               0 :   nsresult rv = aSelection->GetRangeCount(&count);
        1354               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1355                 :
        1356                 :   // if selection is uninitialized return
        1357               0 :   if (!count)
        1358               0 :     return NS_ERROR_FAILURE;
        1359                 :
        1360                 :   // we'll just use the common parent of the first range.  Implicit assumption
        1361                 :   // here that multi-range selections are table cell selections, in which case
        1362                 :   // the common parent is somewhere in the table and we don't really care where.
        1363               0 :   rv = aSelection->GetRangeAt(0, getter_AddRefs(range));
        1364               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1365               0 :   if (!range)
        1366               0 :     return NS_ERROR_NULL_POINTER;
        1367               0 :   range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
        1368                 :
        1369               0 :   for (nsCOMPtr<nsIContent> selContent(do_QueryInterface(commonParent));
        1370               0 :        selContent;
        1371               0 :        selContent = selContent->GetParent())
        1372                 :   {
        1373                 :     // checking for selection inside a plaintext form widget
        1374               0 :     nsIAtom *atom = selContent->Tag();
        1375               0 :     if (atom == nsGkAtoms::input ||
        1376                 :         atom == nsGkAtoms::textarea)
        1377                 :     {
        1378               0 :       mIsTextWidget = true;
        1379               0 :       break;
        1380                 :     }
        1381               0 :     else if (atom == nsGkAtoms::body)
        1382                 :     {
        1383                 :       // check for moz prewrap style on body.  If it's there we are
        1384                 :       // in a plaintext editor.  This is pretty cheezy but I haven't
        1385                 :       // found a good way to tell if we are in a plaintext editor.
        1386               0 :       nsCOMPtr<nsIDOMElement> bodyElem = do_QueryInterface(selContent);
        1387               0 :       nsAutoString wsVal;
        1388               0 :       rv = bodyElem->GetAttribute(NS_LITERAL_STRING("style"), wsVal);
        1389               0 :       if (NS_SUCCEEDED(rv) && (kNotFound != wsVal.Find(NS_LITERAL_STRING("pre-wrap"))))
        1390                 :       {
        1391               0 :         mIsTextWidget = true;
        1392                 :         break;
        1393                 :       }
        1394                 :     }
        1395                 :   }
        1396                 :
        1397                 :   // also consider ourselves in a text widget if we can't find an html document
        1398               0 :   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
        1399               0 :   if (!(htmlDoc && mDocument->IsHTML()))
        1400               0 :     mIsTextWidget = true;
        1401                 :
        1402                 :   // normalize selection if we are not in a widget
        1403               0 :   if (mIsTextWidget)
        1404                 :   {
        1405               0 :     mSelection = aSelection;
        1406               0 :     mMimeType.AssignLiteral("text/plain");
        1407               0 :     return NS_OK;
        1408                 :   }
        1409                 :
        1410                 :   // there's no Clone() for selection! fix...
        1411                 :   //nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
        1412                 :   //NS_ENSURE_SUCCESS(rv, rv);
        1413               0 :   NS_NewDomSelection(getter_AddRefs(mSelection));
        1414               0 :   NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
        1415               0 :   nsCOMPtr<nsISelectionPrivate> privSelection( do_QueryInterface(aSelection) );
        1416               0 :   NS_ENSURE_TRUE(privSelection, NS_ERROR_FAILURE);
        1417                 :
        1418                 :   // get selection range enumerator
        1419               0 :   nsCOMPtr<nsIEnumerator> enumerator;
        1420               0 :   rv = privSelection->GetEnumerator(getter_AddRefs(enumerator));
        1421               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1422               0 :   NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
        1423                 :
        1424                 :   // loop thru the ranges in the selection
        1425               0 :   enumerator->First();
        1426               0 :   nsCOMPtr<nsISupports> currentItem;
        1427               0 :   while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
        1428                 :   {
        1429               0 :     rv = enumerator->CurrentItem(getter_AddRefs(currentItem));
        1430               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1431               0 :     NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
        1432                 :
        1433               0 :     range = do_QueryInterface(currentItem);
        1434               0 :     NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
        1435               0 :     nsCOMPtr<nsIDOMRange> myRange;
        1436               0 :     range->CloneRange(getter_AddRefs(myRange));
        1437               0 :     NS_ENSURE_TRUE(myRange, NS_ERROR_FAILURE);
        1438                 :
        1439                 :     // adjust range to include any ancestors who's children are entirely selected
        1440               0 :     rv = PromoteRange(myRange);
        1441               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1442                 :
        1443               0 :     rv = mSelection->AddRange(myRange);
        1444               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1445                 :
        1446               0 :     enumerator->Next();
        1447                 :   }
        1448                 :
        1449               0 :   return NS_OK;
        1450                 : }
        1451                 :
        1452                 : NS_IMETHODIMP
        1453               0 : nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
        1454                 :                                              nsAString& aInfoString,
        1455                 :                                              nsAString& aEncodedString)
        1456                 : {
        1457               0 :   nsresult rv = EncodeToString(aEncodedString);
        1458               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1459                 :
        1460                 :   // do not encode any context info or range hints if we are in a text widget.
        1461               0 :   if (mIsTextWidget) return NS_OK;
        1462                 :
        1463                 :   // now encode common ancestors into aContextString.  Note that the common ancestors
        1464                 :   // will be for the last range in the selection in the case of multirange selections.
        1465                 :   // encoding ancestors every range in a multirange selection in a way that could be
        1466                 :   // understood by the paste code would be a lot more work to do.  As a practical matter,
        1467                 :   // selections are single range, and the ones that aren't are table cell selections
        1468                 :   // where all the cells are in the same table.
        1469                 :
        1470                 :   // leaf of ancestors might be text node.  If so discard it.
        1471               0 :   PRInt32 count = mCommonAncestors.Length();
        1472                 :   PRInt32 i;
        1473               0 :   nsCOMPtr<nsINode> node;
        1474               0 :   if (count > 0)
        1475               0 :     node = mCommonAncestors.ElementAt(0);
        1476                 :
        1477               0 :   if (node && IsTextNode(node))
        1478                 :   {
        1479               0 :     mCommonAncestors.RemoveElementAt(0);
        1480                 :     // don't forget to adjust range depth info
        1481               0 :     if (mStartDepth) mStartDepth--;
        1482               0 :     if (mEndDepth) mEndDepth--;
        1483                 :     // and the count
        1484               0 :     count--;
        1485                 :   }
        1486                 :
        1487               0 :   i = count;
        1488               0 :   while (i > 0)
        1489                 :   {
        1490               0 :     node = mCommonAncestors.ElementAt(--i);
        1491               0 :     SerializeNodeStart(node, 0, -1, aContextString);
        1492                 :   }
        1493                 :   //i = 0; guaranteed by above
        1494               0 :   while (i < count)
        1495                 :   {
        1496               0 :     node = mCommonAncestors.ElementAt(i++);
        1497               0 :     SerializeNodeEnd(node, aContextString);
        1498                 :   }
        1499                 :
        1500                 :   // encode range info : the start and end depth of the selection, where the depth is
        1501                 :   // distance down in the parent hierarchy.  Later we will need to add leading/trailing
        1502                 :   // whitespace info to this.
        1503               0 :   nsAutoString infoString;
        1504               0 :   infoString.AppendInt(mStartDepth);
        1505               0 :   infoString.Append(PRUnichar(','));
        1506               0 :   infoString.AppendInt(mEndDepth);
        1507               0 :   aInfoString = infoString;
        1508                 :
        1509               0 :   return NS_OK;
        1510                 : }
        1511                 :
        1512                 :
        1513                 : bool
        1514               0 : nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
        1515                 : {
        1516               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
        1517                 :
        1518               0 :   if (!content)
        1519               0 :     return false;
        1520                 :
        1521               0 :   nsIAtom *tag = content->Tag();
        1522                 :
        1523                 :   return (tag == nsGkAtoms::b        ||
        1524                 :           tag == nsGkAtoms::i        ||
        1525                 :           tag == nsGkAtoms::u        ||
        1526                 :           tag == nsGkAtoms::a        ||
        1527                 :           tag == nsGkAtoms::tt       ||
        1528                 :           tag == nsGkAtoms::s        ||
        1529                 :           tag == nsGkAtoms::big      ||
        1530                 :           tag == nsGkAtoms::small    ||
        1531                 :           tag == nsGkAtoms::strike   ||
        1532                 :           tag == nsGkAtoms::em       ||
        1533                 :           tag == nsGkAtoms::strong   ||
        1534                 :           tag == nsGkAtoms::dfn      ||
        1535                 :           tag == nsGkAtoms::code     ||
        1536                 :           tag == nsGkAtoms::cite     ||
        1537                 :           tag == nsGkAtoms::var      ||
        1538                 :           tag == nsGkAtoms::abbr     ||
        1539                 :           tag == nsGkAtoms::font     ||
        1540                 :           tag == nsGkAtoms::script   ||
        1541                 :           tag == nsGkAtoms::span     ||
        1542                 :           tag == nsGkAtoms::pre      ||
        1543                 :           tag == nsGkAtoms::h1       ||
        1544                 :           tag == nsGkAtoms::h2       ||
        1545                 :           tag == nsGkAtoms::h3       ||
        1546                 :           tag == nsGkAtoms::h4       ||
        1547                 :           tag == nsGkAtoms::h5       ||
        1548               0 :           tag == nsGkAtoms::h6);
        1549                 : }
        1550                 :
        1551                 :
        1552                 : nsresult
        1553               0 : nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
        1554                 : {
        1555               0 :   if (!inRange) return NS_ERROR_NULL_POINTER;
        1556                 :   nsresult rv;
        1557               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode, common;
        1558                 :   PRInt32 startOffset, endOffset;
        1559                 :
        1560               0 :   rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
        1561               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1562               0 :   rv = inRange->GetStartContainer(getter_AddRefs(startNode));
        1563               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1564               0 :   rv = inRange->GetStartOffset(&startOffset);
        1565               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1566               0 :   rv = inRange->GetEndContainer(getter_AddRefs(endNode));
        1567               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1568               0 :   rv = inRange->GetEndOffset(&endOffset);
        1569               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1570                 :
        1571               0 :   nsCOMPtr<nsIDOMNode> opStartNode;
        1572               0 :   nsCOMPtr<nsIDOMNode> opEndNode;
        1573                 :   PRInt32 opStartOffset, opEndOffset;
        1574               0 :   nsCOMPtr<nsIDOMRange> opRange;
        1575                 :
        1576                 :   // examine range endpoints.
        1577               0 :   rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
        1578               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1579               0 :   rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
        1580               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1581                 :
        1582                 :   // if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
        1583               0 :   if ( (opStartNode == common) && (opEndNode == common) )
        1584                 :   {
        1585               0 :     rv = PromoteAncestorChain(address_of(opStartNode), &opStartOffset, &opEndOffset);
        1586               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1587               0 :     opEndNode = opStartNode;
        1588                 :   }
        1589                 :
        1590                 :   // set the range to the new values
        1591               0 :   rv = inRange->SetStart(opStartNode, opStartOffset);
        1592               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1593               0 :   rv = inRange->SetEnd(opEndNode, opEndOffset);
        1594               0 :   return rv;
        1595                 : }
        1596                 :
        1597                 :
        1598                 : // PromoteAncestorChain will promote a range represented by [{*ioNode,*ioStartOffset} , {*ioNode,*ioEndOffset}]
        1599                 : // The promotion is different from that found in getPromotedPoint: it will only promote one endpoint if it can
        1600                 : // promote the other.  Thus, instead of having a startnode/endNode, there is just the one ioNode.
        1601                 : nsresult
        1602               0 : nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
        1603                 :                                         PRInt32 *ioStartOffset,
        1604                 :                                         PRInt32 *ioEndOffset)
        1605                 : {
        1606               0 :   if (!ioNode || !ioStartOffset || !ioEndOffset) return NS_ERROR_NULL_POINTER;
        1607                 :
        1608               0 :   nsresult rv = NS_OK;
        1609               0 :   bool done = false;
        1610                 :
        1611               0 :   nsCOMPtr<nsIDOMNode> frontNode, endNode, parent;
        1612                 :   PRInt32 frontOffset, endOffset;
        1613                 :
        1614                 :   //save the editable state of the ioNode, so we don't promote an ancestor if it has different editable state
        1615               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(*ioNode);
        1616               0 :   bool isEditable = node->IsEditable();
        1617                 :
        1618                 :   // loop for as long as we can promote both endpoints
        1619               0 :   while (!done)
        1620                 :   {
        1621               0 :     rv = (*ioNode)->GetParentNode(getter_AddRefs(parent));
        1622               0 :     if ((NS_FAILED(rv)) || !parent)
        1623               0 :       done = true;
        1624                 :     else
        1625                 :     {
        1626                 :       // passing parent as last param to GetPromotedPoint() allows it to promote only one level
        1627                 :       // up the hierarchy.
        1628               0 :       rv = GetPromotedPoint( kStart, *ioNode, *ioStartOffset, address_of(frontNode), &frontOffset, parent);
        1629               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1630                 :       // then we make the same attempt with the endpoint
        1631               0 :       rv = GetPromotedPoint( kEnd, *ioNode, *ioEndOffset, address_of(endNode), &endOffset, parent);
        1632               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1633                 :
        1634               0 :       nsCOMPtr<nsINode> frontINode = do_QueryInterface(frontNode);
        1635                 :       // if both endpoints were promoted one level and isEditable is the same as the original node,
        1636                 :       // keep looping - otherwise we are done.
        1637               0 :       if ( (frontNode != parent) || (endNode != parent) || (frontINode->IsEditable() != isEditable) )
        1638               0 :         done = true;
        1639                 :       else
        1640                 :       {
        1641               0 :         *ioNode = frontNode;
        1642               0 :         *ioStartOffset = frontOffset;
        1643               0 :         *ioEndOffset = endOffset;
        1644                 :       }
        1645                 :     }
        1646                 :   }
        1647               0 :   return rv;
        1648                 : }
        1649                 :
        1650                 : nsresult
        1651               0 : nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
        1652                 :                                   nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset, nsIDOMNode *common)
        1653                 : {
        1654               0 :   nsresult rv = NS_OK;
        1655               0 :   nsCOMPtr<nsIDOMNode> node = aNode;
        1656               0 :   nsCOMPtr<nsIDOMNode> parent = aNode;
        1657               0 :   PRInt32 offset = aOffset;
        1658               0 :   bool    bResetPromotion = false;
        1659                 :
        1660                 :   // default values
        1661               0 :   *outNode = node;
        1662               0 :   *outOffset = offset;
        1663                 :
        1664               0 :   if (common == node)
        1665               0 :     return NS_OK;
        1666                 :
        1667               0 :   if (aWhere == kStart)
        1668                 :   {
        1669                 :     // some special casing for text nodes
        1670               0 :     nsCOMPtr<nsINode> t = do_QueryInterface(aNode);
        1671               0 :     if (IsTextNode(t))
        1672                 :     {
        1673                 :       // if not at beginning of text node, we are done
        1674               0 :       if (offset >  0)
        1675                 :       {
        1676                 :         // unless everything before us in just whitespace.  NOTE: we need a more
        1677                 :         // general solution that truly detects all cases of non-significant
        1678                 :         // whitesace with no false alarms.
        1679               0 :         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
        1680               0 :         nsAutoString text;
        1681               0 :         nodeAsText->SubstringData(0, offset, text);
        1682               0 :         text.CompressWhitespace();
        1683               0 :         if (!text.IsEmpty())
        1684               0 :           return NS_OK;
        1685               0 :         bResetPromotion = true;
        1686                 :       }
        1687                 :       // else
        1688               0 :       rv = GetNodeLocation(aNode, address_of(parent), &offset);
        1689               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1690                 :     }
        1691                 :     else
        1692                 :     {
        1693               0 :       node = GetChildAt(parent,offset);
        1694                 :     }
        1695               0 :     if (!node) node = parent;
        1696                 :
        1697                 :     // finding the real start for this point.  look up the tree for as long as we are the
        1698                 :     // first node in the container, and as long as we haven't hit the body node.
        1699               0 :     if (!IsRoot(node) && (parent != common))
        1700                 :     {
        1701               0 :       rv = GetNodeLocation(node, address_of(parent), &offset);
        1702               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1703               0 :       if (offset == -1) return NS_OK; // we hit generated content; STOP
        1704               0 :       nsIParserService *parserService = nsContentUtils::GetParserService();
        1705               0 :       if (!parserService)
        1706               0 :         return NS_ERROR_OUT_OF_MEMORY;
        1707               0 :       while ((IsFirstNode(node)) && (!IsRoot(parent)) && (parent != common))
        1708                 :       {
        1709               0 :         if (bResetPromotion)
        1710                 :         {
        1711               0 :           nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
        1712               0 :           if (content)
        1713                 :           {
        1714               0 :             bool isBlock = false;
        1715               0 :             parserService->IsBlock(parserService->HTMLAtomTagToId(content->Tag()), isBlock);
        1716               0 :             if (isBlock)
        1717                 :             {
        1718               0 :               bResetPromotion = false;
        1719                 :             }
        1720                 :           }
        1721                 :         }
        1722                 :
        1723               0 :         node = parent;
        1724               0 :         rv = GetNodeLocation(node, address_of(parent), &offset);
        1725               0 :         NS_ENSURE_SUCCESS(rv, rv);
        1726               0 :         if (offset == -1)  // we hit generated content; STOP
        1727                 :         {
        1728                 :           // back up a bit
        1729               0 :           parent = node;
        1730               0 :           offset = 0;
        1731               0 :           break;
        1732                 :         }
        1733                 :       }
        1734               0 :       if (bResetPromotion)
        1735                 :       {
        1736               0 :         *outNode = aNode;
        1737               0 :         *outOffset = aOffset;
        1738                 :       }
        1739                 :       else
        1740                 :       {
        1741               0 :         *outNode = parent;
        1742               0 :         *outOffset = offset;
        1743                 :       }
        1744               0 :       return rv;
        1745                 :     }
        1746                 :   }
        1747                 :
        1748               0 :   if (aWhere == kEnd)
        1749                 :   {
        1750                 :     // some special casing for text nodes
        1751               0 :     nsCOMPtr<nsINode> n = do_QueryInterface(aNode);
        1752               0 :     if (IsTextNode(n))
        1753                 :     {
        1754                 :       // if not at end of text node, we are done
        1755                 :       PRUint32 len;
        1756               0 :       GetLengthOfDOMNode(aNode, len);
        1757               0 :       if (offset < (PRInt32)len)
        1758                 :       {
        1759                 :         // unless everything after us in just whitespace.  NOTE: we need a more
        1760                 :         // general solution that truly detects all cases of non-significant
        1761                 :         // whitesace with no false alarms.
        1762               0 :         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
        1763               0 :         nsAutoString text;
        1764               0 :         nodeAsText->SubstringData(offset, len-offset, text);
        1765               0 :         text.CompressWhitespace();
        1766               0 :         if (!text.IsEmpty())
        1767               0 :           return NS_OK;
        1768               0 :         bResetPromotion = true;
        1769                 :       }
        1770               0 :       rv = GetNodeLocation(aNode, address_of(parent), &offset);
        1771               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1772                 :     }
        1773                 :     else
        1774                 :     {
        1775               0 :       if (offset) offset--; // we want node _before_ offset
        1776               0 :       node = GetChildAt(parent,offset);
        1777                 :     }
        1778               0 :     if (!node) node = parent;
        1779                 :
        1780                 :     // finding the real end for this point.  look up the tree for as long as we are the
        1781                 :     // last node in the container, and as long as we haven't hit the body node.
        1782               0 :     if (!IsRoot(node) && (parent != common))
        1783                 :     {
        1784               0 :       rv = GetNodeLocation(node, address_of(parent), &offset);
        1785               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1786               0 :       if (offset == -1) return NS_OK; // we hit generated content; STOP
        1787               0 :       nsIParserService *parserService = nsContentUtils::GetParserService();
        1788               0 :       if (!parserService)
        1789               0 :         return NS_ERROR_OUT_OF_MEMORY;
        1790               0 :       while ((IsLastNode(node)) && (!IsRoot(parent)) && (parent != common))
        1791                 :       {
        1792               0 :         if (bResetPromotion)
        1793                 :         {
        1794               0 :           nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
        1795               0 :           if (content)
        1796                 :           {
        1797               0 :             bool isBlock = false;
        1798               0 :             parserService->IsBlock(parserService->HTMLAtomTagToId(content->Tag()), isBlock);
        1799               0 :             if (isBlock)
        1800                 :             {
        1801               0 :               bResetPromotion = false;
        1802                 :             }
        1803                 :           }
        1804                 :         }
        1805                 :
        1806               0 :         node = parent;
        1807               0 :         rv = GetNodeLocation(node, address_of(parent), &offset);
        1808               0 :         NS_ENSURE_SUCCESS(rv, rv);
        1809               0 :         if (offset == -1)  // we hit generated content; STOP
        1810                 :         {
        1811                 :           // back up a bit
        1812               0 :           parent = node;
        1813               0 :           offset = 0;
        1814               0 :           break;
        1815                 :         }
        1816                 :       }
        1817               0 :       if (bResetPromotion)
        1818                 :       {
        1819               0 :         *outNode = aNode;
        1820               0 :         *outOffset = aOffset;
        1821                 :       }
        1822                 :       else
        1823                 :       {
        1824               0 :         *outNode = parent;
        1825               0 :         offset++;  // add one since this in an endpoint - want to be AFTER node.
        1826               0 :         *outOffset = offset;
        1827                 :       }
        1828               0 :       return rv;
        1829                 :     }
        1830                 :   }
        1831                 :
        1832               0 :   return rv;
        1833                 : }
        1834                 :
        1835                 : nsCOMPtr<nsIDOMNode>
        1836               0 : nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
        1837                 : {
        1838               0 :   nsCOMPtr<nsIDOMNode> resultNode;
        1839                 :
        1840               0 :   if (!aParent)
        1841               0 :     return resultNode;
        1842                 :
        1843               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
        1844               0 :   NS_PRECONDITION(content, "null content in nsHTMLCopyEncoder::GetChildAt");
        1845                 :
        1846               0 :   resultNode = do_QueryInterface(content->GetChildAt(aOffset));
        1847                 :
        1848                 :   return resultNode;
        1849                 : }
        1850                 :
        1851                 : bool
        1852               0 : nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
        1853                 : {
        1854               0 :   MOZ_ASSERT(aNode);
        1855               0 :   nsCOMPtr<Element> element = do_QueryInterface(aNode);
        1856                 :   return element &&
        1857               0 :          element->IsHTML(nsGkAtoms::br) &&
        1858               0 :          element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
        1859               0 :                               NS_LITERAL_STRING("_moz"), eIgnoreCase);
        1860                 : }
        1861                 :
        1862                 : nsresult
        1863               0 : nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
        1864                 :                                    nsCOMPtr<nsIDOMNode> *outParent,
        1865                 :                                    PRInt32 *outOffset)
        1866                 : {
        1867               0 :   NS_ASSERTION((inChild && outParent && outOffset), "bad args");
        1868               0 :   nsresult result = NS_ERROR_NULL_POINTER;
        1869               0 :   if (inChild && outParent && outOffset)
        1870                 :   {
        1871               0 :     result = inChild->GetParentNode(getter_AddRefs(*outParent));
        1872               0 :     if ((NS_SUCCEEDED(result)) && (*outParent))
        1873                 :     {
        1874               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(*outParent);
        1875               0 :       nsCOMPtr<nsIContent> cChild = do_QueryInterface(inChild);
        1876               0 :       if (!cChild || !content)
        1877               0 :         return NS_ERROR_NULL_POINTER;
        1878                 :
        1879               0 :       *outOffset = content->IndexOf(cChild);
        1880                 :     }
        1881                 :   }
        1882               0 :   return result;
        1883                 : }
        1884                 :
        1885                 : bool
        1886               0 : nsHTMLCopyEncoder::IsRoot(nsIDOMNode* aNode)
        1887                 : {
        1888               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
        1889               0 :   if (content)
        1890                 :   {
        1891               0 :     if (mIsTextWidget)
        1892               0 :       return (IsTag(content, nsGkAtoms::div));
        1893                 :
        1894               0 :     return (IsTag(content, nsGkAtoms::body) ||
        1895               0 :             IsTag(content, nsGkAtoms::td)   ||
        1896               0 :             IsTag(content, nsGkAtoms::th));
        1897                 :   }
        1898               0 :   return false;
        1899                 : }
        1900                 :
        1901                 : bool
        1902               0 : nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
        1903                 : {
        1904               0 :   nsCOMPtr<nsIDOMNode> parent;
        1905               0 :   PRInt32 offset, j=0;
        1906               0 :   nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
        1907               0 :   if (NS_FAILED(rv))
        1908                 :   {
        1909               0 :     NS_NOTREACHED("failure in IsFirstNode");
        1910               0 :     return false;
        1911                 :   }
        1912               0 :   if (offset == 0)  // easy case, we are first dom child
        1913               0 :     return true;
        1914               0 :   if (!parent)
        1915               0 :     return true;
        1916                 :
        1917                 :   // need to check if any nodes before us are really visible.
        1918                 :   // Mike wrote something for me along these lines in nsSelectionController,
        1919                 :   // but I don't think it's ready for use yet - revisit.
        1920                 :   // HACK: for now, simply consider all whitespace text nodes to be
        1921                 :   // invisible formatting nodes.
        1922               0 :   nsCOMPtr<nsIDOMNodeList> childList;
        1923               0 :   nsCOMPtr<nsIDOMNode> child;
        1924                 :
        1925               0 :   rv = parent->GetChildNodes(getter_AddRefs(childList));
        1926               0 :   if (NS_FAILED(rv) || !childList)
        1927                 :   {
        1928               0 :     NS_NOTREACHED("failure in IsFirstNode");
        1929               0 :     return true;
        1930                 :   }
        1931               0 :   while (j < offset)
        1932                 :   {
        1933               0 :     childList->Item(j, getter_AddRefs(child));
        1934               0 :     if (!IsEmptyTextContent(child))
        1935               0 :       return false;
        1936               0 :     j++;
        1937                 :   }
        1938               0 :   return true;
        1939                 : }
        1940                 :
        1941                 :
        1942                 : bool
        1943               0 : nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
        1944                 : {
        1945               0 :   nsCOMPtr<nsIDOMNode> parent;
        1946                 :   PRInt32 offset,j;
        1947                 :   PRUint32 numChildren;
        1948               0 :   nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
        1949               0 :   if (NS_FAILED(rv))
        1950                 :   {
        1951               0 :     NS_NOTREACHED("failure in IsLastNode");
        1952               0 :     return false;
        1953                 :   }
        1954               0 :   GetLengthOfDOMNode(parent, numChildren);
        1955               0 :   if (offset+1 == (PRInt32)numChildren) // easy case, we are last dom child
        1956               0 :     return true;
        1957               0 :   if (!parent)
        1958               0 :     return true;
        1959                 :   // need to check if any nodes after us are really visible.
        1960                 :   // Mike wrote something for me along these lines in nsSelectionController,
        1961                 :   // but I don't think it's ready for use yet - revisit.
        1962                 :   // HACK: for now, simply consider all whitespace text nodes to be
        1963                 :   // invisible formatting nodes.
        1964               0 :   j = (PRInt32)numChildren-1;
        1965               0 :   nsCOMPtr<nsIDOMNodeList>childList;
        1966               0 :   nsCOMPtr<nsIDOMNode> child;
        1967               0 :   rv = parent->GetChildNodes(getter_AddRefs(childList));
        1968               0 :   if (NS_FAILED(rv) || !childList)
        1969                 :   {
        1970               0 :     NS_NOTREACHED("failure in IsLastNode");
        1971               0 :     return true;
        1972                 :   }
        1973               0 :   while (j > offset)
        1974                 :   {
        1975               0 :     childList->Item(j, getter_AddRefs(child));
        1976               0 :     j--;
        1977               0 :     if (IsMozBR(child))  // we ignore trailing moz BRs.
        1978               0 :       continue;
        1979               0 :     if (!IsEmptyTextContent(child))
        1980               0 :       return false;
        1981                 :   }
        1982               0 :   return true;
        1983                 : }
        1984                 :
        1985                 : bool
        1986               0 : nsHTMLCopyEncoder::IsEmptyTextContent(nsIDOMNode* aNode)
        1987                 : {
        1988               0 :   nsCOMPtr<nsIContent> cont = do_QueryInterface(aNode);
        1989               0 :   return cont && cont->TextIsOnlyWhitespace();
        1990                 : }
        1991                 :
        1992                 : nsresult NS_NewHTMLCopyTextEncoder(nsIDocumentEncoder** aResult); // make mac compiler happy
        1993                 :
        1994                 : nsresult
        1995               0 : NS_NewHTMLCopyTextEncoder(nsIDocumentEncoder** aResult)
        1996                 : {
        1997               0 :   *aResult = new nsHTMLCopyEncoder;
        1998               0 :   if (!*aResult)
        1999               0 :     return NS_ERROR_OUT_OF_MEMORY;
        2000               0 :  NS_ADDREF(*aResult);
        2001               0 :  return NS_OK;
        2002            4392 : }

Generated by: LCOV version 1.7