LCOV - code coverage report
Current view: directory - editor/libeditor/html - nsHTMLDataTransfer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1185 0 0.0 %
Date: 2012-06-02 Functions: 47 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Util.h"
      40                 : 
      41                 : #include "nsHTMLEditor.h"
      42                 : #include "nsHTMLEditRules.h"
      43                 : #include "nsTextEditUtils.h"
      44                 : #include "nsHTMLEditUtils.h"
      45                 : #include "nsWSRunObject.h"
      46                 : 
      47                 : #include "nsIDOMNode.h"
      48                 : #include "nsIDOMDocument.h"
      49                 : #include "nsIDOMComment.h"
      50                 : #include "nsIDOMNodeList.h"
      51                 : #include "nsIDocument.h"
      52                 : #include "nsIDOMMouseEvent.h"
      53                 : #include "nsISelection.h"
      54                 : #include "nsISelectionPrivate.h"
      55                 : #include "nsIDOMHTMLAnchorElement.h"
      56                 : #include "nsIDOMHTMLImageElement.h"
      57                 : #include "nsISelectionController.h"
      58                 : #include "nsIFileChannel.h"
      59                 : 
      60                 : #include "nsIDocumentObserver.h"
      61                 : #include "nsIDocumentStateListener.h"
      62                 : 
      63                 : #include "nsIEnumerator.h"
      64                 : #include "nsIContent.h"
      65                 : #include "nsIContentIterator.h"
      66                 : #include "nsIDOMRange.h"
      67                 : #include "nsIDOMDOMStringList.h"
      68                 : #include "nsIDOMDragEvent.h"
      69                 : #include "nsCOMArray.h"
      70                 : #include "nsIFile.h"
      71                 : #include "nsIURL.h"
      72                 : #include "nsIComponentManager.h"
      73                 : #include "nsIServiceManager.h"
      74                 : #include "nsIDocumentEncoder.h"
      75                 : #include "nsIDOMDocumentFragment.h"
      76                 : #include "nsIPresShell.h"
      77                 : #include "nsPresContext.h"
      78                 : #include "nsIParser.h"
      79                 : #include "nsParserCIID.h"
      80                 : #include "nsXPCOM.h"
      81                 : #include "nsISupportsPrimitives.h"
      82                 : #include "nsLinebreakConverter.h"
      83                 : #include "nsHtml5Module.h"
      84                 : #include "nsTreeSanitizer.h"
      85                 : 
      86                 : // netwerk
      87                 : #include "nsIURI.h"
      88                 : #include "nsNetUtil.h"
      89                 : #include "nsIMIMEService.h"
      90                 : 
      91                 : // Drag & Drop, Clipboard
      92                 : #include "nsIClipboard.h"
      93                 : #include "nsITransferable.h"
      94                 : #include "nsIDragService.h"
      95                 : #include "nsIDOMUIEvent.h"
      96                 : #include "nsIOutputStream.h"
      97                 : #include "nsIInputStream.h"
      98                 : #include "nsDirectoryServiceDefs.h"
      99                 : 
     100                 : // for relativization
     101                 : #include "nsUnicharUtils.h"
     102                 : #include "nsIDOMTreeWalker.h"
     103                 : #include "nsIDOMNodeFilter.h"
     104                 : #include "nsIDOMNamedNodeMap.h"
     105                 : #include "nsIDOMHTMLLinkElement.h"
     106                 : #include "nsIDOMHTMLObjectElement.h"
     107                 : #include "nsIDOMHTMLFrameElement.h"
     108                 : #include "nsIDOMHTMLIFrameElement.h"
     109                 : #include "nsIDOMHTMLInputElement.h"
     110                 : #include "nsIDOMHTMLScriptElement.h"
     111                 : #include "nsIDOMHTMLEmbedElement.h"
     112                 : #include "nsIDOMHTMLTableCellElement.h"
     113                 : #include "nsIDOMHTMLTableRowElement.h"
     114                 : #include "nsIDOMHTMLTableElement.h"
     115                 : #include "nsIDOMHTMLBodyElement.h"
     116                 : 
     117                 : // Misc
     118                 : #include "nsEditorUtils.h"
     119                 : #include "nsIContentFilter.h"
     120                 : #include "nsEventDispatcher.h"
     121                 : #include "plbase64.h"
     122                 : #include "prmem.h"
     123                 : #include "nsStreamUtils.h"
     124                 : #include "nsIPrincipal.h"
     125                 : #include "nsIDocShell.h"
     126                 : #include "nsIDocShellTreeItem.h"
     127                 : #include "nsContentUtils.h"
     128                 : #include "mozilla/Preferences.h"
     129                 : 
     130                 : using namespace mozilla;
     131                 : 
     132                 : const PRUnichar nbsp = 160;
     133                 : 
     134                 : static NS_DEFINE_CID(kCParserCID,     NS_PARSER_CID);
     135                 : 
     136                 : #define kInsertCookie  "_moz_Insert Here_moz_"
     137                 : 
     138                 : #define NS_FOUND_TARGET NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR, 3)
     139                 : 
     140                 : // some little helpers
     141                 : static bool FindIntegerAfterString(const char *aLeadingString, 
     142                 :                                      nsCString &aCStr, PRInt32 &foundNumber);
     143                 : static nsresult RemoveFragComments(nsCString &theStr);
     144                 : static void RemoveBodyAndHead(nsIDOMNode *aNode);
     145                 : static nsresult FindTargetNode(nsIDOMNode *aStart, nsCOMPtr<nsIDOMNode> &aResult);
     146                 : 
     147               0 : static nsCOMPtr<nsIDOMNode> GetListParent(nsIDOMNode* aNode)
     148                 : {
     149               0 :   NS_ENSURE_TRUE(aNode, nsnull);
     150               0 :   nsCOMPtr<nsIDOMNode> parent, tmp;
     151               0 :   aNode->GetParentNode(getter_AddRefs(parent));
     152               0 :   while (parent)
     153                 :   {
     154               0 :     if (nsHTMLEditUtils::IsList(parent)) return parent;
     155               0 :     parent->GetParentNode(getter_AddRefs(tmp));
     156               0 :     parent = tmp;
     157                 :   }
     158               0 :   return nsnull;
     159                 : }
     160                 : 
     161               0 : static nsCOMPtr<nsIDOMNode> GetTableParent(nsIDOMNode* aNode)
     162                 : {
     163               0 :   NS_ENSURE_TRUE(aNode, nsnull);
     164               0 :   nsCOMPtr<nsIDOMNode> parent, tmp;
     165               0 :   aNode->GetParentNode(getter_AddRefs(parent));
     166               0 :   while (parent)
     167                 :   {
     168               0 :     if (nsHTMLEditUtils::IsTable(parent)) return parent;
     169               0 :     parent->GetParentNode(getter_AddRefs(tmp));
     170               0 :     parent = tmp;
     171                 :   }
     172               0 :   return nsnull;
     173                 : }
     174                 : 
     175                 : 
     176               0 : NS_IMETHODIMP nsHTMLEditor::LoadHTML(const nsAString & aInputString)
     177                 : {
     178               0 :   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
     179                 : 
     180                 :   // force IME commit; set up rules sniffing and batching
     181               0 :   ForceCompositionEnd();
     182               0 :   nsAutoEditBatch beginBatching(this);
     183               0 :   nsAutoRules beginRulesSniffing(this, kOpLoadHTML, nsIEditor::eNext);
     184                 :   
     185                 :   // Get selection
     186               0 :   nsCOMPtr<nsISelection>selection;
     187               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
     188               0 :   NS_ENSURE_SUCCESS(res, res);
     189                 :   
     190               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kLoadHTML);
     191                 :   bool cancel, handled;
     192               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     193               0 :   NS_ENSURE_SUCCESS(res, res);
     194               0 :   if (cancel) return NS_OK; // rules canceled the operation
     195               0 :   if (!handled)
     196                 :   {
     197                 :     bool isCollapsed;
     198               0 :     res = selection->GetIsCollapsed(&isCollapsed);
     199               0 :     NS_ENSURE_SUCCESS(res, res);
     200                 : 
     201                 :     // Delete Selection, but only if it isn't collapsed, see bug #106269
     202               0 :     if (!isCollapsed) 
     203                 :     {
     204               0 :       res = DeleteSelection(eNone);
     205               0 :       NS_ENSURE_SUCCESS(res, res);
     206                 :     }
     207                 : 
     208                 :     // Get the first range in the selection, for context:
     209               0 :     nsCOMPtr<nsIDOMRange> range;
     210               0 :     res = selection->GetRangeAt(0, getter_AddRefs(range));
     211               0 :     NS_ENSURE_SUCCESS(res, res);
     212               0 :     NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
     213                 : 
     214                 :     // create fragment for pasted html
     215               0 :     nsCOMPtr<nsIDOMDocumentFragment> docfrag;
     216                 :     {
     217               0 :       res = range->CreateContextualFragment(aInputString, getter_AddRefs(docfrag));
     218               0 :       NS_ENSURE_SUCCESS(res, res);
     219                 :     }
     220                 :     // put the fragment into the document
     221               0 :     nsCOMPtr<nsIDOMNode> parent, junk;
     222               0 :     res = range->GetStartContainer(getter_AddRefs(parent));
     223               0 :     NS_ENSURE_SUCCESS(res, res);
     224               0 :     NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
     225                 :     PRInt32 childOffset;
     226               0 :     res = range->GetStartOffset(&childOffset);
     227               0 :     NS_ENSURE_SUCCESS(res, res);
     228                 : 
     229               0 :     nsCOMPtr<nsIDOMNode> nodeToInsert;
     230               0 :     docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
     231               0 :     while (nodeToInsert)
     232                 :     {
     233               0 :       res = InsertNode(nodeToInsert, parent, childOffset++);
     234               0 :       NS_ENSURE_SUCCESS(res, res);
     235               0 :       docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
     236                 :     }
     237                 :   }
     238                 : 
     239               0 :   return mRules->DidDoAction(selection, &ruleInfo, res);
     240                 : }
     241                 : 
     242                 : 
     243               0 : NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsAString & aInString)
     244                 : {
     245               0 :   const nsAFlatString& empty = EmptyString();
     246                 : 
     247                 :   return InsertHTMLWithContext(aInString, empty, empty, empty,
     248               0 :                                nsnull,  nsnull, 0, true);
     249                 : }
     250                 : 
     251                 : 
     252                 : nsresult
     253               0 : nsHTMLEditor::InsertHTMLWithContext(const nsAString & aInputString,
     254                 :                                     const nsAString & aContextStr,
     255                 :                                     const nsAString & aInfoStr,
     256                 :                                     const nsAString & aFlavor,
     257                 :                                     nsIDOMDocument *aSourceDoc,
     258                 :                                     nsIDOMNode *aDestNode,
     259                 :                                     PRInt32 aDestOffset,
     260                 :                                     bool aDeleteSelection)
     261                 : {
     262                 :   return DoInsertHTMLWithContext(aInputString, aContextStr, aInfoStr,
     263                 :       aFlavor, aSourceDoc, aDestNode, aDestOffset, aDeleteSelection,
     264               0 :       true);
     265                 : }
     266                 : 
     267                 : nsresult
     268               0 : nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
     269                 :                                       const nsAString & aContextStr,
     270                 :                                       const nsAString & aInfoStr,
     271                 :                                       const nsAString & aFlavor,
     272                 :                                       nsIDOMDocument *aSourceDoc,
     273                 :                                       nsIDOMNode *aDestNode,
     274                 :                                       PRInt32 aDestOffset,
     275                 :                                       bool aDeleteSelection,
     276                 :                                       bool aTrustedInput)
     277                 : {
     278               0 :   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
     279                 : 
     280                 :   // force IME commit; set up rules sniffing and batching
     281               0 :   ForceCompositionEnd();
     282               0 :   nsAutoEditBatch beginBatching(this);
     283               0 :   nsAutoRules beginRulesSniffing(this, kOpHTMLPaste, nsIEditor::eNext);
     284                 :   
     285                 :   // Get selection
     286                 :   nsresult res;
     287               0 :   nsCOMPtr<nsISelection>selection;
     288               0 :   res = GetSelection(getter_AddRefs(selection));
     289               0 :   NS_ENSURE_SUCCESS(res, res);
     290                 :   
     291                 :   // create a dom document fragment that represents the structure to paste
     292               0 :   nsCOMPtr<nsIDOMNode> fragmentAsNode, streamStartParent, streamEndParent;
     293               0 :   PRInt32 streamStartOffset = 0, streamEndOffset = 0;
     294                 : 
     295                 :   res = CreateDOMFragmentFromPaste(aInputString, aContextStr, aInfoStr, 
     296                 :                                    address_of(fragmentAsNode),
     297                 :                                    address_of(streamStartParent),
     298                 :                                    address_of(streamEndParent),
     299                 :                                    &streamStartOffset,
     300                 :                                    &streamEndOffset,
     301               0 :                                    aTrustedInput);
     302               0 :   NS_ENSURE_SUCCESS(res, res);
     303                 : 
     304               0 :   nsCOMPtr<nsIDOMNode> targetNode, tempNode;
     305               0 :   PRInt32 targetOffset=0;
     306                 : 
     307               0 :   if (!aDestNode)
     308                 :   {
     309                 :     // if caller didn't provide the destination/target node,
     310                 :     // fetch the paste insertion point from our selection
     311               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(targetNode), &targetOffset);
     312               0 :     if (!targetNode) res = NS_ERROR_FAILURE;
     313               0 :     NS_ENSURE_SUCCESS(res, res);
     314                 :   }
     315                 :   else
     316                 :   {
     317               0 :     targetNode = aDestNode;
     318               0 :     targetOffset = aDestOffset;
     319                 :   }
     320                 : 
     321               0 :   bool doContinue = true;
     322                 : 
     323                 :   res = DoContentFilterCallback(aFlavor, aSourceDoc, aDeleteSelection,
     324               0 :                                 (nsIDOMNode **)address_of(fragmentAsNode), 
     325               0 :                                 (nsIDOMNode **)address_of(streamStartParent), 
     326                 :                                 &streamStartOffset,
     327               0 :                                 (nsIDOMNode **)address_of(streamEndParent),
     328                 :                                 &streamEndOffset, 
     329               0 :                                 (nsIDOMNode **)address_of(targetNode), 
     330               0 :                                 &targetOffset, &doContinue);
     331                 : 
     332               0 :   NS_ENSURE_SUCCESS(res, res);
     333               0 :   NS_ENSURE_TRUE(doContinue, NS_OK);
     334                 : 
     335                 :   // if we have a destination / target node, we want to insert there
     336                 :   // rather than in place of the selection
     337                 :   // ignore aDeleteSelection here if no aDestNode since deletion will
     338                 :   // also occur later; this block is intended to cover the various
     339                 :   // scenarios where we are dropping in an editor (and may want to delete
     340                 :   // the selection before collapsing the selection in the new destination)
     341               0 :   if (aDestNode)
     342                 :   {
     343               0 :     if (aDeleteSelection)
     344                 :     {
     345                 :       // Use an auto tracker so that our drop point is correctly
     346                 :       // positioned after the delete.
     347               0 :       nsAutoTrackDOMPoint tracker(mRangeUpdater, &targetNode, &targetOffset);
     348               0 :       res = DeleteSelection(eNone);
     349               0 :       NS_ENSURE_SUCCESS(res, res);
     350                 :     }
     351                 : 
     352               0 :     res = selection->Collapse(targetNode, targetOffset);
     353               0 :     NS_ENSURE_SUCCESS(res, res);
     354                 :   }
     355                 : 
     356                 :   // we need to recalculate various things based on potentially new offsets
     357                 :   // this is work to be completed at a later date (probably by jfrancis)
     358                 : 
     359                 :   // make a list of what nodes in docFrag we need to move
     360               0 :   nsCOMArray<nsIDOMNode> nodeList;
     361                 :   res = CreateListOfNodesToPaste(fragmentAsNode, nodeList,
     362                 :                                  streamStartParent, streamStartOffset,
     363               0 :                                  streamEndParent, streamEndOffset);
     364               0 :   NS_ENSURE_SUCCESS(res, res);
     365                 : 
     366               0 :   if (nodeList.Count() == 0)
     367               0 :     return NS_OK;
     368                 : 
     369                 :   // are there any table elements in the list?  
     370                 :   // node and offset for insertion
     371               0 :   nsCOMPtr<nsIDOMNode> parentNode;
     372                 :   PRInt32 offsetOfNewNode;
     373                 :   
     374                 :   // check for table cell selection mode
     375               0 :   bool cellSelectionMode = false;
     376               0 :   nsCOMPtr<nsIDOMElement> cell;
     377               0 :   res = GetFirstSelectedCell(nsnull, getter_AddRefs(cell));
     378               0 :   if (NS_SUCCEEDED(res) && cell)
     379                 :   {
     380               0 :     cellSelectionMode = true;
     381                 :   }
     382                 :   
     383               0 :   if (cellSelectionMode)
     384                 :   {
     385                 :     // do we have table content to paste?  If so, we want to delete
     386                 :     // the selected table cells and replace with new table elements;
     387                 :     // but if not we want to delete _contents_ of cells and replace
     388                 :     // with non-table elements.  Use cellSelectionMode bool to 
     389                 :     // indicate results.
     390               0 :     nsIDOMNode* firstNode = nodeList[0];
     391               0 :     if (!nsHTMLEditUtils::IsTableElement(firstNode))
     392               0 :       cellSelectionMode = false;
     393                 :   }
     394                 : 
     395               0 :   if (!cellSelectionMode)
     396                 :   {
     397               0 :     res = DeleteSelectionAndPrepareToCreateNode(parentNode, offsetOfNewNode);
     398               0 :     NS_ENSURE_SUCCESS(res, res);
     399                 : 
     400                 :     // pasting does not inherit local inline styles
     401               0 :     res = RemoveAllInlineProperties();
     402               0 :     NS_ENSURE_SUCCESS(res, res);
     403                 :   }
     404                 :   else
     405                 :   {
     406                 :     // delete whole cells: we will replace with new table content
     407                 :     if (1)
     408                 :     {
     409                 :       // Save current selection since DeleteTableCell perturbs it
     410               0 :       nsAutoSelectionReset selectionResetter(selection, this);
     411               0 :       res = DeleteTableCell(1);
     412               0 :       NS_ENSURE_SUCCESS(res, res);
     413                 :     }
     414                 :     // collapse selection to beginning of deleted table content
     415               0 :     selection->CollapseToStart();
     416                 :   }
     417                 :   
     418                 :   // give rules a chance to handle or cancel
     419               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
     420                 :   bool cancel, handled;
     421               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     422               0 :   NS_ENSURE_SUCCESS(res, res);
     423               0 :   if (cancel) return NS_OK; // rules canceled the operation
     424               0 :   if (!handled)
     425                 :   {
     426                 :     // The rules code (WillDoAction above) might have changed the selection.  
     427                 :     // refresh our memory...
     428               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(parentNode), &offsetOfNewNode);
     429               0 :     if (!parentNode) res = NS_ERROR_FAILURE;
     430               0 :     NS_ENSURE_SUCCESS(res, res);
     431                 : 
     432                 :     // Adjust position based on the first node we are going to insert.
     433               0 :     NormalizeEOLInsertPosition(nodeList[0], address_of(parentNode), &offsetOfNewNode);
     434                 : 
     435                 :     // if there are any invisible br's after our insertion point, remove them.
     436                 :     // this is because if there is a br at end of what we paste, it will make
     437                 :     // the invisible br visible.
     438               0 :     nsWSRunObject wsObj(this, parentNode, offsetOfNewNode);
     439               0 :     if (nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) && 
     440               0 :         !IsVisBreak(wsObj.mEndReasonNode) )
     441                 :     {
     442               0 :       res = DeleteNode(wsObj.mEndReasonNode);
     443               0 :       NS_ENSURE_SUCCESS(res, res);
     444                 :     }
     445                 :     
     446                 :     // remeber if we are in a link.  
     447               0 :     bool bStartedInLink = IsInLink(parentNode);
     448                 :   
     449                 :     // are we in a text node?  If so, split it.
     450               0 :     if (IsTextNode(parentNode))
     451                 :     {
     452               0 :       nsCOMPtr<nsIDOMNode> temp;
     453               0 :       res = SplitNodeDeep(parentNode, parentNode, offsetOfNewNode, &offsetOfNewNode);
     454               0 :       NS_ENSURE_SUCCESS(res, res);
     455               0 :       res = parentNode->GetParentNode(getter_AddRefs(temp));
     456               0 :       NS_ENSURE_SUCCESS(res, res);
     457               0 :       parentNode = temp;
     458                 :     }
     459                 : 
     460                 :     // build up list of parents of first node in list that are either
     461                 :     // lists or tables.  First examine front of paste node list.
     462               0 :     nsCOMArray<nsIDOMNode> startListAndTableArray;
     463               0 :     res = GetListAndTableParents(false, nodeList, startListAndTableArray);
     464               0 :     NS_ENSURE_SUCCESS(res, res);
     465                 :     
     466                 :     // remember number of lists and tables above us
     467               0 :     PRInt32 highWaterMark = -1;
     468               0 :     if (startListAndTableArray.Count() > 0)
     469                 :     {
     470               0 :       res = DiscoverPartialListsAndTables(nodeList, startListAndTableArray, &highWaterMark);
     471               0 :       NS_ENSURE_SUCCESS(res, res);
     472                 :     }
     473                 : 
     474                 :     // if we have pieces of tables or lists to be inserted, let's force the paste 
     475                 :     // to deal with table elements right away, so that it doesn't orphan some 
     476                 :     // table or list contents outside the table or list.
     477               0 :     if (highWaterMark >= 0)
     478                 :     {
     479               0 :       res = ReplaceOrphanedStructure(false, nodeList, startListAndTableArray, highWaterMark);
     480               0 :       NS_ENSURE_SUCCESS(res, res);
     481                 :     }
     482                 :     
     483                 :     // Now go through the same process again for the end of the paste node list.
     484               0 :     nsCOMArray<nsIDOMNode> endListAndTableArray;
     485               0 :     res = GetListAndTableParents(true, nodeList, endListAndTableArray);
     486               0 :     NS_ENSURE_SUCCESS(res, res);
     487               0 :     highWaterMark = -1;
     488                 :    
     489                 :     // remember number of lists and tables above us
     490               0 :     if (endListAndTableArray.Count() > 0)
     491                 :     {
     492               0 :       res = DiscoverPartialListsAndTables(nodeList, endListAndTableArray, &highWaterMark);
     493               0 :       NS_ENSURE_SUCCESS(res, res);
     494                 :     }
     495                 :     
     496                 :     // don't orphan partial list or table structure
     497               0 :     if (highWaterMark >= 0)
     498                 :     {
     499               0 :       res = ReplaceOrphanedStructure(true, nodeList, endListAndTableArray, highWaterMark);
     500               0 :       NS_ENSURE_SUCCESS(res, res);
     501                 :     }
     502                 : 
     503                 :     // Loop over the node list and paste the nodes:
     504               0 :     nsCOMPtr<nsIDOMNode> parentBlock, lastInsertNode, insertedContextParent;
     505               0 :     PRInt32 listCount = nodeList.Count();
     506                 :     PRInt32 j;
     507               0 :     if (IsBlockNode(parentNode))
     508               0 :       parentBlock = parentNode;
     509                 :     else
     510               0 :       parentBlock = GetBlockNodeParent(parentNode);
     511                 :       
     512               0 :     for (j=0; j<listCount; j++)
     513                 :     {
     514               0 :       bool bDidInsert = false;
     515               0 :       nsCOMPtr<nsIDOMNode> curNode = nodeList[j];
     516                 : 
     517               0 :       NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
     518               0 :       NS_ENSURE_TRUE(curNode != fragmentAsNode, NS_ERROR_FAILURE);
     519               0 :       NS_ENSURE_TRUE(!nsTextEditUtils::IsBody(curNode), NS_ERROR_FAILURE);
     520                 :       
     521               0 :       if (insertedContextParent)
     522                 :       {
     523                 :         // if we had to insert something higher up in the paste hierarchy, we want to 
     524                 :         // skip any further paste nodes that descend from that.  Else we will paste twice.
     525               0 :         if (nsEditorUtils::IsDescendantOf(curNode, insertedContextParent))
     526               0 :           continue;
     527                 :       }
     528                 :       
     529                 :       // give the user a hand on table element insertion.  if they have
     530                 :       // a table or table row on the clipboard, and are trying to insert
     531                 :       // into a table or table row, insert the appropriate children instead.
     532               0 :       if (  (nsHTMLEditUtils::IsTableRow(curNode) && nsHTMLEditUtils::IsTableRow(parentNode))
     533               0 :          && (nsHTMLEditUtils::IsTable(curNode)    || nsHTMLEditUtils::IsTable(parentNode)) )
     534                 :       {
     535               0 :         nsCOMPtr<nsIDOMNode> child;
     536               0 :         curNode->GetFirstChild(getter_AddRefs(child));
     537               0 :         while (child)
     538                 :         {
     539               0 :           res = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, true);
     540               0 :           if (NS_FAILED(res))
     541               0 :             break;
     542                 : 
     543               0 :           bDidInsert = true;
     544               0 :           lastInsertNode = child;
     545               0 :           offsetOfNewNode++;
     546                 : 
     547               0 :           curNode->GetFirstChild(getter_AddRefs(child));
     548                 :         }
     549                 :       }
     550                 :       // give the user a hand on list insertion.  if they have
     551                 :       // a list on the clipboard, and are trying to insert
     552                 :       // into a list or list item, insert the appropriate children instead,
     553                 :       // ie, merge the lists instead of pasting in a sublist.
     554               0 :       else if (nsHTMLEditUtils::IsList(curNode) && 
     555               0 :               (nsHTMLEditUtils::IsList(parentNode)  || nsHTMLEditUtils::IsListItem(parentNode)) )
     556                 :       {
     557               0 :         nsCOMPtr<nsIDOMNode> child, tmp;
     558               0 :         curNode->GetFirstChild(getter_AddRefs(child));
     559               0 :         while (child)
     560                 :         {
     561               0 :           if (nsHTMLEditUtils::IsListItem(child) || nsHTMLEditUtils::IsList(child))
     562                 :           {
     563                 :             // check if we are pasting into empty list item. If so
     564                 :             // delete it and paste into parent list instead.
     565               0 :             if (nsHTMLEditUtils::IsListItem(parentNode))
     566                 :             {
     567                 :               bool isEmpty;
     568               0 :               res = IsEmptyNode(parentNode, &isEmpty, true);
     569               0 :               if ((NS_SUCCEEDED(res)) && isEmpty)
     570                 :               {
     571               0 :                 nsCOMPtr<nsIDOMNode> listNode;
     572                 :                 PRInt32 newOffset;
     573               0 :                 GetNodeLocation(parentNode, address_of(listNode), &newOffset);
     574               0 :                 if (listNode)
     575                 :                 {
     576               0 :                   DeleteNode(parentNode);
     577               0 :                   parentNode = listNode;
     578               0 :                   offsetOfNewNode = newOffset;
     579                 :                 }
     580                 :               }
     581                 :             } 
     582               0 :             res = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, true);
     583               0 :             if (NS_FAILED(res))
     584               0 :               break;
     585                 : 
     586               0 :             bDidInsert = true;
     587               0 :             lastInsertNode = child;
     588               0 :             offsetOfNewNode++;
     589                 :           }
     590                 :           else
     591                 :           {
     592               0 :             curNode->RemoveChild(child, getter_AddRefs(tmp));
     593                 :           }
     594               0 :           curNode->GetFirstChild(getter_AddRefs(child));
     595                 :         }
     596                 :         
     597                 :       }
     598                 :       // check for pre's going into pre's.  
     599               0 :       else if (nsHTMLEditUtils::IsPre(parentBlock) && nsHTMLEditUtils::IsPre(curNode))
     600                 :       {
     601               0 :         nsCOMPtr<nsIDOMNode> child, tmp;
     602               0 :         curNode->GetFirstChild(getter_AddRefs(child));
     603               0 :         while (child)
     604                 :         {
     605               0 :           res = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, true);
     606               0 :           if (NS_FAILED(res))
     607               0 :             break;
     608                 : 
     609               0 :           bDidInsert = true;
     610               0 :           lastInsertNode = child;
     611               0 :           offsetOfNewNode++;
     612                 : 
     613               0 :           curNode->GetFirstChild(getter_AddRefs(child));
     614                 :         }
     615                 :       }
     616                 : 
     617               0 :       if (!bDidInsert || NS_FAILED(res))
     618                 :       {
     619                 :         // try to insert
     620               0 :         res = InsertNodeAtPoint(curNode, address_of(parentNode), &offsetOfNewNode, true);
     621               0 :         if (NS_SUCCEEDED(res)) 
     622                 :         {
     623               0 :           bDidInsert = true;
     624               0 :           lastInsertNode = curNode;
     625                 :         }
     626                 : 
     627                 :         // Assume failure means no legal parent in the document hierarchy,
     628                 :         // try again with the parent of curNode in the paste hierarchy.
     629               0 :         nsCOMPtr<nsIDOMNode> parent;
     630               0 :         while (NS_FAILED(res) && curNode)
     631                 :         {
     632               0 :           curNode->GetParentNode(getter_AddRefs(parent));
     633               0 :           if (parent && !nsTextEditUtils::IsBody(parent))
     634                 :           {
     635               0 :             res = InsertNodeAtPoint(parent, address_of(parentNode), &offsetOfNewNode, true);
     636               0 :             if (NS_SUCCEEDED(res)) 
     637                 :             {
     638               0 :               bDidInsert = true;
     639               0 :               insertedContextParent = parent;
     640               0 :               lastInsertNode = GetChildAt(parentNode, offsetOfNewNode);
     641                 :             }
     642                 :           }
     643               0 :           curNode = parent;
     644                 :         }
     645                 :       }
     646               0 :       if (lastInsertNode)
     647                 :       {
     648               0 :         res = GetNodeLocation(lastInsertNode, address_of(parentNode), &offsetOfNewNode);
     649               0 :         NS_ENSURE_SUCCESS(res, res);
     650               0 :         offsetOfNewNode++;
     651                 :       }
     652                 :     }
     653                 : 
     654                 :     // Now collapse the selection to the end of what we just inserted:
     655               0 :     if (lastInsertNode) 
     656                 :     {
     657                 :       // set selection to the end of what we just pasted.
     658               0 :       nsCOMPtr<nsIDOMNode> selNode, tmp, visNode, highTable;
     659                 :       PRInt32 selOffset;
     660                 :       
     661                 :       // but don't cross tables
     662               0 :       if (!nsHTMLEditUtils::IsTable(lastInsertNode))
     663                 :       {
     664               0 :         res = GetLastEditableLeaf(lastInsertNode, address_of(selNode));
     665               0 :         NS_ENSURE_SUCCESS(res, res);
     666               0 :         tmp = selNode;
     667               0 :         while (tmp && (tmp != lastInsertNode))
     668                 :         {
     669               0 :           if (nsHTMLEditUtils::IsTable(tmp))
     670               0 :             highTable = tmp;
     671               0 :           nsCOMPtr<nsIDOMNode> parent = tmp;
     672               0 :           tmp->GetParentNode(getter_AddRefs(parent));
     673               0 :           tmp = parent;
     674                 :         }
     675               0 :         if (highTable)
     676               0 :           selNode = highTable;
     677                 :       }
     678               0 :       if (!selNode) 
     679               0 :         selNode = lastInsertNode;
     680               0 :       if (IsTextNode(selNode) || (IsContainer(selNode) && !nsHTMLEditUtils::IsTable(selNode)))  
     681                 :       {
     682               0 :         res = GetLengthOfDOMNode(selNode, (PRUint32&)selOffset);
     683               0 :         NS_ENSURE_SUCCESS(res, res);
     684                 :       }
     685                 :       else // we need to find a container for selection.  Look up.
     686                 :       {
     687               0 :         tmp = selNode;
     688               0 :         res = GetNodeLocation(tmp, address_of(selNode), &selOffset);
     689               0 :         ++selOffset;  // want to be *after* last leaf node in paste
     690               0 :         NS_ENSURE_SUCCESS(res, res);
     691                 :       }
     692                 :       
     693                 :       // make sure we don't end up with selection collapsed after an invisible break node
     694               0 :       nsWSRunObject wsRunObj(this, selNode, selOffset);
     695               0 :       PRInt32 outVisOffset=0;
     696               0 :       PRInt16 visType=0;
     697               0 :       res = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType);
     698               0 :       NS_ENSURE_SUCCESS(res, res);
     699               0 :       if (visType == nsWSRunObject::eBreak)
     700                 :       {
     701                 :         // we are after a break.  Is it visible?  Despite the name, 
     702                 :         // PriorVisibleNode does not make that determination for breaks.
     703                 :         // It also may not return the break in visNode.  We have to pull it
     704                 :         // out of the nsWSRunObject's state.
     705               0 :         if (!IsVisBreak(wsRunObj.mStartReasonNode))
     706                 :         {
     707                 :           // don't leave selection past an invisible break;
     708                 :           // reset {selNode,selOffset} to point before break
     709               0 :           res = GetNodeLocation(wsRunObj.mStartReasonNode, address_of(selNode), &selOffset);
     710                 :           // we want to be inside any inline style prior to break
     711               0 :           nsWSRunObject wsRunObj(this, selNode, selOffset);
     712               0 :           res = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType);
     713               0 :           NS_ENSURE_SUCCESS(res, res);
     714               0 :           if (visType == nsWSRunObject::eText ||
     715                 :               visType == nsWSRunObject::eNormalWS)
     716                 :           {
     717               0 :             selNode = visNode;
     718               0 :             selOffset = outVisOffset;  // PriorVisibleNode already set offset to _after_ the text or ws
     719                 :           }
     720               0 :           else if (visType == nsWSRunObject::eSpecial)
     721                 :           {
     722                 :             // prior visible thing is an image or some other non-text thingy.  
     723                 :             // We want to be right after it.
     724               0 :             res = GetNodeLocation(wsRunObj.mStartReasonNode, address_of(selNode), &selOffset);
     725               0 :             ++selOffset;
     726                 :           }
     727                 :         }
     728                 :       }
     729               0 :       selection->Collapse(selNode, selOffset);
     730                 :       
     731                 :       // if we just pasted a link, discontinue link style
     732               0 :       nsCOMPtr<nsIDOMNode> link;
     733               0 :       if (!bStartedInLink && IsInLink(selNode, address_of(link)))
     734                 :       {
     735                 :         // so, if we just pasted a link, I split it.  Why do that instead of just
     736                 :         // nudging selection point beyond it?  Because it might have ended in a BR
     737                 :         // that is not visible.  If so, the code above just placed selection
     738                 :         // inside that.  So I split it instead.
     739               0 :         nsCOMPtr<nsIDOMNode> leftLink;
     740                 :         PRInt32 linkOffset;
     741               0 :         res = SplitNodeDeep(link, selNode, selOffset, &linkOffset, true, address_of(leftLink));
     742               0 :         NS_ENSURE_SUCCESS(res, res);
     743               0 :         res = GetNodeLocation(leftLink, address_of(selNode), &selOffset);
     744               0 :         NS_ENSURE_SUCCESS(res, res);
     745               0 :         selection->Collapse(selNode, selOffset+1);
     746                 :       }
     747                 :     }
     748                 :   }
     749                 :   
     750               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
     751               0 :   return res;
     752                 : }
     753                 : 
     754                 : // returns empty string if nothing to modify on node
     755                 : nsresult
     756               0 : nsHTMLEditor::GetAttributeToModifyOnNode(nsIDOMNode *aNode, nsAString &aAttr)
     757                 : {
     758               0 :   aAttr.Truncate();
     759                 : 
     760               0 :   NS_NAMED_LITERAL_STRING(srcStr, "src");
     761               0 :   nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNode);
     762               0 :   if (nodeAsImage)
     763                 :   {
     764               0 :     aAttr = srcStr;
     765               0 :     return NS_OK;
     766                 :   }
     767                 : 
     768               0 :   nsCOMPtr<nsIDOMHTMLAnchorElement> nodeAsAnchor = do_QueryInterface(aNode);
     769               0 :   if (nodeAsAnchor)
     770                 :   {
     771               0 :     aAttr.AssignLiteral("href");
     772               0 :     return NS_OK;
     773                 :   }
     774                 : 
     775               0 :   NS_NAMED_LITERAL_STRING(bgStr, "background");
     776               0 :   nsCOMPtr<nsIDOMHTMLBodyElement> nodeAsBody = do_QueryInterface(aNode);
     777               0 :   if (nodeAsBody)
     778                 :   {
     779               0 :     aAttr = bgStr;
     780               0 :     return NS_OK;
     781                 :   }
     782                 : 
     783               0 :   nsCOMPtr<nsIDOMHTMLTableElement> nodeAsTable = do_QueryInterface(aNode);
     784               0 :   if (nodeAsTable)
     785                 :   {
     786               0 :     aAttr = bgStr;
     787               0 :     return NS_OK;
     788                 :   }
     789                 : 
     790               0 :   nsCOMPtr<nsIDOMHTMLTableRowElement> nodeAsTableRow = do_QueryInterface(aNode);
     791               0 :   if (nodeAsTableRow)
     792                 :   {
     793               0 :     aAttr = bgStr;
     794               0 :     return NS_OK;
     795                 :   }
     796                 : 
     797               0 :   nsCOMPtr<nsIDOMHTMLTableCellElement> nodeAsTableCell = do_QueryInterface(aNode);
     798               0 :   if (nodeAsTableCell)
     799                 :   {
     800               0 :     aAttr = bgStr;
     801               0 :     return NS_OK;
     802                 :   }
     803                 : 
     804               0 :   nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNode);
     805               0 :   if (nodeAsScript)
     806                 :   {
     807               0 :     aAttr = srcStr;
     808               0 :     return NS_OK;
     809                 :   }
     810                 :   
     811               0 :   nsCOMPtr<nsIDOMHTMLEmbedElement> nodeAsEmbed = do_QueryInterface(aNode);
     812               0 :   if (nodeAsEmbed)
     813                 :   {
     814               0 :     aAttr = srcStr;
     815               0 :     return NS_OK;
     816                 :   }
     817                 :   
     818               0 :   nsCOMPtr<nsIDOMHTMLObjectElement> nodeAsObject = do_QueryInterface(aNode);
     819               0 :   if (nodeAsObject)
     820                 :   {
     821               0 :     aAttr.AssignLiteral("data");
     822               0 :     return NS_OK;
     823                 :   }
     824                 :   
     825               0 :   nsCOMPtr<nsIDOMHTMLLinkElement> nodeAsLink = do_QueryInterface(aNode);
     826               0 :   if (nodeAsLink)
     827                 :   {
     828                 :     // Test if the link has a rel value indicating it to be a stylesheet
     829               0 :     nsAutoString linkRel;
     830               0 :     if (NS_SUCCEEDED(nodeAsLink->GetRel(linkRel)) && !linkRel.IsEmpty())
     831                 :     {
     832               0 :       nsReadingIterator<PRUnichar> start;
     833               0 :       nsReadingIterator<PRUnichar> end;
     834               0 :       nsReadingIterator<PRUnichar> current;
     835                 : 
     836               0 :       linkRel.BeginReading(start);
     837               0 :       linkRel.EndReading(end);
     838                 : 
     839                 :       // Walk through space delimited string looking for "stylesheet"
     840               0 :       for (current = start; current != end; ++current)
     841                 :       {
     842                 :         // Ignore whitespace
     843               0 :         if (nsCRT::IsAsciiSpace(*current))
     844               0 :           continue;
     845                 : 
     846                 :         // Grab the next space delimited word
     847               0 :         nsReadingIterator<PRUnichar> startWord = current;
     848               0 :         do {
     849               0 :           ++current;
     850               0 :         } while (current != end && !nsCRT::IsAsciiSpace(*current));
     851                 : 
     852                 :         // Store the link for fix up if it says "stylesheet"
     853               0 :         if (Substring(startWord, current).LowerCaseEqualsLiteral("stylesheet"))
     854                 :         {
     855               0 :           aAttr.AssignLiteral("href");
     856               0 :           return NS_OK;
     857                 :         }
     858               0 :         if (current == end)
     859               0 :           break;
     860                 :       }
     861                 :     }
     862               0 :     return NS_OK;
     863                 :   }
     864                 : 
     865               0 :   nsCOMPtr<nsIDOMHTMLFrameElement> nodeAsFrame = do_QueryInterface(aNode);
     866               0 :   if (nodeAsFrame)
     867                 :   {
     868               0 :     aAttr = srcStr;
     869               0 :     return NS_OK;
     870                 :   }
     871                 : 
     872               0 :   nsCOMPtr<nsIDOMHTMLIFrameElement> nodeAsIFrame = do_QueryInterface(aNode);
     873               0 :   if (nodeAsIFrame)
     874                 :   {
     875               0 :     aAttr = srcStr;
     876               0 :     return NS_OK;
     877                 :   }
     878                 : 
     879               0 :   nsCOMPtr<nsIDOMHTMLInputElement> nodeAsInput = do_QueryInterface(aNode);
     880               0 :   if (nodeAsInput)
     881                 :   {
     882               0 :     aAttr = srcStr;
     883               0 :     return NS_OK;
     884                 :   }
     885                 : 
     886               0 :   return NS_OK;
     887                 : }
     888                 : 
     889                 : nsresult
     890               0 : nsHTMLEditor::AddInsertionListener(nsIContentFilter *aListener)
     891                 : {
     892               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
     893                 : 
     894                 :   // don't let a listener be added more than once
     895               0 :   if (mContentFilters.IndexOfObject(aListener) == -1)
     896                 :   {
     897               0 :     if (!mContentFilters.AppendObject(aListener))
     898               0 :       return NS_ERROR_FAILURE;
     899                 :   }
     900                 : 
     901               0 :   return NS_OK;
     902                 : }
     903                 :  
     904                 : nsresult
     905               0 : nsHTMLEditor::RemoveInsertionListener(nsIContentFilter *aListener)
     906                 : {
     907               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
     908                 : 
     909               0 :   if (!mContentFilters.RemoveObject(aListener))
     910               0 :     return NS_ERROR_FAILURE;
     911                 : 
     912               0 :   return NS_OK;
     913                 : }
     914                 :  
     915                 : nsresult
     916               0 : nsHTMLEditor::DoContentFilterCallback(const nsAString &aFlavor, 
     917                 :                                       nsIDOMDocument *sourceDoc,
     918                 :                                       bool aWillDeleteSelection,
     919                 :                                       nsIDOMNode **aFragmentAsNode, 
     920                 :                                       nsIDOMNode **aFragStartNode, 
     921                 :                                       PRInt32 *aFragStartOffset,
     922                 :                                       nsIDOMNode **aFragEndNode, 
     923                 :                                       PRInt32 *aFragEndOffset,
     924                 :                                       nsIDOMNode **aTargetNode,
     925                 :                                       PRInt32 *aTargetOffset,
     926                 :                                       bool *aDoContinue)
     927                 : {
     928               0 :   *aDoContinue = true;
     929                 : 
     930                 :   PRInt32 i;
     931                 :   nsIContentFilter *listener;
     932               0 :   for (i=0; i < mContentFilters.Count() && *aDoContinue; i++)
     933                 :   {
     934               0 :     listener = (nsIContentFilter *)mContentFilters[i];
     935               0 :     if (listener)
     936                 :       listener->NotifyOfInsertion(aFlavor, nsnull, sourceDoc,
     937                 :                                   aWillDeleteSelection, aFragmentAsNode,
     938                 :                                   aFragStartNode, aFragStartOffset, 
     939                 :                                   aFragEndNode, aFragEndOffset,
     940               0 :                                   aTargetNode, aTargetOffset, aDoContinue);
     941                 :   }
     942                 : 
     943               0 :   return NS_OK;
     944                 : }
     945                 : 
     946                 : bool
     947               0 : nsHTMLEditor::IsInLink(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *outLink)
     948                 : {
     949               0 :   NS_ENSURE_TRUE(aNode, false);
     950               0 :   if (outLink)
     951               0 :     *outLink = nsnull;
     952               0 :   nsCOMPtr<nsIDOMNode> tmp, node = aNode;
     953               0 :   while (node)
     954                 :   {
     955               0 :     if (nsHTMLEditUtils::IsLink(node)) 
     956                 :     {
     957               0 :       if (outLink)
     958               0 :         *outLink = node;
     959               0 :       return true;
     960                 :     }
     961               0 :     tmp = node;
     962               0 :     tmp->GetParentNode(getter_AddRefs(node));
     963                 :   }
     964               0 :   return false;
     965                 : }
     966                 : 
     967                 : 
     968                 : nsresult
     969               0 : nsHTMLEditor::StripFormattingNodes(nsIDOMNode *aNode, bool aListOnly)
     970                 : {
     971               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
     972                 : 
     973               0 :   nsresult res = NS_OK;
     974               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     975               0 :   if (content->TextIsOnlyWhitespace())
     976                 :   {
     977               0 :     nsCOMPtr<nsIDOMNode> parent, ignored;
     978               0 :     aNode->GetParentNode(getter_AddRefs(parent));
     979               0 :     if (parent)
     980                 :     {
     981               0 :       if (!aListOnly || nsHTMLEditUtils::IsList(parent))
     982               0 :         res = parent->RemoveChild(aNode, getter_AddRefs(ignored));
     983               0 :       return res;
     984                 :     }
     985                 :   }
     986                 :   
     987               0 :   if (!nsHTMLEditUtils::IsPre(aNode))
     988                 :   {
     989               0 :     nsCOMPtr<nsIDOMNode> child;
     990               0 :     aNode->GetLastChild(getter_AddRefs(child));
     991                 :   
     992               0 :     while (child)
     993                 :     {
     994               0 :       nsCOMPtr<nsIDOMNode> tmp;
     995               0 :       child->GetPreviousSibling(getter_AddRefs(tmp));
     996               0 :       res = StripFormattingNodes(child, aListOnly);
     997               0 :       NS_ENSURE_SUCCESS(res, res);
     998               0 :       child = tmp;
     999                 :     }
    1000                 :   }
    1001               0 :   return res;
    1002                 : }
    1003                 : 
    1004               0 : NS_IMETHODIMP nsHTMLEditor::PrepareTransferable(nsITransferable **transferable)
    1005                 : {
    1006               0 :   return NS_OK;
    1007                 : }
    1008                 : 
    1009               0 : NS_IMETHODIMP nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransferable, 
    1010                 :                                                     bool aHavePrivFlavor)
    1011                 : {
    1012                 :   // Create generic Transferable for getting the data
    1013               0 :   nsresult rv = CallCreateInstance("@mozilla.org/widget/transferable;1", aTransferable);
    1014               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1015                 : 
    1016                 :   // Get the nsITransferable interface for getting the data from the clipboard
    1017               0 :   if (aTransferable)
    1018                 :   {
    1019                 :     // Create the desired DataFlavor for the type of data
    1020                 :     // we want to get out of the transferable
    1021                 :     // This should only happen in html editors, not plaintext
    1022               0 :     if (!IsPlaintextEditor())
    1023                 :     {
    1024               0 :       if (!aHavePrivFlavor) 
    1025                 :       {
    1026               0 :         (*aTransferable)->AddDataFlavor(kNativeHTMLMime);
    1027                 :       }
    1028               0 :       (*aTransferable)->AddDataFlavor(kHTMLMime);
    1029               0 :       (*aTransferable)->AddDataFlavor(kFileMime);
    1030                 : 
    1031               0 :       switch (Preferences::GetInt("clipboard.paste_image_type", 1))
    1032                 :       {
    1033                 :         case 0:  // prefer JPEG over PNG over GIF encoding
    1034               0 :           (*aTransferable)->AddDataFlavor(kJPEGImageMime);
    1035               0 :           (*aTransferable)->AddDataFlavor(kPNGImageMime);
    1036               0 :           (*aTransferable)->AddDataFlavor(kGIFImageMime);
    1037               0 :           break;
    1038                 :         case 1:  // prefer PNG over JPEG over GIF encoding (default)
    1039                 :         default:
    1040               0 :           (*aTransferable)->AddDataFlavor(kPNGImageMime);
    1041               0 :           (*aTransferable)->AddDataFlavor(kJPEGImageMime);
    1042               0 :           (*aTransferable)->AddDataFlavor(kGIFImageMime);
    1043               0 :           break;
    1044                 :         case 2:  // prefer GIF over JPEG over PNG encoding
    1045               0 :           (*aTransferable)->AddDataFlavor(kGIFImageMime);
    1046               0 :           (*aTransferable)->AddDataFlavor(kJPEGImageMime);
    1047               0 :           (*aTransferable)->AddDataFlavor(kPNGImageMime);
    1048               0 :           break;
    1049                 :       }
    1050                 :     }
    1051               0 :     (*aTransferable)->AddDataFlavor(kUnicodeMime);
    1052               0 :     (*aTransferable)->AddDataFlavor(kMozTextInternal);
    1053                 :   }
    1054                 :   
    1055               0 :   return NS_OK;
    1056                 : }
    1057                 : 
    1058                 : bool
    1059               0 : FindIntegerAfterString(const char *aLeadingString, 
    1060                 :                        nsCString &aCStr, PRInt32 &foundNumber)
    1061                 : {
    1062                 :   // first obtain offsets from cfhtml str
    1063               0 :   PRInt32 numFront = aCStr.Find(aLeadingString);
    1064               0 :   if (numFront == -1)
    1065               0 :     return false;
    1066               0 :   numFront += strlen(aLeadingString); 
    1067                 :   
    1068               0 :   PRInt32 numBack = aCStr.FindCharInSet(CRLF, numFront);
    1069               0 :   if (numBack == -1)
    1070               0 :     return false;
    1071                 :    
    1072               0 :   nsCAutoString numStr(Substring(aCStr, numFront, numBack-numFront));
    1073                 :   PRInt32 errorCode;
    1074               0 :   foundNumber = numStr.ToInteger(&errorCode);
    1075               0 :   return true;
    1076                 : }
    1077                 : 
    1078                 : nsresult
    1079               0 : RemoveFragComments(nsCString & aStr)
    1080                 : {
    1081                 :   // remove the StartFragment/EndFragment comments from the str, if present
    1082               0 :   PRInt32 startCommentIndx = aStr.Find("<!--StartFragment");
    1083               0 :   if (startCommentIndx >= 0)
    1084                 :   {
    1085               0 :     PRInt32 startCommentEnd = aStr.Find("-->", false, startCommentIndx);
    1086               0 :     if (startCommentEnd > startCommentIndx)
    1087               0 :       aStr.Cut(startCommentIndx, (startCommentEnd+3)-startCommentIndx);
    1088                 :   }  
    1089               0 :   PRInt32 endCommentIndx = aStr.Find("<!--EndFragment");
    1090               0 :   if (endCommentIndx >= 0)
    1091                 :   {
    1092               0 :     PRInt32 endCommentEnd = aStr.Find("-->", false, endCommentIndx);
    1093               0 :     if (endCommentEnd > endCommentIndx)
    1094               0 :       aStr.Cut(endCommentIndx, (endCommentEnd+3)-endCommentIndx);
    1095                 :   }  
    1096               0 :   return NS_OK;
    1097                 : }
    1098                 : 
    1099                 : nsresult
    1100               0 : nsHTMLEditor::ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnichar **aCfcontext)
    1101                 : {
    1102                 :   // First obtain offsets from cfhtml str.
    1103                 :   PRInt32 startHTML, endHTML, startFragment, endFragment;
    1104               0 :   if (!FindIntegerAfterString("StartHTML:", aCfhtml, startHTML) || 
    1105                 :       startHTML < -1)
    1106               0 :     return NS_ERROR_FAILURE;
    1107               0 :   if (!FindIntegerAfterString("EndHTML:", aCfhtml, endHTML) || 
    1108                 :       endHTML < -1) 
    1109               0 :     return NS_ERROR_FAILURE;
    1110               0 :   if (!FindIntegerAfterString("StartFragment:", aCfhtml, startFragment) || 
    1111                 :       startFragment < 0) 
    1112               0 :     return NS_ERROR_FAILURE;
    1113               0 :   if (!FindIntegerAfterString("EndFragment:", aCfhtml, endFragment) || 
    1114                 :       startFragment < 0)
    1115               0 :     return NS_ERROR_FAILURE;
    1116                 : 
    1117                 :   // The StartHTML and EndHTML markers are allowed to be -1 to include everything.
    1118                 :   //   See Reference: MSDN doc entitled "HTML Clipboard Format"
    1119                 :   //   http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx#unknown_854
    1120               0 :   if (startHTML == -1) {
    1121               0 :     startHTML = aCfhtml.Find("<!--StartFragment-->");
    1122               0 :     if (startHTML == -1)
    1123               0 :       return false;
    1124                 :   }
    1125               0 :   if (endHTML == -1) {
    1126               0 :     const char endFragmentMarker[] = "<!--EndFragment-->";
    1127               0 :     endHTML = aCfhtml.Find(endFragmentMarker);
    1128               0 :     if (endHTML == -1)
    1129               0 :       return false;
    1130               0 :     endHTML += ArrayLength(endFragmentMarker) - 1;
    1131                 :   }
    1132                 : 
    1133                 :   // create context string
    1134               0 :   nsCAutoString contextUTF8(Substring(aCfhtml, startHTML, startFragment - startHTML) +
    1135               0 :                             NS_LITERAL_CSTRING("<!--" kInsertCookie "-->") +
    1136               0 :                             Substring(aCfhtml, endFragment, endHTML - endFragment));
    1137                 : 
    1138                 :   // validate startFragment
    1139                 :   // make sure it's not in the middle of a HTML tag
    1140                 :   // see bug #228879 for more details
    1141               0 :   PRInt32 curPos = startFragment;
    1142               0 :   while (curPos > startHTML)
    1143                 :   {
    1144               0 :       if (aCfhtml[curPos] == '>')
    1145                 :       {
    1146                 :           // working backwards, the first thing we see is the end of a tag
    1147                 :           // so StartFragment is good, so do nothing.
    1148               0 :           break;
    1149                 :       }
    1150               0 :       else if (aCfhtml[curPos] == '<') 
    1151                 :       {
    1152                 :           // if we are at the start, then we want to see the '<'
    1153               0 :           if (curPos != startFragment) 
    1154                 :           {
    1155                 :               // working backwards, the first thing we see is the start of a tag
    1156                 :               // so StartFragment is bad, so we need to update it.
    1157               0 :               NS_ERROR("StartFragment byte count in the clipboard looks bad, see bug #228879");
    1158               0 :               startFragment = curPos - 1;
    1159                 :           }
    1160               0 :           break;
    1161                 :       }
    1162                 :       else 
    1163                 :       {
    1164               0 :           curPos--;
    1165                 :       }
    1166                 :   }
    1167                 : 
    1168                 :   // create fragment string
    1169               0 :   nsCAutoString fragmentUTF8(Substring(aCfhtml, startFragment, endFragment-startFragment));
    1170                 :   
    1171                 :   // remove the StartFragment/EndFragment comments from the fragment, if present
    1172               0 :   RemoveFragComments(fragmentUTF8);
    1173                 : 
    1174                 :   // remove the StartFragment/EndFragment comments from the context, if present
    1175               0 :   RemoveFragComments(contextUTF8);
    1176                 : 
    1177                 :   // convert both strings to usc2
    1178               0 :   const nsAFlatString& fragUcs2Str = NS_ConvertUTF8toUTF16(fragmentUTF8);
    1179               0 :   const nsAFlatString& cntxtUcs2Str = NS_ConvertUTF8toUTF16(contextUTF8);
    1180                 :   
    1181                 :   // translate platform linebreaks for fragment
    1182               0 :   PRInt32 oldLengthInChars = fragUcs2Str.Length() + 1;  // +1 to include null terminator
    1183               0 :   PRInt32 newLengthInChars = 0;
    1184                 :   *aStuffToPaste = nsLinebreakConverter::ConvertUnicharLineBreaks(fragUcs2Str.get(),
    1185                 :                                                            nsLinebreakConverter::eLinebreakAny, 
    1186                 :                                                            nsLinebreakConverter::eLinebreakContent, 
    1187               0 :                                                            oldLengthInChars, &newLengthInChars);
    1188               0 :   if (!*aStuffToPaste)
    1189                 :   {
    1190               0 :     return NS_ERROR_FAILURE;
    1191                 :   }
    1192                 :   
    1193                 :   // translate platform linebreaks for context
    1194               0 :   oldLengthInChars = cntxtUcs2Str.Length() + 1;  // +1 to include null terminator
    1195               0 :   newLengthInChars = 0;
    1196                 :   *aCfcontext = nsLinebreakConverter::ConvertUnicharLineBreaks(cntxtUcs2Str.get(),
    1197                 :                                                            nsLinebreakConverter::eLinebreakAny, 
    1198                 :                                                            nsLinebreakConverter::eLinebreakContent, 
    1199               0 :                                                            oldLengthInChars, &newLengthInChars);
    1200                 :   // it's ok for context to be empty.  frag might be whole doc and contain all its context.
    1201                 :   
    1202                 :   // we're done!  
    1203               0 :   return NS_OK;
    1204                 : }
    1205                 : 
    1206               0 : bool nsHTMLEditor::IsSafeToInsertData(nsIDOMDocument* aSourceDoc)
    1207                 : {
    1208                 :   // Try to determine whether we should use a sanitizing fragment sink
    1209               0 :   bool isSafe = false;
    1210               0 :   nsCOMPtr<nsIDOMDocument> destdomdoc;
    1211               0 :   GetDocument(getter_AddRefs(destdomdoc));
    1212                 : 
    1213               0 :   nsCOMPtr<nsIDocument> destdoc = do_QueryInterface(destdomdoc);
    1214               0 :   NS_ASSERTION(destdoc, "Where is our destination doc?");
    1215               0 :   nsCOMPtr<nsISupports> container = destdoc->GetContainer();
    1216               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti(do_QueryInterface(container));
    1217               0 :   nsCOMPtr<nsIDocShellTreeItem> root;
    1218               0 :   if (dsti)
    1219               0 :     dsti->GetRootTreeItem(getter_AddRefs(root));
    1220               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
    1221                 :   PRUint32 appType;
    1222               0 :   if (docShell && NS_SUCCEEDED(docShell->GetAppType(&appType)))
    1223               0 :     isSafe = appType == nsIDocShell::APP_TYPE_EDITOR;
    1224               0 :   if (!isSafe && aSourceDoc) {
    1225               0 :     nsCOMPtr<nsIDocument> srcdoc = do_QueryInterface(aSourceDoc);
    1226               0 :     NS_ASSERTION(srcdoc, "Where is our source doc?");
    1227                 : 
    1228               0 :     nsIPrincipal* srcPrincipal = srcdoc->NodePrincipal();
    1229               0 :     nsIPrincipal* destPrincipal = destdoc->NodePrincipal();
    1230               0 :     NS_ASSERTION(srcPrincipal && destPrincipal, "How come we don't have a principal?");
    1231               0 :     srcPrincipal->Subsumes(destPrincipal, &isSafe);
    1232                 :   }
    1233                 : 
    1234               0 :   return isSafe;
    1235                 : }
    1236                 : 
    1237               0 : nsresult nsHTMLEditor::InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
    1238                 :                                     nsIDOMDocument *aSourceDoc,
    1239                 :                                     nsIDOMNode *aDestinationNode,
    1240                 :                                     PRInt32 aDestOffset,
    1241                 :                                     bool aDoDeleteSelection)
    1242                 : {
    1243                 :   nsresult rv;
    1244                 : 
    1245               0 :   const char* type = aType;
    1246                 : 
    1247                 :   // Check to see if we can insert an image file
    1248               0 :   bool insertAsImage = false;
    1249               0 :   nsCOMPtr<nsIURI> fileURI;
    1250               0 :   if (0 == nsCRT::strcmp(type, kFileMime))
    1251                 :   {
    1252               0 :     nsCOMPtr<nsIFile> fileObj(do_QueryInterface(aObject));
    1253               0 :     if (fileObj)
    1254                 :     {
    1255               0 :       rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
    1256               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1257                 : 
    1258               0 :       nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
    1259               0 :       NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
    1260               0 :       nsCAutoString contentType;
    1261               0 :       rv = mime->GetTypeFromFile(fileObj, contentType);
    1262               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1263                 : 
    1264                 :       // Accept any image type fed to us
    1265               0 :       if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
    1266               0 :         insertAsImage = true;
    1267               0 :         type = contentType.get();
    1268                 :       }
    1269                 :     }
    1270                 :   }
    1271                 : 
    1272               0 :   if (0 == nsCRT::strcmp(type, kJPEGImageMime) ||
    1273               0 :       0 == nsCRT::strcmp(type, kPNGImageMime) ||
    1274               0 :       0 == nsCRT::strcmp(type, kGIFImageMime) ||
    1275                 :       insertAsImage)
    1276                 :   {
    1277               0 :     nsCOMPtr<nsIInputStream> imageStream;
    1278               0 :     if (insertAsImage) {
    1279               0 :       NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
    1280               0 :       rv = NS_OpenURI(getter_AddRefs(imageStream), fileURI);
    1281               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1282                 :     } else {
    1283               0 :       imageStream = do_QueryInterface(aObject);
    1284               0 :       NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
    1285                 :     }
    1286                 : 
    1287               0 :     nsCString imageData;
    1288               0 :     rv = NS_ConsumeStream(imageStream, PR_UINT32_MAX, imageData);
    1289               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1290                 : 
    1291               0 :     rv = imageStream->Close();
    1292               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1293                 : 
    1294               0 :     char * base64 = PL_Base64Encode(imageData.get(), imageData.Length(), nsnull);
    1295               0 :     NS_ENSURE_TRUE(base64, NS_ERROR_OUT_OF_MEMORY);
    1296                 : 
    1297               0 :     nsAutoString stuffToPaste;
    1298               0 :     stuffToPaste.AssignLiteral("<IMG src=\"data:");
    1299               0 :     AppendUTF8toUTF16(type, stuffToPaste);
    1300               0 :     stuffToPaste.AppendLiteral(";base64,");
    1301               0 :     AppendUTF8toUTF16(base64, stuffToPaste);
    1302               0 :     stuffToPaste.AppendLiteral("\" alt=\"\" >");
    1303               0 :     nsAutoEditBatch beginBatching(this);
    1304               0 :     rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(), 
    1305               0 :                                  NS_LITERAL_STRING(kFileMime),
    1306                 :                                  aSourceDoc,
    1307                 :                                  aDestinationNode, aDestOffset,
    1308                 :                                  aDoDeleteSelection,
    1309               0 :                                  aIsSafe);
    1310               0 :     PR_Free(base64);
    1311                 :   }
    1312                 : 
    1313               0 :   return NS_OK;
    1314                 : }
    1315                 : 
    1316               0 : NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable, 
    1317                 :                                                    nsIDOMDocument *aSourceDoc,
    1318                 :                                                    const nsAString & aContextStr,
    1319                 :                                                    const nsAString & aInfoStr,
    1320                 :                                                    nsIDOMNode *aDestinationNode,
    1321                 :                                                    PRInt32 aDestOffset,
    1322                 :                                                    bool aDoDeleteSelection)
    1323                 : {
    1324               0 :   nsresult rv = NS_OK;
    1325               0 :   nsXPIDLCString bestFlavor;
    1326               0 :   nsCOMPtr<nsISupports> genericDataObj;
    1327               0 :   PRUint32 len = 0;
    1328               0 :   if ( NS_SUCCEEDED(transferable->GetAnyTransferData(getter_Copies(bestFlavor), getter_AddRefs(genericDataObj), &len)) )
    1329                 :   {
    1330               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(this);
    1331               0 :     nsAutoString flavor;
    1332               0 :     flavor.AssignWithConversion(bestFlavor);
    1333               0 :     nsAutoString stuffToPaste;
    1334                 : #ifdef DEBUG_clipboard
    1335                 :     printf("Got flavor [%s]\n", bestFlavor.get());
    1336                 : #endif
    1337                 : 
    1338               0 :     bool isSafe = IsSafeToInsertData(aSourceDoc);
    1339                 : 
    1340               0 :         if (0 == nsCRT::strcmp(bestFlavor, kFileMime) ||
    1341               0 :         0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime) ||
    1342               0 :         0 == nsCRT::strcmp(bestFlavor, kPNGImageMime) ||
    1343               0 :         0 == nsCRT::strcmp(bestFlavor, kGIFImageMime)) {
    1344                 :       rv = InsertObject(bestFlavor, genericDataObj, isSafe,
    1345               0 :                         aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
    1346                 :     }
    1347               0 :     else if (0 == nsCRT::strcmp(bestFlavor, kNativeHTMLMime))
    1348                 :     {
    1349                 :       // note cf_html uses utf8, hence use length = len, not len/2 as in flavors below
    1350               0 :       nsCOMPtr<nsISupportsCString> textDataObj(do_QueryInterface(genericDataObj));
    1351               0 :       if (textDataObj && len > 0)
    1352                 :       {
    1353               0 :         nsCAutoString cfhtml;
    1354               0 :         textDataObj->GetData(cfhtml);
    1355               0 :         NS_ASSERTION(cfhtml.Length() <= (len), "Invalid length!");
    1356               0 :         nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
    1357                 :          
    1358               0 :         rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
    1359               0 :         if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
    1360                 :         {
    1361               0 :           nsAutoEditBatch beginBatching(this);
    1362                 :           rv = DoInsertHTMLWithContext(cffragment,
    1363                 :                                        cfcontext, cfselection, flavor,
    1364                 :                                        aSourceDoc,
    1365                 :                                        aDestinationNode, aDestOffset,
    1366                 :                                        aDoDeleteSelection,
    1367               0 :                                        isSafe);
    1368                 :         }
    1369                 :       }
    1370                 :     }
    1371               0 :     else if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime) ||
    1372               0 :              0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
    1373               0 :              0 == nsCRT::strcmp(bestFlavor, kMozTextInternal)) {
    1374               0 :       nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
    1375               0 :       if (textDataObj && len > 0)
    1376                 :       {
    1377               0 :         nsAutoString text;
    1378               0 :         textDataObj->GetData(text);
    1379               0 :         NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
    1380               0 :         stuffToPaste.Assign(text.get(), len / 2);
    1381                 : 
    1382               0 :         nsAutoEditBatch beginBatching(this);
    1383               0 :         if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime)) {
    1384                 :           rv = DoInsertHTMLWithContext(stuffToPaste,
    1385                 :                                        aContextStr, aInfoStr, flavor,
    1386                 :                                        aSourceDoc,
    1387                 :                                        aDestinationNode, aDestOffset,
    1388                 :                                        aDoDeleteSelection,
    1389               0 :                                        isSafe);
    1390                 :         } else {
    1391               0 :           rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
    1392                 :         }
    1393                 :       }
    1394                 :     }
    1395                 :   }
    1396                 : 
    1397                 :   // Try to scroll the selection into view if the paste succeeded
    1398               0 :   if (NS_SUCCEEDED(rv))
    1399               0 :     ScrollSelectionIntoView(false);
    1400                 : 
    1401               0 :   return rv;
    1402                 : }
    1403                 : 
    1404                 : static void
    1405               0 : GetStringFromDataTransfer(nsIDOMDataTransfer *aDataTransfer, const nsAString& aType,
    1406                 :                           PRInt32 aIndex, nsAString& aOutputString)
    1407                 : {
    1408               0 :   nsCOMPtr<nsIVariant> variant;
    1409               0 :   aDataTransfer->MozGetDataAt(aType, aIndex, getter_AddRefs(variant));
    1410               0 :   if (variant)
    1411               0 :     variant->GetAsAString(aOutputString);
    1412               0 : }
    1413                 : 
    1414               0 : nsresult nsHTMLEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
    1415                 :                                               PRInt32 aIndex,
    1416                 :                                               nsIDOMDocument *aSourceDoc,
    1417                 :                                               nsIDOMNode *aDestinationNode,
    1418                 :                                               PRInt32 aDestOffset,
    1419                 :                                               bool aDoDeleteSelection)
    1420                 : {
    1421               0 :   nsresult rv = NS_OK;
    1422                 : 
    1423               0 :   nsCOMPtr<nsIDOMDOMStringList> types;
    1424               0 :   aDataTransfer->MozTypesAt(aIndex, getter_AddRefs(types));
    1425                 : 
    1426                 :   bool hasPrivateHTMLFlavor;
    1427               0 :   types->Contains(NS_LITERAL_STRING(kHTMLContext), &hasPrivateHTMLFlavor);
    1428                 : 
    1429               0 :   bool isText = IsPlaintextEditor();
    1430               0 :   bool isSafe = IsSafeToInsertData(aSourceDoc);
    1431                 :   
    1432                 :   PRUint32 length;
    1433               0 :   types->GetLength(&length);
    1434               0 :   for (PRUint32 t = 0; t < length; t++) {
    1435               0 :     nsAutoString type;
    1436               0 :     types->Item(t, type);
    1437                 : 
    1438               0 :     if (!isText) {
    1439               0 :       if (type.EqualsLiteral(kFileMime) ||
    1440               0 :           type.EqualsLiteral(kJPEGImageMime) ||
    1441               0 :           type.EqualsLiteral(kPNGImageMime) ||
    1442               0 :           type.EqualsLiteral(kGIFImageMime)) {
    1443               0 :         nsCOMPtr<nsIVariant> variant;
    1444               0 :         aDataTransfer->MozGetDataAt(type, aIndex, getter_AddRefs(variant));
    1445               0 :         if (variant) {
    1446               0 :           nsCOMPtr<nsISupports> object;
    1447               0 :           variant->GetAsISupports(getter_AddRefs(object));
    1448               0 :           rv = InsertObject(NS_ConvertUTF16toUTF8(type).get(), object, isSafe,
    1449               0 :                             aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
    1450               0 :           if (NS_SUCCEEDED(rv))
    1451               0 :             return NS_OK;
    1452                 :         }
    1453                 :       }
    1454               0 :       else if (!hasPrivateHTMLFlavor && type.EqualsLiteral(kNativeHTMLMime)) {
    1455               0 :         nsAutoString text;
    1456               0 :         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kNativeHTMLMime), aIndex, text);
    1457               0 :         NS_ConvertUTF16toUTF8 cfhtml(text);
    1458                 : 
    1459               0 :         nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
    1460                 :            
    1461               0 :         rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
    1462               0 :         if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
    1463                 :         {
    1464               0 :           nsAutoEditBatch beginBatching(this);
    1465                 :           rv = DoInsertHTMLWithContext(cffragment,
    1466                 :                                        cfcontext, cfselection, type,
    1467                 :                                        aSourceDoc,
    1468                 :                                        aDestinationNode, aDestOffset,
    1469                 :                                        aDoDeleteSelection,
    1470               0 :                                        isSafe);
    1471               0 :           if (NS_SUCCEEDED(rv))
    1472               0 :             return NS_OK;
    1473                 :         }
    1474                 :       }
    1475               0 :       else if (type.EqualsLiteral(kHTMLMime)) {
    1476               0 :         nsAutoString text, contextString, infoString;
    1477               0 :         GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
    1478               0 :         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), aIndex, contextString);
    1479               0 :         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), aIndex, infoString);
    1480                 : 
    1481               0 :         nsAutoEditBatch beginBatching(this);
    1482               0 :         if (type.EqualsLiteral(kHTMLMime)) {
    1483                 :           rv = DoInsertHTMLWithContext(text,
    1484                 :                                        contextString, infoString, type,
    1485                 :                                        aSourceDoc,
    1486                 :                                        aDestinationNode, aDestOffset,
    1487                 :                                        aDoDeleteSelection,
    1488               0 :                                        isSafe);
    1489               0 :           if (NS_SUCCEEDED(rv))
    1490               0 :             return NS_OK;
    1491                 :         }
    1492                 :       }
    1493                 :     }
    1494                 : 
    1495               0 :     if (type.EqualsLiteral(kTextMime) ||
    1496               0 :         type.EqualsLiteral(kMozTextInternal)) {
    1497               0 :       nsAutoString text;
    1498               0 :       GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
    1499                 : 
    1500               0 :       nsAutoEditBatch beginBatching(this);
    1501               0 :       rv = InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
    1502               0 :       if (NS_SUCCEEDED(rv))
    1503               0 :         return NS_OK;
    1504                 :     }
    1505                 :   }
    1506                 : 
    1507               0 :   return rv;
    1508                 : }
    1509                 : 
    1510               0 : bool nsHTMLEditor::HavePrivateHTMLFlavor(nsIClipboard *aClipboard)
    1511                 : {
    1512                 :   // check the clipboard for our special kHTMLContext flavor.  If that is there, we know
    1513                 :   // we have our own internal html format on clipboard.
    1514                 :   
    1515               0 :   NS_ENSURE_TRUE(aClipboard, false);
    1516               0 :   bool bHavePrivateHTMLFlavor = false;
    1517                 :   
    1518               0 :   const char* flavArray[] = { kHTMLContext };
    1519                 :   
    1520               0 :   if (NS_SUCCEEDED(aClipboard->HasDataMatchingFlavors(flavArray,
    1521                 :     ArrayLength(flavArray), nsIClipboard::kGlobalClipboard,
    1522                 :     &bHavePrivateHTMLFlavor )))
    1523               0 :     return bHavePrivateHTMLFlavor;
    1524                 :     
    1525               0 :   return false;
    1526                 : }
    1527                 : 
    1528                 : 
    1529               0 : NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType)
    1530                 : {
    1531               0 :   if (!FireClipboardEvent(NS_PASTE))
    1532               0 :     return NS_OK;
    1533                 : 
    1534                 :   // Get Clipboard Service
    1535                 :   nsresult rv;
    1536               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
    1537               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1538                 :   
    1539                 :   // find out if we have our internal html flavor on the clipboard.  We don't want to mess
    1540                 :   // around with cfhtml if we do.
    1541               0 :   bool bHavePrivateHTMLFlavor = HavePrivateHTMLFlavor(clipboard);
    1542                 : 
    1543                 :   // Get the nsITransferable interface for getting the data from the clipboard
    1544               0 :   nsCOMPtr<nsITransferable> trans;
    1545               0 :   rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
    1546               0 :   if (NS_SUCCEEDED(rv) && trans)
    1547                 :   {
    1548                 :     // Get the Data from the clipboard  
    1549               0 :     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
    1550                 :     {
    1551                 :       // also get additional html copy hints, if present
    1552               0 :       nsAutoString contextStr, infoStr;
    1553                 : 
    1554                 :       // also get additional html copy hints, if present
    1555               0 :       if (bHavePrivateHTMLFlavor)
    1556                 :       {
    1557               0 :         nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
    1558                 :         PRUint32 contextLen, infoLen;
    1559               0 :         nsCOMPtr<nsISupportsString> textDataObj;
    1560                 :         
    1561                 :         nsCOMPtr<nsITransferable> contextTrans =
    1562               0 :                       do_CreateInstance("@mozilla.org/widget/transferable;1");
    1563               0 :         NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
    1564               0 :         contextTrans->AddDataFlavor(kHTMLContext);
    1565               0 :         clipboard->GetData(contextTrans, aSelectionType);
    1566               0 :         contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
    1567                 : 
    1568                 :         nsCOMPtr<nsITransferable> infoTrans =
    1569               0 :                       do_CreateInstance("@mozilla.org/widget/transferable;1");
    1570               0 :         NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
    1571               0 :         infoTrans->AddDataFlavor(kHTMLInfo);
    1572               0 :         clipboard->GetData(infoTrans, aSelectionType);
    1573               0 :         infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
    1574                 :         
    1575               0 :         if (contextDataObj)
    1576                 :         {
    1577               0 :           nsAutoString text;
    1578               0 :           textDataObj = do_QueryInterface(contextDataObj);
    1579               0 :           textDataObj->GetData(text);
    1580               0 :           NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
    1581               0 :           contextStr.Assign(text.get(), contextLen / 2);
    1582                 :         }
    1583                 :         
    1584               0 :         if (infoDataObj)
    1585                 :         {
    1586               0 :           nsAutoString text;
    1587               0 :           textDataObj = do_QueryInterface(infoDataObj);
    1588               0 :           textDataObj->GetData(text);
    1589               0 :           NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
    1590               0 :           infoStr.Assign(text.get(), infoLen / 2);
    1591                 :         }
    1592                 :       }
    1593                 : 
    1594                 :       // handle transferable hooks
    1595               0 :       nsCOMPtr<nsIDOMDocument> domdoc;
    1596               0 :       GetDocument(getter_AddRefs(domdoc));
    1597               0 :       if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
    1598               0 :         return NS_OK;
    1599                 : 
    1600                 :       rv = InsertFromTransferable(trans, nsnull, contextStr, infoStr,
    1601               0 :                                   nsnull, 0, true);
    1602                 :     }
    1603                 :   }
    1604                 : 
    1605               0 :   return rv;
    1606                 : }
    1607                 : 
    1608               0 : NS_IMETHODIMP nsHTMLEditor::PasteTransferable(nsITransferable *aTransferable)
    1609                 : {
    1610               0 :   if (!FireClipboardEvent(NS_PASTE))
    1611               0 :     return NS_OK;
    1612                 : 
    1613                 :   // handle transferable hooks
    1614               0 :   nsCOMPtr<nsIDOMDocument> domdoc;
    1615               0 :   GetDocument(getter_AddRefs(domdoc));
    1616               0 :   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
    1617               0 :     return NS_OK;
    1618                 : 
    1619               0 :   nsAutoString contextStr, infoStr;
    1620                 :   return InsertFromTransferable(aTransferable, nsnull, contextStr, infoStr,
    1621               0 :                                 nsnull, 0, true);
    1622                 : }
    1623                 : 
    1624                 : // 
    1625                 : // HTML PasteNoFormatting. Ignore any HTML styles and formating in paste source
    1626                 : //
    1627               0 : NS_IMETHODIMP nsHTMLEditor::PasteNoFormatting(PRInt32 aSelectionType)
    1628                 : {
    1629               0 :   ForceCompositionEnd();
    1630                 : 
    1631                 :   // Get Clipboard Service
    1632                 :   nsresult rv;
    1633               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
    1634               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1635                 :     
    1636                 :   // Get the nsITransferable interface for getting the data from the clipboard.
    1637                 :   // use nsPlaintextEditor::PrepareTransferable() to force unicode plaintext data.
    1638               0 :   nsCOMPtr<nsITransferable> trans;
    1639               0 :   rv = nsPlaintextEditor::PrepareTransferable(getter_AddRefs(trans));
    1640               0 :   if (NS_SUCCEEDED(rv) && trans)
    1641                 :   {
    1642                 :     // Get the Data from the clipboard  
    1643               0 :     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
    1644                 :     {
    1645               0 :       const nsAFlatString& empty = EmptyString();
    1646                 :       rv = InsertFromTransferable(trans, nsnull, empty, empty, nsnull, 0,
    1647               0 :                                   true);
    1648                 :     }
    1649                 :   }
    1650                 : 
    1651               0 :   return rv;
    1652                 : }
    1653                 : 
    1654                 : 
    1655                 : // The following arrays contain the MIME types that we can paste. The arrays
    1656                 : // are used by CanPaste() and CanPasteTransferable() below.
    1657                 : 
    1658                 : static const char* textEditorFlavors[] = { kUnicodeMime };
    1659                 : static const char* textHtmlEditorFlavors[] = { kUnicodeMime, kHTMLMime,
    1660                 :                                                kJPEGImageMime, kPNGImageMime,
    1661                 :                                                kGIFImageMime };
    1662                 : 
    1663               0 : NS_IMETHODIMP nsHTMLEditor::CanPaste(PRInt32 aSelectionType, bool *aCanPaste)
    1664                 : {
    1665               0 :   NS_ENSURE_ARG_POINTER(aCanPaste);
    1666               0 :   *aCanPaste = false;
    1667                 : 
    1668                 :   // can't paste if readonly
    1669               0 :   if (!IsModifiable())
    1670               0 :     return NS_OK;
    1671                 : 
    1672                 :   nsresult rv;
    1673               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
    1674               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1675                 : 
    1676                 :   bool haveFlavors;
    1677                 : 
    1678                 :   // Use the flavors depending on the current editor mask
    1679               0 :   if (IsPlaintextEditor())
    1680               0 :     rv = clipboard->HasDataMatchingFlavors(textEditorFlavors,
    1681                 :                                            ArrayLength(textEditorFlavors),
    1682               0 :                                            aSelectionType, &haveFlavors);
    1683                 :   else
    1684               0 :     rv = clipboard->HasDataMatchingFlavors(textHtmlEditorFlavors,
    1685                 :                                            ArrayLength(textHtmlEditorFlavors),
    1686               0 :                                            aSelectionType, &haveFlavors);
    1687                 :   
    1688               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1689                 :   
    1690               0 :   *aCanPaste = haveFlavors;
    1691               0 :   return NS_OK;
    1692                 : }
    1693                 : 
    1694               0 : NS_IMETHODIMP nsHTMLEditor::CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste)
    1695                 : {
    1696               0 :   NS_ENSURE_ARG_POINTER(aCanPaste);
    1697                 : 
    1698                 :   // can't paste if readonly
    1699               0 :   if (!IsModifiable()) {
    1700               0 :     *aCanPaste = false;
    1701               0 :     return NS_OK;
    1702                 :   }
    1703                 : 
    1704                 :   // If |aTransferable| is null, assume that a paste will succeed.
    1705               0 :   if (!aTransferable) {
    1706               0 :     *aCanPaste = true;
    1707               0 :     return NS_OK;
    1708                 :   }
    1709                 : 
    1710                 :   // Peek in |aTransferable| to see if it contains a supported MIME type.
    1711                 : 
    1712                 :   // Use the flavors depending on the current editor mask
    1713                 :   const char ** flavors;
    1714                 :   unsigned length;
    1715               0 :   if (IsPlaintextEditor()) {
    1716               0 :     flavors = textEditorFlavors;
    1717               0 :     length = ArrayLength(textEditorFlavors);
    1718                 :   } else {
    1719               0 :     flavors = textHtmlEditorFlavors;
    1720               0 :     length = ArrayLength(textHtmlEditorFlavors);
    1721                 :   }
    1722                 : 
    1723               0 :   for (unsigned int i = 0; i < length; i++, flavors++) {
    1724               0 :     nsCOMPtr<nsISupports> data;
    1725                 :     PRUint32 dataLen;
    1726                 :     nsresult rv = aTransferable->GetTransferData(*flavors,
    1727               0 :                                                  getter_AddRefs(data),
    1728               0 :                                                  &dataLen);
    1729               0 :     if (NS_SUCCEEDED(rv) && data) {
    1730               0 :       *aCanPaste = true;
    1731               0 :       return NS_OK;
    1732                 :     }
    1733                 :   }
    1734                 :   
    1735               0 :   *aCanPaste = false;
    1736               0 :   return NS_OK;
    1737                 : }
    1738                 : 
    1739                 : 
    1740                 : // 
    1741                 : // HTML PasteAsQuotation: Paste in a blockquote type=cite
    1742                 : //
    1743               0 : NS_IMETHODIMP nsHTMLEditor::PasteAsQuotation(PRInt32 aSelectionType)
    1744                 : {
    1745               0 :   if (IsPlaintextEditor())
    1746               0 :     return PasteAsPlaintextQuotation(aSelectionType);
    1747                 : 
    1748               0 :   nsAutoString citation;
    1749               0 :   return PasteAsCitedQuotation(citation, aSelectionType);
    1750                 : }
    1751                 : 
    1752               0 : NS_IMETHODIMP nsHTMLEditor::PasteAsCitedQuotation(const nsAString & aCitation,
    1753                 :                                                   PRInt32 aSelectionType)
    1754                 : {
    1755               0 :   nsAutoEditBatch beginBatching(this);
    1756               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
    1757                 : 
    1758                 :   // get selection
    1759               0 :   nsCOMPtr<nsISelection> selection;
    1760               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    1761               0 :   NS_ENSURE_SUCCESS(res, res);
    1762               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1763                 : 
    1764                 :   // give rules a chance to handle or cancel
    1765               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
    1766                 :   bool cancel, handled;
    1767               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1768               0 :   NS_ENSURE_SUCCESS(res, res);
    1769               0 :   if (cancel) return NS_OK; // rules canceled the operation
    1770               0 :   if (!handled)
    1771                 :   {
    1772               0 :     nsCOMPtr<nsIDOMNode> newNode;
    1773               0 :     res = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("blockquote"), getter_AddRefs(newNode));
    1774               0 :     NS_ENSURE_SUCCESS(res, res);
    1775               0 :     NS_ENSURE_TRUE(newNode, NS_ERROR_NULL_POINTER);
    1776                 : 
    1777                 :     // Try to set type=cite.  Ignore it if this fails.
    1778               0 :     nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
    1779               0 :     if (newElement)
    1780                 :     {
    1781               0 :       newElement->SetAttribute(NS_LITERAL_STRING("type"), NS_LITERAL_STRING("cite"));
    1782                 :     }
    1783                 : 
    1784                 :     // Set the selection to the underneath the node we just inserted:
    1785               0 :     res = selection->Collapse(newNode, 0);
    1786               0 :     if (NS_FAILED(res))
    1787                 :     {
    1788                 : #ifdef DEBUG_akkana
    1789                 :       printf("Couldn't collapse");
    1790                 : #endif
    1791                 :       // XXX: error result:  should res be returned here?
    1792                 :     }
    1793                 : 
    1794               0 :     res = Paste(aSelectionType);
    1795                 :   }
    1796               0 :   return res;
    1797                 : }
    1798                 : 
    1799                 : //
    1800                 : // Paste a plaintext quotation
    1801                 : //
    1802               0 : NS_IMETHODIMP nsHTMLEditor::PasteAsPlaintextQuotation(PRInt32 aSelectionType)
    1803                 : {
    1804                 :   // Get Clipboard Service
    1805                 :   nsresult rv;
    1806               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
    1807               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1808                 : 
    1809                 :   // Create generic Transferable for getting the data
    1810                 :   nsCOMPtr<nsITransferable> trans =
    1811               0 :                  do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
    1812               0 :   if (NS_SUCCEEDED(rv) && trans)
    1813                 :   {
    1814                 :     // We only handle plaintext pastes here
    1815               0 :     trans->AddDataFlavor(kUnicodeMime);
    1816                 : 
    1817                 :     // Get the Data from the clipboard
    1818               0 :     clipboard->GetData(trans, aSelectionType);
    1819                 : 
    1820                 :     // Now we ask the transferable for the data
    1821                 :     // it still owns the data, we just have a pointer to it.
    1822                 :     // If it can't support a "text" output of the data the call will fail
    1823               0 :     nsCOMPtr<nsISupports> genericDataObj;
    1824               0 :     PRUint32 len = 0;
    1825               0 :     char* flav = 0;
    1826               0 :     rv = trans->GetAnyTransferData(&flav, getter_AddRefs(genericDataObj),
    1827               0 :                                    &len);
    1828               0 :     if (NS_FAILED(rv))
    1829                 :     {
    1830                 : #ifdef DEBUG_akkana
    1831                 :       printf("PasteAsPlaintextQuotation: GetAnyTransferData failed, %d\n", rv);
    1832                 : #endif
    1833               0 :       return rv;
    1834                 :     }
    1835                 : 
    1836               0 :     if (flav && 0 == nsCRT::strcmp((flav), kUnicodeMime))
    1837                 :     {
    1838                 : #ifdef DEBUG_clipboard
    1839                 :     printf("Got flavor [%s]\n", flav);
    1840                 : #endif
    1841               0 :       nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
    1842               0 :       if (textDataObj && len > 0)
    1843                 :       {
    1844               0 :         nsAutoString stuffToPaste;
    1845               0 :         textDataObj->GetData(stuffToPaste);
    1846               0 :         NS_ASSERTION(stuffToPaste.Length() <= (len/2), "Invalid length!");
    1847               0 :         nsAutoEditBatch beginBatching(this);
    1848               0 :         rv = InsertAsPlaintextQuotation(stuffToPaste, true, 0);
    1849                 :       }
    1850                 :     }
    1851               0 :     NS_Free(flav);
    1852                 :   }
    1853                 : 
    1854               0 :   return rv;
    1855                 : }
    1856                 : 
    1857                 : NS_IMETHODIMP
    1858               0 : nsHTMLEditor::InsertTextWithQuotations(const nsAString &aStringToInsert)
    1859                 : {
    1860               0 :   if (mWrapToWindow)
    1861               0 :     return InsertText(aStringToInsert);
    1862                 : 
    1863                 :   // The whole operation should be undoable in one transaction:
    1864               0 :   BeginTransaction();
    1865                 : 
    1866                 :   // We're going to loop over the string, collecting up a "hunk"
    1867                 :   // that's all the same type (quoted or not),
    1868                 :   // Whenever the quotedness changes (or we reach the string's end)
    1869                 :   // we will insert the hunk all at once, quoted or non.
    1870                 : 
    1871                 :   static const PRUnichar cite('>');
    1872               0 :   bool curHunkIsQuoted = (aStringToInsert.First() == cite);
    1873                 : 
    1874               0 :   nsAString::const_iterator hunkStart, strEnd;
    1875               0 :   aStringToInsert.BeginReading(hunkStart);
    1876               0 :   aStringToInsert.EndReading(strEnd);
    1877                 : 
    1878                 :   // In the loop below, we only look for DOM newlines (\n),
    1879                 :   // because we don't have a FindChars method that can look
    1880                 :   // for both \r and \n.  \r is illegal in the dom anyway,
    1881                 :   // but in debug builds, let's take the time to verify that
    1882                 :   // there aren't any there:
    1883                 : #ifdef DEBUG
    1884               0 :   nsAString::const_iterator dbgStart (hunkStart);
    1885               0 :   if (FindCharInReadable('\r', dbgStart, strEnd))
    1886               0 :     NS_ASSERTION(false,
    1887                 :             "Return characters in DOM! InsertTextWithQuotations may be wrong");
    1888                 : #endif /* DEBUG */
    1889                 : 
    1890                 :   // Loop over lines:
    1891               0 :   nsresult rv = NS_OK;
    1892               0 :   nsAString::const_iterator lineStart (hunkStart);
    1893               0 :   while (1)   // we will break from inside when we run out of newlines
    1894                 :   {
    1895                 :     // Search for the end of this line (dom newlines, see above):
    1896               0 :     bool found = FindCharInReadable('\n', lineStart, strEnd);
    1897               0 :     bool quoted = false;
    1898               0 :     if (found)
    1899                 :     {
    1900                 :       // if there's another newline, lineStart now points there.
    1901                 :       // Loop over any consecutive newline chars:
    1902               0 :       nsAString::const_iterator firstNewline (lineStart);
    1903               0 :       while (*lineStart == '\n')
    1904               0 :         ++lineStart;
    1905               0 :       quoted = (*lineStart == cite);
    1906               0 :       if (quoted == curHunkIsQuoted)
    1907               0 :         continue;
    1908                 :       // else we're changing state, so we need to insert
    1909                 :       // from curHunk to lineStart then loop around.
    1910                 : 
    1911                 :       // But if the current hunk is quoted, then we want to make sure
    1912                 :       // that any extra newlines on the end do not get included in
    1913                 :       // the quoted section: blank lines flaking a quoted section
    1914                 :       // should be considered unquoted, so that if the user clicks
    1915                 :       // there and starts typing, the new text will be outside of
    1916                 :       // the quoted block.
    1917               0 :       if (curHunkIsQuoted)
    1918               0 :         lineStart = firstNewline;
    1919                 :     }
    1920                 : 
    1921                 :     // If no newline found, lineStart is now strEnd and we can finish up,
    1922                 :     // inserting from curHunk to lineStart then returning.
    1923               0 :     const nsAString &curHunk = Substring(hunkStart, lineStart);
    1924               0 :     nsCOMPtr<nsIDOMNode> dummyNode;
    1925                 : #ifdef DEBUG_akkana_verbose
    1926                 :     printf("==== Inserting text as %squoted: ---\n%s---\n",
    1927                 :            curHunkIsQuoted ? "" : "non-",
    1928                 :            NS_LossyConvertUTF16toASCII(curHunk).get());
    1929                 : #endif
    1930               0 :     if (curHunkIsQuoted)
    1931                 :       rv = InsertAsPlaintextQuotation(curHunk, false,
    1932               0 :                                       getter_AddRefs(dummyNode));
    1933                 :     else
    1934               0 :       rv = InsertText(curHunk);
    1935                 : 
    1936               0 :     if (!found)
    1937                 :       break;
    1938                 : 
    1939               0 :     curHunkIsQuoted = quoted;
    1940               0 :     hunkStart = lineStart;
    1941                 :   }
    1942                 : 
    1943               0 :   EndTransaction();
    1944                 : 
    1945               0 :   return rv;
    1946                 : }
    1947                 : 
    1948               0 : NS_IMETHODIMP nsHTMLEditor::InsertAsQuotation(const nsAString & aQuotedText,
    1949                 :                                               nsIDOMNode **aNodeInserted)
    1950                 : {
    1951               0 :   if (IsPlaintextEditor())
    1952               0 :     return InsertAsPlaintextQuotation(aQuotedText, true, aNodeInserted);
    1953                 : 
    1954               0 :   nsAutoString citation;
    1955                 :   return InsertAsCitedQuotation(aQuotedText, citation, false,
    1956               0 :                                 aNodeInserted);
    1957                 : }
    1958                 : 
    1959                 : // Insert plaintext as a quotation, with cite marks (e.g. "> ").
    1960                 : // This differs from its corresponding method in nsPlaintextEditor
    1961                 : // in that here, quoted material is enclosed in a <pre> tag
    1962                 : // in order to preserve the original line wrapping.
    1963                 : NS_IMETHODIMP
    1964               0 : nsHTMLEditor::InsertAsPlaintextQuotation(const nsAString & aQuotedText,
    1965                 :                                          bool aAddCites,
    1966                 :                                          nsIDOMNode **aNodeInserted)
    1967                 : {
    1968               0 :   if (mWrapToWindow)
    1969               0 :     return nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
    1970                 : 
    1971               0 :   nsCOMPtr<nsIDOMNode> preNode;
    1972                 :   // get selection
    1973               0 :   nsCOMPtr<nsISelection> selection;
    1974               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
    1975               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1976               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1977                 : 
    1978               0 :   nsAutoEditBatch beginBatching(this);
    1979               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
    1980                 : 
    1981                 :   // give rules a chance to handle or cancel
    1982               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
    1983                 :   bool cancel, handled;
    1984               0 :   rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1985               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1986               0 :   if (cancel) return NS_OK; // rules canceled the operation
    1987               0 :   if (!handled)
    1988                 :   {
    1989                 :     // Wrap the inserted quote in a <span> so it won't be wrapped:
    1990               0 :     rv = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("span"), getter_AddRefs(preNode));
    1991                 : 
    1992                 :     // If this succeeded, then set selection inside the pre
    1993                 :     // so the inserted text will end up there.
    1994                 :     // If it failed, we don't care what the return value was,
    1995                 :     // but we'll fall through and try to insert the text anyway.
    1996               0 :     if (NS_SUCCEEDED(rv) && preNode)
    1997                 :     {
    1998                 :       // Add an attribute on the pre node so we'll know it's a quotation.
    1999                 :       // Do this after the insertion, so that
    2000               0 :       nsCOMPtr<nsIDOMElement> preElement(do_QueryInterface(preNode));
    2001               0 :       if (preElement)
    2002                 :       {
    2003               0 :         preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
    2004               0 :                                  NS_LITERAL_STRING("true"));
    2005                 :         // turn off wrapping on spans
    2006               0 :         preElement->SetAttribute(NS_LITERAL_STRING("style"),
    2007               0 :                                  NS_LITERAL_STRING("white-space: pre;"));
    2008                 :       }
    2009                 :       // and set the selection inside it:
    2010               0 :       selection->Collapse(preNode, 0);
    2011                 :     }
    2012                 : 
    2013               0 :     if (aAddCites)
    2014               0 :       rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
    2015                 :     else
    2016               0 :       rv = nsPlaintextEditor::InsertText(aQuotedText);
    2017                 :     // Note that if !aAddCites, aNodeInserted isn't set.
    2018                 :     // That's okay because the routines that use aAddCites
    2019                 :     // don't need to know the inserted node.
    2020                 : 
    2021               0 :     if (aNodeInserted && NS_SUCCEEDED(rv))
    2022                 :     {
    2023               0 :       *aNodeInserted = preNode;
    2024               0 :       NS_IF_ADDREF(*aNodeInserted);
    2025                 :     }
    2026                 :   }
    2027                 : 
    2028                 :   // Set the selection to just after the inserted node:
    2029               0 :   if (NS_SUCCEEDED(rv) && preNode)
    2030                 :   {
    2031               0 :     nsCOMPtr<nsIDOMNode> parent;
    2032                 :     PRInt32 offset;
    2033               0 :     if (NS_SUCCEEDED(GetNodeLocation(preNode, address_of(parent), &offset)) && parent)
    2034               0 :       selection->Collapse(parent, offset+1);
    2035                 :   }
    2036               0 :   return rv;
    2037                 : }
    2038                 : 
    2039                 : NS_IMETHODIMP    
    2040               0 : nsHTMLEditor::StripCites()
    2041                 : {
    2042               0 :   return nsPlaintextEditor::StripCites();
    2043                 : }
    2044                 : 
    2045                 : NS_IMETHODIMP    
    2046               0 : nsHTMLEditor::Rewrap(bool aRespectNewlines)
    2047                 : {
    2048               0 :   return nsPlaintextEditor::Rewrap(aRespectNewlines);
    2049                 : }
    2050                 : 
    2051                 : NS_IMETHODIMP
    2052               0 : nsHTMLEditor::InsertAsCitedQuotation(const nsAString & aQuotedText,
    2053                 :                                      const nsAString & aCitation,
    2054                 :                                      bool aInsertHTML,
    2055                 :                                      nsIDOMNode **aNodeInserted)
    2056                 : {
    2057                 :   // Don't let anyone insert html into a "plaintext" editor:
    2058               0 :   if (IsPlaintextEditor())
    2059                 :   {
    2060               0 :     NS_ASSERTION(!aInsertHTML, "InsertAsCitedQuotation: trying to insert html into plaintext editor");
    2061               0 :     return InsertAsPlaintextQuotation(aQuotedText, true, aNodeInserted);
    2062                 :   }
    2063                 : 
    2064               0 :   nsCOMPtr<nsIDOMNode> newNode;
    2065               0 :   nsresult res = NS_OK;
    2066                 : 
    2067                 :   // get selection
    2068               0 :   nsCOMPtr<nsISelection> selection;
    2069               0 :   res = GetSelection(getter_AddRefs(selection));
    2070               0 :   NS_ENSURE_SUCCESS(res, res);
    2071               0 :   if (!selection)
    2072                 :   {
    2073               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2074                 :   }
    2075                 :   else
    2076                 :   {
    2077               0 :     nsAutoEditBatch beginBatching(this);
    2078               0 :     nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
    2079                 : 
    2080                 :     // give rules a chance to handle or cancel
    2081               0 :     nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
    2082                 :     bool cancel, handled;
    2083               0 :     res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2084               0 :     NS_ENSURE_SUCCESS(res, res);
    2085               0 :     if (cancel) return NS_OK; // rules canceled the operation
    2086               0 :     if (!handled)
    2087                 :     {
    2088               0 :       res = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("blockquote"), getter_AddRefs(newNode));
    2089               0 :       NS_ENSURE_SUCCESS(res, res);
    2090               0 :       NS_ENSURE_TRUE(newNode, NS_ERROR_NULL_POINTER);
    2091                 : 
    2092                 :       // Try to set type=cite.  Ignore it if this fails.
    2093               0 :       nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
    2094               0 :       if (newElement)
    2095                 :       {
    2096               0 :         NS_NAMED_LITERAL_STRING(citestr, "cite");
    2097               0 :         newElement->SetAttribute(NS_LITERAL_STRING("type"), citestr);
    2098                 : 
    2099               0 :         if (!aCitation.IsEmpty())
    2100               0 :           newElement->SetAttribute(citestr, aCitation);
    2101                 : 
    2102                 :         // Set the selection inside the blockquote so aQuotedText will go there:
    2103               0 :         selection->Collapse(newNode, 0);
    2104                 :       }
    2105                 : 
    2106               0 :       if (aInsertHTML)
    2107               0 :         res = LoadHTML(aQuotedText);
    2108                 : 
    2109                 :       else
    2110               0 :         res = InsertText(aQuotedText);  // XXX ignore charset
    2111                 : 
    2112               0 :       if (aNodeInserted)
    2113                 :       {
    2114               0 :         if (NS_SUCCEEDED(res))
    2115                 :         {
    2116               0 :           *aNodeInserted = newNode;
    2117               0 :           NS_IF_ADDREF(*aNodeInserted);
    2118                 :         }
    2119                 :       }
    2120                 :     }
    2121                 :   }
    2122                 : 
    2123                 :   // Set the selection to just after the inserted node:
    2124               0 :   if (NS_SUCCEEDED(res) && newNode)
    2125                 :   {
    2126               0 :     nsCOMPtr<nsIDOMNode> parent;
    2127                 :     PRInt32 offset;
    2128               0 :     if (NS_SUCCEEDED(GetNodeLocation(newNode, address_of(parent), &offset)) && parent)
    2129               0 :       selection->Collapse(parent, offset+1);
    2130                 :   }
    2131               0 :   return res;
    2132                 : }
    2133                 : 
    2134                 : 
    2135               0 : void RemoveBodyAndHead(nsIDOMNode *aNode)
    2136                 : {
    2137               0 :   if (!aNode) 
    2138               0 :     return;
    2139                 :     
    2140               0 :   nsCOMPtr<nsIDOMNode> tmp, child, body, head;  
    2141                 :   // find the body and head nodes if any.
    2142                 :   // look only at immediate children of aNode.
    2143               0 :   aNode->GetFirstChild(getter_AddRefs(child));
    2144               0 :   while (child)
    2145                 :   {
    2146               0 :     if (nsTextEditUtils::IsBody(child))
    2147                 :     {
    2148               0 :       body = child;
    2149                 :     }
    2150               0 :     else if (nsEditor::NodeIsType(child, nsEditProperty::head))
    2151                 :     {
    2152               0 :       head = child;
    2153                 :     }
    2154               0 :     child->GetNextSibling(getter_AddRefs(tmp));
    2155               0 :     child = tmp;
    2156                 :   }
    2157               0 :   if (head) 
    2158                 :   {
    2159               0 :     aNode->RemoveChild(head, getter_AddRefs(tmp));
    2160                 :   }
    2161               0 :   if (body)
    2162                 :   {
    2163               0 :     body->GetFirstChild(getter_AddRefs(child));
    2164               0 :     while (child)
    2165                 :     {
    2166               0 :       aNode->InsertBefore(child, body, getter_AddRefs(tmp));
    2167               0 :       body->GetFirstChild(getter_AddRefs(child));
    2168                 :     }
    2169               0 :     aNode->RemoveChild(body, getter_AddRefs(tmp));
    2170                 :   }
    2171                 : }
    2172                 : 
    2173                 : /**
    2174                 :  * This function finds the target node that we will be pasting into. aStart is
    2175                 :  * the context that we're given and aResult will be the target. Initially,
    2176                 :  * *aResult must be NULL.
    2177                 :  *
    2178                 :  * The target for a paste is found by either finding the node that contains
    2179                 :  * the magical comment node containing kInsertCookie or, failing that, the
    2180                 :  * firstChild of the firstChild (until we reach a leaf).
    2181                 :  */
    2182               0 : nsresult FindTargetNode(nsIDOMNode *aStart, nsCOMPtr<nsIDOMNode> &aResult)
    2183                 : {
    2184               0 :   NS_ENSURE_TRUE(aStart, NS_OK);
    2185                 : 
    2186               0 :   nsCOMPtr<nsIDOMNode> child, tmp;
    2187                 : 
    2188               0 :   nsresult rv = aStart->GetFirstChild(getter_AddRefs(child));
    2189               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2190                 : 
    2191               0 :   if (!child)
    2192                 :   {
    2193                 :     // If the current result is NULL, then aStart is a leaf, and is the
    2194                 :     // fallback result.
    2195               0 :     if (!aResult)
    2196               0 :       aResult = aStart;
    2197                 : 
    2198               0 :     return NS_OK;
    2199                 :   }
    2200                 : 
    2201               0 :   do
    2202                 :   {
    2203                 :     // Is this child the magical cookie?
    2204               0 :     nsCOMPtr<nsIDOMComment> comment = do_QueryInterface(child);
    2205               0 :     if (comment)
    2206                 :     {
    2207               0 :       nsAutoString data;
    2208               0 :       rv = comment->GetData(data);
    2209               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2210                 : 
    2211               0 :       if (data.EqualsLiteral(kInsertCookie))
    2212                 :       {
    2213                 :         // Yes it is! Return an error so we bubble out and short-circuit the
    2214                 :         // search.
    2215               0 :         aResult = aStart;
    2216                 : 
    2217                 :         // Note: it doesn't matter if this fails.
    2218               0 :         aStart->RemoveChild(child, getter_AddRefs(tmp));
    2219                 : 
    2220               0 :         return NS_FOUND_TARGET;
    2221                 :       }
    2222                 :     }
    2223                 : 
    2224                 :     // Note: Don't use NS_ENSURE_* here since we return a failure result to
    2225                 :     // inicate that we found the magical cookie and we don't want to spam the
    2226                 :     // console.
    2227               0 :     rv = FindTargetNode(child, aResult);
    2228               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2229                 : 
    2230               0 :     rv = child->GetNextSibling(getter_AddRefs(tmp));
    2231               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2232                 : 
    2233               0 :     child = tmp;
    2234               0 :   } while (child);
    2235                 : 
    2236               0 :   return NS_OK;
    2237                 : }
    2238                 : 
    2239               0 : nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(const nsAString &aInputString,
    2240                 :                                                   const nsAString & aContextStr,
    2241                 :                                                   const nsAString & aInfoStr,
    2242                 :                                                   nsCOMPtr<nsIDOMNode> *outFragNode,
    2243                 :                                                   nsCOMPtr<nsIDOMNode> *outStartNode,
    2244                 :                                                   nsCOMPtr<nsIDOMNode> *outEndNode,
    2245                 :                                                   PRInt32 *outStartOffset,
    2246                 :                                                   PRInt32 *outEndOffset,
    2247                 :                                                   bool aTrustedInput)
    2248                 : {
    2249               0 :   NS_ENSURE_TRUE(outFragNode && outStartNode && outEndNode, NS_ERROR_NULL_POINTER);
    2250               0 :   nsCOMPtr<nsIDOMDocumentFragment> docfrag;
    2251               0 :   nsCOMPtr<nsIDOMNode> contextAsNode, tmp;  
    2252               0 :   nsresult res = NS_OK;
    2253                 : 
    2254               0 :   nsCOMPtr<nsIDOMDocument> domDoc;
    2255               0 :   GetDocument(getter_AddRefs(domDoc));
    2256                 : 
    2257               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    2258               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    2259                 :   
    2260                 :   // if we have context info, create a fragment for that
    2261               0 :   nsCOMPtr<nsIDOMDocumentFragment> contextfrag;
    2262               0 :   nsCOMPtr<nsIDOMNode> contextLeaf, junk;
    2263               0 :   if (!aContextStr.IsEmpty())
    2264                 :   {
    2265                 :     res = ParseFragment(aContextStr, nsnull, doc, address_of(contextAsNode),
    2266               0 :                         aTrustedInput);
    2267               0 :     NS_ENSURE_SUCCESS(res, res);
    2268               0 :     NS_ENSURE_TRUE(contextAsNode, NS_ERROR_FAILURE);
    2269                 : 
    2270               0 :     res = StripFormattingNodes(contextAsNode);
    2271               0 :     NS_ENSURE_SUCCESS(res, res);
    2272                 : 
    2273               0 :     RemoveBodyAndHead(contextAsNode);
    2274                 : 
    2275               0 :     res = FindTargetNode(contextAsNode, contextLeaf);
    2276               0 :     if (res == NS_FOUND_TARGET)
    2277               0 :       res = NS_OK;
    2278               0 :     NS_ENSURE_SUCCESS(res, res);
    2279                 :   }
    2280                 : 
    2281               0 :   nsCOMPtr<nsIContent> contextLeafAsContent = do_QueryInterface(contextLeaf);
    2282                 : 
    2283                 :   // create fragment for pasted html
    2284                 :   nsIAtom* contextAtom;
    2285               0 :   if (contextLeafAsContent) {
    2286               0 :     contextAtom = contextLeafAsContent->Tag();
    2287               0 :     if (contextAtom == nsGkAtoms::html) {
    2288               0 :       contextAtom = nsGkAtoms::body;
    2289                 :     }
    2290                 :   } else {
    2291               0 :     contextAtom = nsGkAtoms::body;
    2292                 :   }
    2293                 :   res = ParseFragment(aInputString,
    2294                 :                       contextAtom,
    2295                 :                       doc,
    2296                 :                       outFragNode,
    2297               0 :                       aTrustedInput);
    2298               0 :   NS_ENSURE_SUCCESS(res, res);
    2299               0 :   NS_ENSURE_TRUE(*outFragNode, NS_ERROR_FAILURE);
    2300                 : 
    2301               0 :   RemoveBodyAndHead(*outFragNode);
    2302                 : 
    2303               0 :   if (contextAsNode)
    2304                 :   {
    2305                 :     // unite the two trees
    2306               0 :     contextLeaf->AppendChild(*outFragNode, getter_AddRefs(junk));
    2307               0 :     *outFragNode = contextAsNode;
    2308                 :   }
    2309                 : 
    2310               0 :   res = StripFormattingNodes(*outFragNode, true);
    2311               0 :   NS_ENSURE_SUCCESS(res, res);
    2312                 : 
    2313                 :   // If there was no context, then treat all of the data we did get as the
    2314                 :   // pasted data.
    2315               0 :   if (contextLeaf)
    2316               0 :     *outEndNode = *outStartNode = contextLeaf;
    2317                 :   else
    2318               0 :     *outEndNode = *outStartNode = *outFragNode;
    2319                 : 
    2320               0 :   *outStartOffset = 0;
    2321                 : 
    2322                 :   // get the infoString contents
    2323               0 :   nsAutoString numstr1, numstr2;
    2324               0 :   if (!aInfoStr.IsEmpty())
    2325                 :   {
    2326                 :     PRInt32 err, sep, num;
    2327               0 :     sep = aInfoStr.FindChar((PRUnichar)',');
    2328               0 :     numstr1 = Substring(aInfoStr, 0, sep);
    2329               0 :     numstr2 = Substring(aInfoStr, sep+1, aInfoStr.Length() - (sep+1));
    2330                 : 
    2331                 :     // Move the start and end children.
    2332               0 :     num = numstr1.ToInteger(&err);
    2333               0 :     while (num--)
    2334                 :     {
    2335               0 :       (*outStartNode)->GetFirstChild(getter_AddRefs(tmp));
    2336               0 :       NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    2337               0 :       tmp.swap(*outStartNode);
    2338                 :     }
    2339                 : 
    2340               0 :     num = numstr2.ToInteger(&err);
    2341               0 :     while (num--)
    2342                 :     {
    2343               0 :       (*outEndNode)->GetLastChild(getter_AddRefs(tmp));
    2344               0 :       NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    2345               0 :       tmp.swap(*outEndNode);
    2346                 :     }
    2347                 :   }
    2348                 : 
    2349               0 :   GetLengthOfDOMNode(*outEndNode, (PRUint32&)*outEndOffset);
    2350               0 :   return res;
    2351                 : }
    2352                 : 
    2353                 : 
    2354               0 : nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr,
    2355                 :                                      nsIAtom* aContextLocalName,
    2356                 :                                      nsIDocument* aTargetDocument,
    2357                 :                                      nsCOMPtr<nsIDOMNode> *outNode,
    2358                 :                                      bool aTrustedInput)
    2359                 : {
    2360                 :   nsresult rv;
    2361               0 :   nsCOMPtr<nsIDOMDocumentFragment> frag;
    2362               0 :   NS_NewDocumentFragment(getter_AddRefs(frag),
    2363               0 :                          aTargetDocument->NodeInfoManager());
    2364               0 :   nsCOMPtr<nsIContent> fragment = do_QueryInterface(frag);
    2365                 :   rv = nsContentUtils::ParseFragmentHTML(aFragStr,
    2366                 :                                          fragment,
    2367                 :                                          aContextLocalName ?
    2368                 :                                            aContextLocalName : nsGkAtoms::body,
    2369                 :                                         kNameSpaceID_XHTML,
    2370                 :                                         false,
    2371               0 :                                         true);
    2372               0 :   if (!aTrustedInput) {
    2373               0 :     nsTreeSanitizer sanitizer(!!aContextLocalName, !aContextLocalName);
    2374               0 :     sanitizer.Sanitize(fragment);
    2375                 :   }
    2376               0 :   *outNode = do_QueryInterface(frag);
    2377               0 :   return rv;
    2378                 : }
    2379                 : 
    2380               0 : nsresult nsHTMLEditor::CreateListOfNodesToPaste(nsIDOMNode  *aFragmentAsNode,
    2381                 :                                                 nsCOMArray<nsIDOMNode>& outNodeList,
    2382                 :                                                 nsIDOMNode *aStartNode,
    2383                 :                                                 PRInt32 aStartOffset,
    2384                 :                                                 nsIDOMNode *aEndNode,
    2385                 :                                                 PRInt32 aEndOffset)
    2386                 : {
    2387               0 :   NS_ENSURE_TRUE(aFragmentAsNode, NS_ERROR_NULL_POINTER);
    2388                 : 
    2389                 :   nsresult res;
    2390                 : 
    2391                 :   // if no info was provided about the boundary between context and stream,
    2392                 :   // then assume all is stream.
    2393               0 :   if (!aStartNode)
    2394                 :   {
    2395                 :     PRInt32 fragLen;
    2396               0 :     res = GetLengthOfDOMNode(aFragmentAsNode, (PRUint32&)fragLen);
    2397               0 :     NS_ENSURE_SUCCESS(res, res);
    2398                 : 
    2399               0 :     aStartNode = aFragmentAsNode;
    2400               0 :     aStartOffset = 0;
    2401               0 :     aEndNode = aFragmentAsNode;
    2402               0 :     aEndOffset = fragLen;
    2403                 :   }
    2404                 : 
    2405               0 :   nsRefPtr<nsRange> docFragRange = new nsRange();
    2406               0 :   res = docFragRange->SetStart(aStartNode, aStartOffset);
    2407               0 :   NS_ENSURE_SUCCESS(res, res);
    2408               0 :   res = docFragRange->SetEnd(aEndNode, aEndOffset);
    2409               0 :   NS_ENSURE_SUCCESS(res, res);
    2410                 : 
    2411                 :   // now use a subtree iterator over the range to create a list of nodes
    2412               0 :   nsTrivialFunctor functor;
    2413               0 :   nsDOMSubtreeIterator iter;
    2414               0 :   res = iter.Init(docFragRange);
    2415               0 :   NS_ENSURE_SUCCESS(res, res);
    2416               0 :   res = iter.AppendList(functor, outNodeList);
    2417                 : 
    2418               0 :   return res;
    2419                 : }
    2420                 : 
    2421                 : nsresult 
    2422               0 : nsHTMLEditor::GetListAndTableParents(bool aEnd, 
    2423                 :                                      nsCOMArray<nsIDOMNode>& aListOfNodes,
    2424                 :                                      nsCOMArray<nsIDOMNode>& outArray)
    2425                 : {
    2426               0 :   PRInt32 listCount = aListOfNodes.Count();
    2427               0 :   if (listCount <= 0)
    2428               0 :     return NS_ERROR_FAILURE;  // no empty lists, please
    2429                 :     
    2430                 :   // build up list of parents of first (or last) node in list 
    2431                 :   // that are either lists, or tables.  
    2432               0 :   PRInt32 idx = 0;
    2433               0 :   if (aEnd) idx = listCount-1;
    2434                 :   
    2435               0 :   nsCOMPtr<nsIDOMNode>  pNode = aListOfNodes[idx];
    2436               0 :   while (pNode)
    2437                 :   {
    2438               0 :     if (nsHTMLEditUtils::IsList(pNode) || nsHTMLEditUtils::IsTable(pNode))
    2439                 :     {
    2440               0 :       if (!outArray.AppendObject(pNode))
    2441                 :       {
    2442               0 :         return NS_ERROR_FAILURE;
    2443                 :       }
    2444                 :     }
    2445               0 :     nsCOMPtr<nsIDOMNode> parent;
    2446               0 :     pNode->GetParentNode(getter_AddRefs(parent));
    2447               0 :     pNode = parent;
    2448                 :   }
    2449               0 :   return NS_OK;
    2450                 : }
    2451                 : 
    2452                 : nsresult
    2453               0 : nsHTMLEditor::DiscoverPartialListsAndTables(nsCOMArray<nsIDOMNode>& aPasteNodes,
    2454                 :                                             nsCOMArray<nsIDOMNode>& aListsAndTables,
    2455                 :                                             PRInt32 *outHighWaterMark)
    2456                 : {
    2457               0 :   NS_ENSURE_TRUE(outHighWaterMark, NS_ERROR_NULL_POINTER);
    2458                 :   
    2459               0 :   *outHighWaterMark = -1;
    2460               0 :   PRInt32 listAndTableParents = aListsAndTables.Count();
    2461                 :   
    2462                 :   // scan insertion list for table elements (other than table).
    2463               0 :   PRInt32 listCount = aPasteNodes.Count();
    2464                 :   PRInt32 j;  
    2465               0 :   for (j=0; j<listCount; j++)
    2466                 :   {
    2467               0 :     nsCOMPtr<nsIDOMNode> curNode = aPasteNodes[j];
    2468                 : 
    2469               0 :     NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
    2470               0 :     if (nsHTMLEditUtils::IsTableElement(curNode) && !nsHTMLEditUtils::IsTable(curNode))
    2471                 :     {
    2472               0 :       nsCOMPtr<nsIDOMNode> theTable = GetTableParent(curNode);
    2473               0 :       if (theTable)
    2474                 :       {
    2475               0 :         PRInt32 indexT = aListsAndTables.IndexOf(theTable);
    2476               0 :         if (indexT >= 0)
    2477                 :         {
    2478               0 :           *outHighWaterMark = indexT;
    2479               0 :           if (*outHighWaterMark == listAndTableParents-1) break;
    2480                 :         }
    2481                 :         else
    2482                 :         {
    2483                 :           break;
    2484                 :         }
    2485                 :       }
    2486                 :     }
    2487               0 :     if (nsHTMLEditUtils::IsListItem(curNode))
    2488                 :     {
    2489               0 :       nsCOMPtr<nsIDOMNode> theList = GetListParent(curNode);
    2490               0 :       if (theList)
    2491                 :       {
    2492               0 :         PRInt32 indexL = aListsAndTables.IndexOf(theList);
    2493               0 :         if (indexL >= 0)
    2494                 :         {
    2495               0 :           *outHighWaterMark = indexL;
    2496               0 :           if (*outHighWaterMark == listAndTableParents-1) break;
    2497                 :         }
    2498                 :         else
    2499                 :         {
    2500                 :           break;
    2501                 :         }
    2502                 :       }
    2503                 :     }
    2504                 :   }
    2505               0 :   return NS_OK;
    2506                 : }
    2507                 : 
    2508                 : nsresult
    2509               0 : nsHTMLEditor::ScanForListAndTableStructure( bool aEnd,
    2510                 :                                             nsCOMArray<nsIDOMNode>& aNodes,
    2511                 :                                             nsIDOMNode *aListOrTable,
    2512                 :                                             nsCOMPtr<nsIDOMNode> *outReplaceNode)
    2513                 : {
    2514               0 :   NS_ENSURE_TRUE(aListOrTable, NS_ERROR_NULL_POINTER);
    2515               0 :   NS_ENSURE_TRUE(outReplaceNode, NS_ERROR_NULL_POINTER);
    2516                 : 
    2517               0 :   *outReplaceNode = 0;
    2518                 :   
    2519                 :   // look upward from first/last paste node for a piece of this list/table
    2520               0 :   PRInt32 listCount = aNodes.Count(), idx = 0;
    2521               0 :   if (aEnd) idx = listCount-1;
    2522               0 :   bool bList = nsHTMLEditUtils::IsList(aListOrTable);
    2523                 :   
    2524               0 :   nsCOMPtr<nsIDOMNode>  pNode = aNodes[idx];
    2525               0 :   nsCOMPtr<nsIDOMNode>  originalNode = pNode;
    2526               0 :   while (pNode)
    2527                 :   {
    2528               0 :     if ( (bList && nsHTMLEditUtils::IsListItem(pNode)) ||
    2529               0 :          (!bList && (nsHTMLEditUtils::IsTableElement(pNode) && !nsHTMLEditUtils::IsTable(pNode))) )
    2530                 :     {
    2531               0 :       nsCOMPtr<nsIDOMNode> structureNode;
    2532               0 :       if (bList) structureNode = GetListParent(pNode);
    2533               0 :       else structureNode = GetTableParent(pNode);
    2534               0 :       if (structureNode == aListOrTable)
    2535                 :       {
    2536               0 :         if (bList)
    2537               0 :           *outReplaceNode = structureNode;
    2538                 :         else
    2539               0 :           *outReplaceNode = pNode;
    2540                 :         break;
    2541                 :       }
    2542                 :     }
    2543               0 :     nsCOMPtr<nsIDOMNode> parent;
    2544               0 :     pNode->GetParentNode(getter_AddRefs(parent));
    2545               0 :     pNode = parent;
    2546                 :   }
    2547               0 :   return NS_OK;
    2548                 : }    
    2549                 : 
    2550                 : nsresult
    2551               0 : nsHTMLEditor::ReplaceOrphanedStructure(bool aEnd,
    2552                 :                                        nsCOMArray<nsIDOMNode>& aNodeArray,
    2553                 :                                        nsCOMArray<nsIDOMNode>& aListAndTableArray,
    2554                 :                                        PRInt32 aHighWaterMark)
    2555                 : {
    2556               0 :   nsCOMPtr<nsIDOMNode> curNode = aListAndTableArray[aHighWaterMark];
    2557               0 :   NS_ENSURE_TRUE(curNode, NS_ERROR_NULL_POINTER);
    2558                 :   
    2559               0 :   nsCOMPtr<nsIDOMNode> replaceNode, originalNode;
    2560                 :   
    2561                 :   // find substructure of list or table that must be included in paste.
    2562                 :   nsresult res = ScanForListAndTableStructure(aEnd, aNodeArray, 
    2563               0 :                                  curNode, address_of(replaceNode));
    2564               0 :   NS_ENSURE_SUCCESS(res, res);
    2565                 :   
    2566                 :   // if we found substructure, paste it instead of its descendants
    2567               0 :   if (replaceNode)
    2568                 :   {
    2569                 :     // postprocess list to remove any descendants of this node
    2570                 :     // so that we don't insert them twice.
    2571               0 :     nsCOMPtr<nsIDOMNode> endpoint;
    2572               0 :     do
    2573                 :     {
    2574               0 :       endpoint = GetArrayEndpoint(aEnd, aNodeArray);
    2575               0 :       if (!endpoint) break;
    2576               0 :       if (nsEditorUtils::IsDescendantOf(endpoint, replaceNode))
    2577               0 :         aNodeArray.RemoveObject(endpoint);
    2578                 :       else
    2579               0 :         break;
    2580               0 :     } while(endpoint);
    2581                 :     
    2582                 :     // now replace the removed nodes with the structural parent
    2583               0 :     if (aEnd) aNodeArray.AppendObject(replaceNode);
    2584               0 :     else aNodeArray.InsertObjectAt(replaceNode, 0);
    2585                 :   }
    2586               0 :   return NS_OK;
    2587                 : }
    2588                 : 
    2589               0 : nsIDOMNode* nsHTMLEditor::GetArrayEndpoint(bool aEnd,
    2590                 :                                            nsCOMArray<nsIDOMNode>& aNodeArray)
    2591                 : {
    2592               0 :   PRInt32 listCount = aNodeArray.Count();
    2593               0 :   if (listCount <= 0) 
    2594               0 :     return nsnull;
    2595                 : 
    2596               0 :   if (aEnd)
    2597                 :   {
    2598               0 :     return aNodeArray[listCount-1];
    2599                 :   }
    2600                 :   
    2601               0 :   return aNodeArray[0];
    2602                 : }

Generated by: LCOV version 1.7