LCOV - code coverage report
Current view: directory - editor/libeditor/html - nsHTMLEditRules.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 4333 0 0.0 %
Date: 2012-06-02 Functions: 143 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=79: */
       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                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   Daniel Glazman <glazman@netscape.com>
      26                 :  *   Neil Deakin <neil@mozdevgroup.com>
      27                 :  *   Mats Palmgren <matspal@gmail.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "nsHTMLEditRules.h"
      44                 : 
      45                 : #include "nsEditor.h"
      46                 : #include "nsTextEditUtils.h"
      47                 : #include "nsHTMLEditUtils.h"
      48                 : #include "nsHTMLCSSUtils.h"
      49                 : #include "nsHTMLEditor.h"
      50                 : 
      51                 : #include "nsIServiceManager.h"
      52                 : #include "nsCRT.h"
      53                 : #include "nsIContent.h"
      54                 : #include "nsIContentIterator.h"
      55                 : #include "nsIDOMNode.h"
      56                 : #include "nsIDOMText.h"
      57                 : #include "nsIDOMElement.h"
      58                 : #include "nsIDOMNodeList.h"
      59                 : #include "nsISelection.h"
      60                 : #include "nsISelectionPrivate.h"
      61                 : #include "nsISelectionController.h"
      62                 : #include "nsIDOMRange.h"
      63                 : #include "nsIDOMCharacterData.h"
      64                 : #include "nsIEnumerator.h"
      65                 : #include "nsIDOMNamedNodeMap.h"
      66                 : #include "nsRange.h"
      67                 : 
      68                 : #include "nsEditorUtils.h"
      69                 : #include "nsWSRunObject.h"
      70                 : 
      71                 : #include "InsertTextTxn.h"
      72                 : #include "DeleteTextTxn.h"
      73                 : #include "nsReadableUtils.h"
      74                 : #include "nsUnicharUtils.h"
      75                 : 
      76                 : #include "nsFrameSelection.h"
      77                 : #include "nsContentUtils.h"
      78                 : #include "nsTArray.h"
      79                 : #include "nsIHTMLDocument.h"
      80                 : 
      81                 : #include "mozilla/Preferences.h"
      82                 : #include "mozilla/dom/Element.h"
      83                 : 
      84                 : using namespace mozilla;
      85                 : 
      86                 : //const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
      87                 : //const static char* kMOZEditorBogusNodeValue="TRUE";
      88                 : 
      89                 : enum
      90                 : {
      91                 :   kLonely = 0,
      92                 :   kPrevSib = 1,
      93                 :   kNextSib = 2,
      94                 :   kBothSibs = 3
      95                 : };
      96                 : 
      97                 : /********************************************************
      98                 :  *  first some helpful funcotrs we will use
      99                 :  ********************************************************/
     100                 : 
     101               0 : static bool IsBlockNode(nsIDOMNode* node)
     102                 : {
     103               0 :   bool isBlock (false);
     104               0 :   nsHTMLEditor::NodeIsBlockStatic(node, &isBlock);
     105               0 :   return isBlock;
     106                 : }
     107                 : 
     108               0 : static bool IsInlineNode(nsIDOMNode* node)
     109                 : {
     110               0 :   return !IsBlockNode(node);
     111                 : }
     112                 :  
     113                 : class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor
     114               0 : {
     115                 :   public:
     116               0 :     virtual bool operator()(nsIDOMNode* aNode)  // used to build list of all li's, td's & th's iterator covers
     117                 :     {
     118               0 :       if (nsHTMLEditUtils::IsTableCell(aNode)) return true;
     119               0 :       if (nsHTMLEditUtils::IsListItem(aNode)) return true;
     120               0 :       return false;
     121                 :     }
     122                 : };
     123                 : 
     124                 : class nsBRNodeFunctor : public nsBoolDomIterFunctor
     125               0 : {
     126                 :   public:
     127               0 :     virtual bool operator()(nsIDOMNode* aNode)  
     128                 :     {
     129               0 :       if (nsTextEditUtils::IsBreak(aNode)) return true;
     130               0 :       return false;
     131                 :     }
     132                 : };
     133                 : 
     134                 : class nsEmptyEditableFunctor : public nsBoolDomIterFunctor
     135                 : {
     136                 :   public:
     137               0 :     nsEmptyEditableFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
     138               0 :     virtual bool operator()(nsIDOMNode* aNode)  
     139                 :     {
     140               0 :       if (mHTMLEditor->IsEditable(aNode) &&
     141               0 :         (nsHTMLEditUtils::IsListItem(aNode) ||
     142               0 :         nsHTMLEditUtils::IsTableCellOrCaption(aNode)))
     143                 :       {
     144                 :         bool bIsEmptyNode;
     145               0 :         nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, false, false);
     146               0 :         NS_ENSURE_SUCCESS(res, false);
     147               0 :         if (bIsEmptyNode)
     148               0 :           return true;
     149                 :       }
     150               0 :       return false;
     151                 :     }
     152                 :   protected:
     153                 :     nsHTMLEditor* mHTMLEditor;
     154                 : };
     155                 : 
     156                 : class nsEditableTextFunctor : public nsBoolDomIterFunctor
     157                 : {
     158                 :   public:
     159                 :     nsEditableTextFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
     160                 :     virtual bool operator()(nsIDOMNode* aNode)  
     161                 :     {
     162                 :       if (nsEditor::IsTextNode(aNode) && mHTMLEditor->IsEditable(aNode)) 
     163                 :       {
     164                 :         return true;
     165                 :       }
     166                 :       return false;
     167                 :     }
     168                 :   protected:
     169                 :     nsHTMLEditor* mHTMLEditor;
     170                 : };
     171                 : 
     172                 : 
     173                 : /********************************************************
     174                 :  *  Constructor/Destructor 
     175                 :  ********************************************************/
     176                 : 
     177               0 : nsHTMLEditRules::nsHTMLEditRules() : 
     178                 : mDocChangeRange(nsnull)
     179                 : ,mListenerEnabled(true)
     180                 : ,mReturnInEmptyLIKillsList(true)
     181                 : ,mDidDeleteSelection(false)
     182                 : ,mDidRangedDelete(false)
     183                 : ,mRestoreContentEditableCount(false)
     184                 : ,mUtilRange(nsnull)
     185               0 : ,mJoinOffset(0)
     186                 : {
     187                 :   // populate mCachedStyles
     188               0 :   mCachedStyles[0] = StyleCache(nsEditProperty::b, EmptyString(), EmptyString());
     189               0 :   mCachedStyles[1] = StyleCache(nsEditProperty::i, EmptyString(), EmptyString());
     190               0 :   mCachedStyles[2] = StyleCache(nsEditProperty::u, EmptyString(), EmptyString());
     191               0 :   mCachedStyles[3] = StyleCache(nsEditProperty::font, NS_LITERAL_STRING("face"), EmptyString());
     192               0 :   mCachedStyles[4] = StyleCache(nsEditProperty::font, NS_LITERAL_STRING("size"), EmptyString());
     193               0 :   mCachedStyles[5] = StyleCache(nsEditProperty::font, NS_LITERAL_STRING("color"), EmptyString());
     194               0 :   mCachedStyles[6] = StyleCache(nsEditProperty::tt, EmptyString(), EmptyString());
     195               0 :   mCachedStyles[7] = StyleCache(nsEditProperty::em, EmptyString(), EmptyString());
     196               0 :   mCachedStyles[8] = StyleCache(nsEditProperty::strong, EmptyString(), EmptyString());
     197               0 :   mCachedStyles[9] = StyleCache(nsEditProperty::dfn, EmptyString(), EmptyString());
     198               0 :   mCachedStyles[10] = StyleCache(nsEditProperty::code, EmptyString(), EmptyString());
     199               0 :   mCachedStyles[11] = StyleCache(nsEditProperty::samp, EmptyString(), EmptyString());
     200               0 :   mCachedStyles[12] = StyleCache(nsEditProperty::var, EmptyString(), EmptyString());
     201               0 :   mCachedStyles[13] = StyleCache(nsEditProperty::cite, EmptyString(), EmptyString());
     202               0 :   mCachedStyles[14] = StyleCache(nsEditProperty::abbr, EmptyString(), EmptyString());
     203               0 :   mCachedStyles[15] = StyleCache(nsEditProperty::acronym, EmptyString(), EmptyString());
     204               0 :   mCachedStyles[16] = StyleCache(nsEditProperty::cssBackgroundColor, EmptyString(), EmptyString());
     205               0 :   mCachedStyles[17] = StyleCache(nsEditProperty::sub, EmptyString(), EmptyString());
     206               0 :   mCachedStyles[18] = StyleCache(nsEditProperty::sup, EmptyString(), EmptyString());
     207               0 : }
     208                 : 
     209               0 : nsHTMLEditRules::~nsHTMLEditRules()
     210                 : {
     211                 :   // remove ourselves as a listener to edit actions
     212                 :   // In some cases, we have already been removed by 
     213                 :   // ~nsHTMLEditor, in which case we will get a null pointer here
     214                 :   // which we ignore.  But this allows us to add the ability to
     215                 :   // switch rule sets on the fly if we want.
     216               0 :   if (mHTMLEditor)
     217               0 :     mHTMLEditor->RemoveEditActionListener(this);
     218               0 : }
     219                 : 
     220                 : /********************************************************
     221                 :  *  XPCOM Cruft
     222                 :  ********************************************************/
     223                 : 
     224               0 : NS_IMPL_ADDREF_INHERITED(nsHTMLEditRules, nsTextEditRules)
     225               0 : NS_IMPL_RELEASE_INHERITED(nsHTMLEditRules, nsTextEditRules)
     226               0 : NS_IMPL_QUERY_INTERFACE_INHERITED1(nsHTMLEditRules, nsTextEditRules, nsIEditActionListener)
     227                 : 
     228                 : 
     229                 : /********************************************************
     230                 :  *  Public methods 
     231                 :  ********************************************************/
     232                 : 
     233                 : NS_IMETHODIMP
     234               0 : nsHTMLEditRules::Init(nsPlaintextEditor *aEditor)
     235                 : {
     236               0 :   mHTMLEditor = static_cast<nsHTMLEditor*>(aEditor);
     237                 :   nsresult res;
     238                 :   
     239                 :   // call through to base class Init 
     240               0 :   res = nsTextEditRules::Init(aEditor);
     241               0 :   NS_ENSURE_SUCCESS(res, res);
     242                 : 
     243                 :   // cache any prefs we care about
     244                 :   static const char kPrefName[] =
     245                 :     "editor.html.typing.returnInEmptyListItemClosesList";
     246                 :   nsAdoptingCString returnInEmptyLIKillsList =
     247               0 :     Preferences::GetCString(kPrefName);
     248                 : 
     249                 :   // only when "false", becomes FALSE.  Otherwise (including empty), TRUE.
     250                 :   // XXX Why was this pref designed as a string and not bool?
     251               0 :   mReturnInEmptyLIKillsList = !returnInEmptyLIKillsList.EqualsLiteral("false");
     252                 : 
     253                 :   // make a utility range for use by the listenter
     254               0 :   mUtilRange = new nsRange();
     255                 :    
     256                 :   // set up mDocChangeRange to be whole doc
     257               0 :   nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
     258               0 :   if (rootElem)
     259                 :   {
     260                 :     // temporarily turn off rules sniffing
     261               0 :     nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
     262               0 :     if (!mDocChangeRange)
     263                 :     {
     264               0 :       mDocChangeRange = new nsRange();
     265                 :     }
     266               0 :     mDocChangeRange->SelectNode(rootElem);
     267               0 :     res = AdjustSpecialBreaks();
     268               0 :     NS_ENSURE_SUCCESS(res, res);
     269                 :   }
     270                 : 
     271                 :   // add ourselves as a listener to edit actions
     272               0 :   res = mHTMLEditor->AddEditActionListener(this);
     273                 : 
     274               0 :   return res;
     275                 : }
     276                 : 
     277                 : NS_IMETHODIMP
     278               0 : nsHTMLEditRules::DetachEditor()
     279                 : {
     280               0 :   mHTMLEditor = nsnull;
     281               0 :   return nsTextEditRules::DetachEditor();
     282                 : }
     283                 : 
     284                 : NS_IMETHODIMP
     285               0 : nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
     286                 : {
     287               0 :   if (mLockRulesSniffing) return NS_OK;
     288                 :   
     289               0 :   nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
     290               0 :   mDidExplicitlySetInterline = false;
     291                 : 
     292               0 :   if (!mActionNesting++)
     293                 :   {
     294                 :     // clear our flag about if just deleted a range
     295               0 :     mDidRangedDelete = false;
     296                 :     
     297                 :     // remember where our selection was before edit action took place:
     298                 :     
     299                 :     // get selection
     300               0 :     nsCOMPtr<nsISelection> selection;
     301               0 :     nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     302               0 :     NS_ENSURE_SUCCESS(res, res);
     303                 :   
     304                 :     // get the selection start location
     305               0 :     nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
     306                 :     PRInt32 selOffset;
     307               0 :     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selOffset);
     308               0 :     NS_ENSURE_SUCCESS(res, res);
     309               0 :     mRangeItem.startNode = selStartNode;
     310               0 :     mRangeItem.startOffset = selOffset;
     311                 : 
     312                 :     // get the selection end location
     313               0 :     res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selOffset);
     314               0 :     NS_ENSURE_SUCCESS(res, res);
     315               0 :     mRangeItem.endNode = selEndNode;
     316               0 :     mRangeItem.endOffset = selOffset;
     317                 : 
     318                 :     // register this range with range updater to track this as we perturb the doc
     319               0 :     (mHTMLEditor->mRangeUpdater).RegisterRangeItem(&mRangeItem);
     320                 : 
     321                 :     // clear deletion state bool
     322               0 :     mDidDeleteSelection = false;
     323                 :     
     324                 :     // clear out mDocChangeRange and mUtilRange
     325               0 :     if(mDocChangeRange)
     326                 :     {
     327                 :       // clear out our accounting of what changed
     328               0 :       mDocChangeRange->Reset(); 
     329                 :     }
     330               0 :     if(mUtilRange)
     331                 :     {
     332                 :       // ditto for mUtilRange.
     333               0 :       mUtilRange->Reset(); 
     334                 :     }
     335                 : 
     336                 :     // remember current inline styles for deletion and normal insertion operations
     337               0 :     if ((action == nsEditor::kOpInsertText)      || 
     338                 :         (action == nsEditor::kOpInsertIMEText)   ||
     339                 :         (action == nsEditor::kOpDeleteSelection) ||
     340                 :         (action == nsEditor::kOpInsertBreak))
     341                 :     {
     342               0 :       nsCOMPtr<nsIDOMNode> selNode = selStartNode;
     343               0 :       if (aDirection == nsIEditor::eNext)
     344               0 :         selNode = selEndNode;
     345               0 :       res = CacheInlineStyles(selNode);
     346               0 :       NS_ENSURE_SUCCESS(res, res);
     347                 :     }
     348                 : 
     349                 :     // Stabilize the document against contenteditable count changes
     350               0 :     nsCOMPtr<nsIDOMDocument> doc;
     351               0 :     res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
     352               0 :     NS_ENSURE_SUCCESS(res, res);
     353               0 :     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
     354               0 :     NS_ENSURE_TRUE(htmlDoc, NS_ERROR_FAILURE);
     355               0 :     if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
     356               0 :       htmlDoc->ChangeContentEditableCount(nsnull, +1);
     357               0 :       mRestoreContentEditableCount = true;
     358                 :     }
     359                 : 
     360                 :     // check that selection is in subtree defined by body node
     361               0 :     ConfirmSelectionInBody();
     362                 :     // let rules remember the top level action
     363               0 :     mTheAction = action;
     364                 :   }
     365               0 :   return NS_OK;
     366                 : }
     367                 : 
     368                 : 
     369                 : NS_IMETHODIMP
     370               0 : nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
     371                 : {
     372               0 :   if (mLockRulesSniffing) return NS_OK;
     373                 : 
     374               0 :   nsAutoLockRulesSniffing lockIt(this);
     375                 : 
     376               0 :   NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
     377               0 :   nsresult res = NS_OK;
     378               0 :   if (!--mActionNesting)
     379                 :   {
     380                 :     // do all the tricky stuff
     381               0 :     res = AfterEditInner(action, aDirection);
     382                 : 
     383                 :     // free up selectionState range item
     384               0 :     (mHTMLEditor->mRangeUpdater).DropRangeItem(&mRangeItem);
     385                 : 
     386                 :     // Reset the contenteditable count to its previous value
     387               0 :     if (mRestoreContentEditableCount) {
     388               0 :       nsCOMPtr<nsIDOMDocument> doc;
     389               0 :       res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
     390               0 :       NS_ENSURE_SUCCESS(res, res);
     391               0 :       nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
     392               0 :       NS_ENSURE_TRUE(htmlDoc, NS_ERROR_FAILURE);
     393               0 :       if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
     394               0 :         htmlDoc->ChangeContentEditableCount(nsnull, -1);
     395                 :       }
     396               0 :       mRestoreContentEditableCount = false;
     397                 :     }
     398                 :   }
     399                 : 
     400               0 :   return res;
     401                 : }
     402                 : 
     403                 : 
     404                 : nsresult
     405               0 : nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection)
     406                 : {
     407               0 :   ConfirmSelectionInBody();
     408               0 :   if (action == nsEditor::kOpIgnore) return NS_OK;
     409                 :   
     410               0 :   nsCOMPtr<nsISelection>selection;
     411               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     412               0 :   NS_ENSURE_SUCCESS(res, res);
     413                 :   
     414               0 :   nsCOMPtr<nsIDOMNode> rangeStartParent, rangeEndParent;
     415               0 :   PRInt32 rangeStartOffset = 0, rangeEndOffset = 0;
     416                 :   // do we have a real range to act on?
     417               0 :   bool bDamagedRange = false;  
     418               0 :   if (mDocChangeRange)
     419                 :   {  
     420               0 :     mDocChangeRange->GetStartContainer(getter_AddRefs(rangeStartParent));
     421               0 :     mDocChangeRange->GetEndContainer(getter_AddRefs(rangeEndParent));
     422               0 :     mDocChangeRange->GetStartOffset(&rangeStartOffset);
     423               0 :     mDocChangeRange->GetEndOffset(&rangeEndOffset);
     424               0 :     if (rangeStartParent && rangeEndParent) 
     425               0 :       bDamagedRange = true; 
     426                 :   }
     427                 :   
     428               0 :   if (bDamagedRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
     429                 :   {
     430                 :     // don't let any txns in here move the selection around behind our back.
     431                 :     // Note that this won't prevent explicit selection setting from working.
     432               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
     433                 :    
     434                 :     // expand the "changed doc range" as needed
     435               0 :     res = PromoteRange(mDocChangeRange, action);
     436               0 :     NS_ENSURE_SUCCESS(res, res);
     437                 : 
     438                 :     // if we did a ranged deletion, make sure we have a place to put caret.
     439                 :     // Note we only want to do this if the overall operation was deletion,
     440                 :     // not if deletion was done along the way for kOpLoadHTML, kOpInsertText, etc.
     441                 :     // That's why this is here rather than DidDeleteSelection().
     442               0 :     if ((action == nsEditor::kOpDeleteSelection) && mDidRangedDelete)
     443                 :     {
     444               0 :       res = InsertBRIfNeeded(selection);
     445               0 :       NS_ENSURE_SUCCESS(res, res);
     446                 :     }  
     447                 :     
     448                 :     // add in any needed <br>s, and remove any unneeded ones.
     449               0 :     res = AdjustSpecialBreaks();
     450               0 :     NS_ENSURE_SUCCESS(res, res);
     451                 :     
     452                 :     // merge any adjacent text nodes
     453               0 :     if ( (action != nsEditor::kOpInsertText &&
     454                 :          action != nsEditor::kOpInsertIMEText) )
     455                 :     {
     456               0 :       res = mHTMLEditor->CollapseAdjacentTextNodes(mDocChangeRange);
     457               0 :       NS_ENSURE_SUCCESS(res, res);
     458                 :     }
     459                 : 
     460                 :     // clean up any empty nodes in the selection
     461               0 :     res = RemoveEmptyNodes();
     462               0 :     NS_ENSURE_SUCCESS(res, res);
     463                 : 
     464                 :     // attempt to transform any unneeded nbsp's into spaces after doing various operations
     465               0 :     if ((action == nsEditor::kOpInsertText) || 
     466                 :         (action == nsEditor::kOpInsertIMEText) ||
     467                 :         (action == nsEditor::kOpDeleteSelection) ||
     468                 :         (action == nsEditor::kOpInsertBreak) || 
     469                 :         (action == nsHTMLEditor::kOpHTMLPaste ||
     470                 :         (action == nsHTMLEditor::kOpLoadHTML)))
     471                 :     {
     472               0 :       res = AdjustWhitespace(selection);
     473               0 :       NS_ENSURE_SUCCESS(res, res);
     474                 :       
     475                 :       // also do this for original selection endpoints. 
     476               0 :       nsWSRunObject(mHTMLEditor, mRangeItem.startNode, mRangeItem.startOffset).AdjustWhitespace();
     477                 :       // we only need to handle old selection endpoint if it was different from start
     478               0 :       if ((mRangeItem.startNode != mRangeItem.endNode) || (mRangeItem.startOffset != mRangeItem.endOffset))
     479                 :       {
     480               0 :         nsWSRunObject(mHTMLEditor, mRangeItem.endNode, mRangeItem.endOffset).AdjustWhitespace();
     481                 :       }
     482                 :     }
     483                 :     
     484                 :     // if we created a new block, make sure selection lands in it
     485               0 :     if (mNewBlock)
     486                 :     {
     487               0 :       res = PinSelectionToNewBlock(selection);
     488               0 :       mNewBlock = 0;
     489                 :     }
     490                 : 
     491                 :     // adjust selection for insert text, html paste, and delete actions
     492               0 :     if ((action == nsEditor::kOpInsertText) || 
     493                 :         (action == nsEditor::kOpInsertIMEText) ||
     494                 :         (action == nsEditor::kOpDeleteSelection) ||
     495                 :         (action == nsEditor::kOpInsertBreak) || 
     496                 :         (action == nsHTMLEditor::kOpHTMLPaste ||
     497                 :         (action == nsHTMLEditor::kOpLoadHTML)))
     498                 :     {
     499               0 :       res = AdjustSelection(selection, aDirection);
     500               0 :       NS_ENSURE_SUCCESS(res, res);
     501                 :     }
     502                 : 
     503                 :     // check for any styles which were removed inappropriately
     504               0 :     if ((action == nsEditor::kOpInsertText)      || 
     505                 :         (action == nsEditor::kOpInsertIMEText)   ||
     506                 :         (action == nsEditor::kOpDeleteSelection) ||
     507                 :         (action == nsEditor::kOpInsertBreak))
     508                 :     {
     509               0 :       mHTMLEditor->mTypeInState->UpdateSelState(selection);
     510               0 :       res = ReapplyCachedStyles();
     511               0 :       NS_ENSURE_SUCCESS(res, res);
     512               0 :       res = ClearCachedStyles();
     513               0 :       NS_ENSURE_SUCCESS(res, res);
     514                 :     }    
     515                 :   }
     516                 : 
     517                 :   res = mHTMLEditor->HandleInlineSpellCheck(action, selection, 
     518                 :                                             mRangeItem.startNode, mRangeItem.startOffset,
     519                 :                                             rangeStartParent, rangeStartOffset,
     520               0 :                                             rangeEndParent, rangeEndOffset);
     521               0 :   NS_ENSURE_SUCCESS(res, res);
     522                 : 
     523                 :   // detect empty doc
     524               0 :   res = CreateBogusNodeIfNeeded(selection);
     525                 :   
     526                 :   // adjust selection HINT if needed
     527               0 :   NS_ENSURE_SUCCESS(res, res);
     528                 :   
     529               0 :   if (!mDidExplicitlySetInterline)
     530                 :   {
     531               0 :     res = CheckInterlinePosition(selection);
     532                 :   }
     533                 :   
     534               0 :   return res;
     535                 : }
     536                 : 
     537                 : 
     538                 : NS_IMETHODIMP 
     539               0 : nsHTMLEditRules::WillDoAction(nsISelection *aSelection, 
     540                 :                               nsRulesInfo *aInfo, 
     541                 :                               bool *aCancel, 
     542                 :                               bool *aHandled)
     543                 : {
     544               0 :   NS_ENSURE_TRUE(aInfo && aCancel && aHandled, NS_ERROR_NULL_POINTER);
     545                 : #if defined(DEBUG_ftang)
     546                 :   printf("nsHTMLEditRules::WillDoAction action = %d\n", aInfo->action);
     547                 : #endif
     548                 : 
     549               0 :   *aCancel = false;
     550               0 :   *aHandled = false;
     551                 :     
     552                 :   // my kingdom for dynamic cast
     553               0 :   nsTextRulesInfo *info = static_cast<nsTextRulesInfo*>(aInfo);
     554                 : 
     555                 :   // Deal with actions for which we don't need to check whether the selection is
     556                 :   // editable.
     557               0 :   if (info->action == kOutputText ||
     558                 :       info->action == kUndo ||
     559                 :       info->action == kRedo)
     560                 :   {
     561               0 :     return nsTextEditRules::WillDoAction(aSelection, aInfo, aCancel, aHandled);
     562                 :   }
     563                 : 
     564               0 :   nsCOMPtr<nsIDOMRange> domRange;
     565               0 :   nsresult rv = aSelection->GetRangeAt(0, getter_AddRefs(domRange));
     566               0 :   NS_ENSURE_SUCCESS(rv, rv);
     567                 : 
     568               0 :   nsCOMPtr<nsIDOMNode> selStartNode;
     569               0 :   rv = domRange->GetStartContainer(getter_AddRefs(selStartNode));
     570               0 :   NS_ENSURE_SUCCESS(rv, rv);
     571                 : 
     572               0 :   if (!mHTMLEditor->IsModifiableNode(selStartNode))
     573                 :   {
     574               0 :     *aCancel = true;
     575                 : 
     576               0 :     return NS_OK;
     577                 :   }
     578                 : 
     579               0 :   nsCOMPtr<nsIDOMNode> selEndNode;
     580               0 :   rv = domRange->GetEndContainer(getter_AddRefs(selEndNode));
     581               0 :   NS_ENSURE_SUCCESS(rv, rv);
     582                 : 
     583               0 :   if (selStartNode != selEndNode)
     584                 :   {
     585               0 :     if (!mHTMLEditor->IsModifiableNode(selEndNode))
     586                 :     {
     587               0 :       *aCancel = true;
     588                 : 
     589               0 :       return NS_OK;
     590                 :     }
     591                 : 
     592               0 :     nsRange* range = static_cast<nsRange*>(domRange.get());
     593                 :     nsCOMPtr<nsIDOMNode> ancestor =
     594               0 :       do_QueryInterface(range->GetCommonAncestor());
     595               0 :     if (!mHTMLEditor->IsModifiableNode(ancestor))
     596                 :     {
     597               0 :       *aCancel = true;
     598                 : 
     599               0 :       return NS_OK;
     600                 :     }
     601                 :   }
     602                 : 
     603               0 :   switch (info->action)
     604                 :   {
     605                 :     case kInsertText:
     606                 :     case kInsertTextIME:
     607                 :       return WillInsertText(info->action,
     608                 :                             aSelection, 
     609                 :                             aCancel, 
     610                 :                             aHandled,
     611                 :                             info->inString,
     612                 :                             info->outString,
     613               0 :                             info->maxLength);
     614                 :     case kLoadHTML:
     615               0 :       return WillLoadHTML(aSelection, aCancel);
     616                 :     case kInsertBreak:
     617               0 :       return WillInsertBreak(aSelection, aCancel, aHandled);
     618                 :     case kDeleteSelection:
     619               0 :       return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
     620                 :     case kMakeList:
     621               0 :       return WillMakeList(aSelection, info->blockType, info->entireList, info->bulletType, aCancel, aHandled);
     622                 :     case kIndent:
     623               0 :       return WillIndent(aSelection, aCancel, aHandled);
     624                 :     case kOutdent:
     625               0 :       return WillOutdent(aSelection, aCancel, aHandled);
     626                 :     case kSetAbsolutePosition:
     627               0 :       return WillAbsolutePosition(aSelection, aCancel, aHandled);
     628                 :     case kRemoveAbsolutePosition:
     629               0 :       return WillRemoveAbsolutePosition(aSelection, aCancel, aHandled);
     630                 :     case kAlign:
     631               0 :       return WillAlign(aSelection, info->alignType, aCancel, aHandled);
     632                 :     case kMakeBasicBlock:
     633               0 :       return WillMakeBasicBlock(aSelection, info->blockType, aCancel, aHandled);
     634                 :     case kRemoveList:
     635               0 :       return WillRemoveList(aSelection, info->bOrdered, aCancel, aHandled);
     636                 :     case kMakeDefListItem:
     637               0 :       return WillMakeDefListItem(aSelection, info->blockType, info->entireList, aCancel, aHandled);
     638                 :     case kInsertElement:
     639               0 :       return WillInsert(aSelection, aCancel);
     640                 :     case kDecreaseZIndex:
     641               0 :       return WillRelativeChangeZIndex(aSelection, -1, aCancel, aHandled);
     642                 :     case kIncreaseZIndex:
     643               0 :       return WillRelativeChangeZIndex(aSelection, 1, aCancel, aHandled);
     644                 :   }
     645               0 :   return nsTextEditRules::WillDoAction(aSelection, aInfo, aCancel, aHandled);
     646                 : }
     647                 :   
     648                 :   
     649                 : NS_IMETHODIMP 
     650               0 : nsHTMLEditRules::DidDoAction(nsISelection *aSelection,
     651                 :                              nsRulesInfo *aInfo, nsresult aResult)
     652                 : {
     653               0 :   nsTextRulesInfo *info = static_cast<nsTextRulesInfo*>(aInfo);
     654               0 :   switch (info->action)
     655                 :   {
     656                 :     case kInsertBreak:
     657               0 :       return DidInsertBreak(aSelection, aResult);
     658                 :     case kDeleteSelection:
     659               0 :       return DidDeleteSelection(aSelection, info->collapsedAction, aResult);
     660                 :     case kMakeBasicBlock:
     661                 :     case kIndent:
     662                 :     case kOutdent:
     663                 :     case kAlign:
     664               0 :       return DidMakeBasicBlock(aSelection, aInfo, aResult);
     665                 :     case kSetAbsolutePosition: {
     666               0 :       nsresult rv = DidMakeBasicBlock(aSelection, aInfo, aResult);
     667               0 :       NS_ENSURE_SUCCESS(rv, rv);
     668               0 :       return DidAbsolutePosition();
     669                 :       }
     670                 :   }
     671                 :   
     672                 :   // default: pass thru to nsTextEditRules
     673               0 :   return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
     674                 : }
     675                 :   
     676                 : nsresult
     677               0 : nsHTMLEditRules::GetListState(bool *aMixed, bool *aOL, bool *aUL, bool *aDL)
     678                 : {
     679               0 :   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
     680               0 :   *aMixed = false;
     681               0 :   *aOL = false;
     682               0 :   *aUL = false;
     683               0 :   *aDL = false;
     684               0 :   bool bNonList = false;
     685                 :   
     686               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
     687               0 :   nsresult res = GetListActionNodes(arrayOfNodes, false, true);
     688               0 :   NS_ENSURE_SUCCESS(res, res);
     689                 : 
     690                 :   // examine list type for nodes in selection
     691               0 :   PRInt32 listCount = arrayOfNodes.Count();
     692                 :   PRInt32 i;
     693               0 :   for (i=listCount-1; i>=0; i--)
     694                 :   {
     695               0 :     nsIDOMNode* curNode = arrayOfNodes[i];
     696                 :     
     697               0 :     if (nsHTMLEditUtils::IsUnorderedList(curNode))
     698               0 :       *aUL = true;
     699               0 :     else if (nsHTMLEditUtils::IsOrderedList(curNode))
     700               0 :       *aOL = true;
     701               0 :     else if (nsEditor::NodeIsType(curNode, nsEditProperty::li))
     702                 :     {
     703               0 :       nsCOMPtr<nsIDOMNode> parent;
     704                 :       PRInt32 offset;
     705               0 :       res = nsEditor::GetNodeLocation(curNode, address_of(parent), &offset);
     706               0 :       NS_ENSURE_SUCCESS(res, res);
     707               0 :       if (nsHTMLEditUtils::IsUnorderedList(parent))
     708               0 :         *aUL = true;
     709               0 :       else if (nsHTMLEditUtils::IsOrderedList(parent))
     710               0 :         *aOL = true;
     711                 :     }
     712               0 :     else if (nsEditor::NodeIsType(curNode, nsEditProperty::dl) ||
     713               0 :              nsEditor::NodeIsType(curNode, nsEditProperty::dt) ||
     714               0 :              nsEditor::NodeIsType(curNode, nsEditProperty::dd) )
     715                 :     {
     716               0 :       *aDL = true;
     717                 :     }
     718               0 :     else bNonList = true;
     719                 :   }  
     720                 :   
     721                 :   // hokey arithmetic with booleans
     722               0 :   if ( (*aUL + *aOL + *aDL + bNonList) > 1) *aMixed = true;
     723                 :   
     724               0 :   return res;
     725                 : }
     726                 : 
     727                 : nsresult 
     728               0 : nsHTMLEditRules::GetListItemState(bool *aMixed, bool *aLI, bool *aDT, bool *aDD)
     729                 : {
     730               0 :   NS_ENSURE_TRUE(aMixed && aLI && aDT && aDD, NS_ERROR_NULL_POINTER);
     731               0 :   *aMixed = false;
     732               0 :   *aLI = false;
     733               0 :   *aDT = false;
     734               0 :   *aDD = false;
     735               0 :   bool bNonList = false;
     736                 :   
     737               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
     738               0 :   nsresult res = GetListActionNodes(arrayOfNodes, false, true);
     739               0 :   NS_ENSURE_SUCCESS(res, res);
     740                 : 
     741                 :   // examine list type for nodes in selection
     742               0 :   PRInt32 listCount = arrayOfNodes.Count();
     743                 :   PRInt32 i;
     744               0 :   for (i = listCount-1; i>=0; i--)
     745                 :   {
     746               0 :     nsIDOMNode* curNode = arrayOfNodes[i];
     747                 :     
     748               0 :     if (nsHTMLEditUtils::IsUnorderedList(curNode) ||
     749               0 :         nsHTMLEditUtils::IsOrderedList(curNode) ||
     750               0 :         nsEditor::NodeIsType(curNode, nsEditProperty::li) )
     751                 :     {
     752               0 :       *aLI = true;
     753                 :     }
     754               0 :     else if (nsEditor::NodeIsType(curNode, nsEditProperty::dt))
     755                 :     {
     756               0 :       *aDT = true;
     757                 :     }
     758               0 :     else if (nsEditor::NodeIsType(curNode, nsEditProperty::dd))
     759                 :     {
     760               0 :       *aDD = true;
     761                 :     }
     762               0 :     else if (nsEditor::NodeIsType(curNode, nsEditProperty::dl))
     763                 :     {
     764                 :       // need to look inside dl and see which types of items it has
     765                 :       bool bDT, bDD;
     766               0 :       res = GetDefinitionListItemTypes(curNode, bDT, bDD);
     767               0 :       NS_ENSURE_SUCCESS(res, res);
     768               0 :       *aDT |= bDT;
     769               0 :       *aDD |= bDD;
     770                 :     }
     771               0 :     else bNonList = true;
     772                 :   }  
     773                 :   
     774                 :   // hokey arithmetic with booleans
     775               0 :   if ( (*aDT + *aDD + bNonList) > 1) *aMixed = true;
     776                 :   
     777               0 :   return res;
     778                 : }
     779                 : 
     780                 : nsresult 
     781               0 : nsHTMLEditRules::GetAlignment(bool *aMixed, nsIHTMLEditor::EAlignment *aAlign)
     782                 : {
     783                 :   // for now, just return first alignment.  we'll lie about
     784                 :   // if it's mixed.  This is for efficiency
     785                 :   // given that our current ui doesn't care if it's mixed.
     786                 :   // cmanske: NOT TRUE! We would like to pay attention to mixed state
     787                 :   //  in Format | Align submenu!
     788                 : 
     789                 :   // this routine assumes that alignment is done ONLY via divs
     790                 : 
     791                 :   // default alignment is left
     792               0 :   NS_ENSURE_TRUE(aMixed && aAlign, NS_ERROR_NULL_POINTER);
     793               0 :   *aMixed = false;
     794               0 :   *aAlign = nsIHTMLEditor::eLeft;
     795                 : 
     796                 :   // get selection
     797               0 :   nsCOMPtr<nsISelection>selection;
     798               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     799               0 :   NS_ENSURE_SUCCESS(res, res);
     800                 : 
     801                 :   // get selection location
     802               0 :   nsCOMPtr<nsIDOMNode> parent;
     803               0 :   nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
     804               0 :   NS_ENSURE_TRUE(rootElem, NS_ERROR_FAILURE);
     805                 : 
     806                 :   PRInt32 offset, rootOffset;
     807               0 :   res = nsEditor::GetNodeLocation(rootElem, address_of(parent), &rootOffset);
     808               0 :   NS_ENSURE_SUCCESS(res, res);
     809               0 :   res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(parent), &offset);
     810               0 :   NS_ENSURE_SUCCESS(res, res);
     811                 : 
     812                 :   // is the selection collapsed?
     813                 :   bool bCollapsed;
     814               0 :   res = selection->GetIsCollapsed(&bCollapsed);
     815               0 :   NS_ENSURE_SUCCESS(res, res);
     816               0 :   nsCOMPtr<nsIDOMNode> nodeToExamine;
     817               0 :   nsCOMPtr<nsISupports> isupports;
     818               0 :   if (bCollapsed)
     819                 :   {
     820                 :     // if it is, we want to look at 'parent' and its ancestors
     821                 :     // for divs with alignment on them
     822               0 :     nodeToExamine = parent;
     823                 :   }
     824               0 :   else if (mHTMLEditor->IsTextNode(parent)) 
     825                 :   {
     826                 :     // if we are in a text node, then that is the node of interest
     827               0 :     nodeToExamine = parent;
     828                 :   }
     829               0 :   else if (nsEditor::NodeIsType(parent, nsEditProperty::html) &&
     830                 :            offset == rootOffset)
     831                 :   {
     832                 :     // if we have selected the body, let's look at the first editable node
     833               0 :     mHTMLEditor->GetNextNode(parent, offset, true, address_of(nodeToExamine));
     834                 :   }
     835                 :   else
     836                 :   {
     837               0 :     nsCOMArray<nsIDOMRange> arrayOfRanges;
     838               0 :     res = GetPromotedRanges(selection, arrayOfRanges, kAlign);
     839               0 :     NS_ENSURE_SUCCESS(res, res);
     840                 : 
     841                 :     // use these ranges to construct a list of nodes to act on.
     842               0 :     nsCOMArray<nsIDOMNode> arrayOfNodes;
     843               0 :     res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, kAlign, true);
     844               0 :     NS_ENSURE_SUCCESS(res, res);                                 
     845               0 :     nodeToExamine = arrayOfNodes.SafeObjectAt(0);
     846                 :   }
     847                 : 
     848               0 :   NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER);
     849                 : 
     850               0 :   NS_NAMED_LITERAL_STRING(typeAttrName, "align");
     851               0 :   nsIAtom  *dummyProperty = nsnull;
     852               0 :   nsCOMPtr<nsIDOMNode> blockParent;
     853               0 :   if (mHTMLEditor->IsBlockNode(nodeToExamine))
     854               0 :     blockParent = nodeToExamine;
     855                 :   else
     856               0 :     blockParent = mHTMLEditor->GetBlockNodeParent(nodeToExamine);
     857                 : 
     858               0 :   NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
     859                 : 
     860               0 :   if (mHTMLEditor->IsCSSEnabled())
     861                 :   {
     862               0 :     nsCOMPtr<nsIContent> blockParentContent = do_QueryInterface(blockParent);
     863               0 :     if (blockParentContent && 
     864               0 :         mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParentContent, dummyProperty, &typeAttrName))
     865                 :     {
     866                 :       // we are in CSS mode and we know how to align this element with CSS
     867               0 :       nsAutoString value;
     868                 :       // let's get the value(s) of text-align or margin-left/margin-right
     869                 :       mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet(
     870                 :         blockParentContent, dummyProperty, &typeAttrName, value,
     871               0 :         COMPUTED_STYLE_TYPE);
     872               0 :       if (value.EqualsLiteral("center") ||
     873               0 :           value.EqualsLiteral("-moz-center") ||
     874               0 :           value.EqualsLiteral("auto auto"))
     875                 :       {
     876               0 :         *aAlign = nsIHTMLEditor::eCenter;
     877               0 :         return NS_OK;
     878                 :       }
     879               0 :       if (value.EqualsLiteral("right") ||
     880               0 :           value.EqualsLiteral("-moz-right") ||
     881               0 :           value.EqualsLiteral("auto 0px"))
     882                 :       {
     883               0 :         *aAlign = nsIHTMLEditor::eRight;
     884               0 :         return NS_OK;
     885                 :       }
     886               0 :       if (value.EqualsLiteral("justify"))
     887                 :       {
     888               0 :         *aAlign = nsIHTMLEditor::eJustify;
     889               0 :         return NS_OK;
     890                 :       }
     891               0 :       *aAlign = nsIHTMLEditor::eLeft;
     892               0 :       return NS_OK;
     893                 :     }
     894                 :   }
     895                 : 
     896                 :   // check up the ladder for divs with alignment
     897               0 :   nsCOMPtr<nsIDOMNode> temp = nodeToExamine;
     898               0 :   bool isFirstNodeToExamine = true;
     899               0 :   while (nodeToExamine)
     900                 :   {
     901               0 :     if (!isFirstNodeToExamine && nsHTMLEditUtils::IsTable(nodeToExamine))
     902                 :     {
     903                 :       // the node to examine is a table and this is not the first node
     904                 :       // we examine; let's break here to materialize the 'inline-block'
     905                 :       // behaviour of html tables regarding to text alignment
     906               0 :       return NS_OK;
     907                 :     }
     908               0 :     if (nsHTMLEditUtils::SupportsAlignAttr(nodeToExamine))
     909                 :     {
     910                 :       // check for alignment
     911               0 :       nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(nodeToExamine);
     912               0 :       if (elem)
     913                 :       {
     914               0 :         nsAutoString typeAttrVal;
     915               0 :         res = elem->GetAttribute(NS_LITERAL_STRING("align"), typeAttrVal);
     916               0 :         ToLowerCase(typeAttrVal);
     917               0 :         if (NS_SUCCEEDED(res) && typeAttrVal.Length())
     918                 :         {
     919               0 :           if (typeAttrVal.EqualsLiteral("center"))
     920               0 :             *aAlign = nsIHTMLEditor::eCenter;
     921               0 :           else if (typeAttrVal.EqualsLiteral("right"))
     922               0 :             *aAlign = nsIHTMLEditor::eRight;
     923               0 :           else if (typeAttrVal.EqualsLiteral("justify"))
     924               0 :             *aAlign = nsIHTMLEditor::eJustify;
     925                 :           else
     926               0 :             *aAlign = nsIHTMLEditor::eLeft;
     927               0 :           return res;
     928                 :         }
     929                 :       }
     930                 :     }
     931               0 :     isFirstNodeToExamine = false;
     932               0 :     res = nodeToExamine->GetParentNode(getter_AddRefs(temp));
     933               0 :     if (NS_FAILED(res)) temp = nsnull;
     934               0 :     nodeToExamine = temp; 
     935                 :   }
     936               0 :   return NS_OK;
     937                 : }
     938                 : 
     939               0 : nsIAtom* MarginPropertyAtomForIndent(nsHTMLCSSUtils* aHTMLCSSUtils, nsIDOMNode* aNode) {
     940               0 :   nsAutoString direction;
     941               0 :   aHTMLCSSUtils->GetComputedProperty(aNode, nsEditProperty::cssDirection, direction);
     942               0 :   return direction.EqualsLiteral("rtl") ?
     943               0 :     nsEditProperty::cssMarginRight : nsEditProperty::cssMarginLeft;
     944                 : }
     945                 : 
     946                 : nsresult 
     947               0 : nsHTMLEditRules::GetIndentState(bool *aCanIndent, bool *aCanOutdent)
     948                 : {
     949               0 :   NS_ENSURE_TRUE(aCanIndent && aCanOutdent, NS_ERROR_FAILURE);
     950               0 :   *aCanIndent = true;    
     951               0 :   *aCanOutdent = false;
     952                 : 
     953                 :   // get selection
     954               0 :   nsCOMPtr<nsISelection>selection;
     955               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     956               0 :   NS_ENSURE_SUCCESS(res, res);
     957               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     958               0 :   NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE);
     959                 : 
     960                 :   // contruct a list of nodes to act on.
     961               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
     962               0 :   res = GetNodesFromSelection(selection, kIndent, arrayOfNodes, true);
     963               0 :   NS_ENSURE_SUCCESS(res, res);
     964                 : 
     965                 :   // examine nodes in selection for blockquotes or list elements;
     966                 :   // these we can outdent.  Note that we return true for canOutdent
     967                 :   // if *any* of the selection is outdentable, rather than all of it.
     968               0 :   PRInt32 listCount = arrayOfNodes.Count();
     969                 :   PRInt32 i;
     970               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
     971               0 :   for (i=listCount-1; i>=0; i--)
     972                 :   {
     973               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
     974                 :     
     975               0 :     if (nsHTMLEditUtils::IsNodeThatCanOutdent(curNode))
     976                 :     {
     977               0 :       *aCanOutdent = true;
     978                 :       break;
     979                 :     }
     980               0 :     else if (useCSS) {
     981                 :       // we are in CSS mode, indentation is done using the margin-left (or margin-right) property
     982               0 :       nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
     983               0 :       nsAutoString value;
     984                 :       // retrieve its specified value
     985               0 :       mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, marginProperty, value);
     986                 :       float f;
     987               0 :       nsCOMPtr<nsIAtom> unit;
     988                 :       // get its number part and its unit
     989               0 :       mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
     990                 :       // if the number part is strictly positive, outdent is possible
     991               0 :       if (0 < f) {
     992               0 :         *aCanOutdent = true;
     993                 :         break;
     994                 :       }
     995                 :     }
     996                 :   }  
     997                 :   
     998               0 :   if (!*aCanOutdent)
     999                 :   {
    1000                 :     // if we haven't found something to outdent yet, also check the parents
    1001                 :     // of selection endpoints.  We might have a blockquote or list item 
    1002                 :     // in the parent hierarchy.
    1003                 :     
    1004                 :     // gather up info we need for test
    1005               0 :     nsCOMPtr<nsIDOMNode> parent, tmp, root = do_QueryInterface(mHTMLEditor->GetRoot());
    1006               0 :     NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
    1007               0 :     nsCOMPtr<nsISelection> selection;
    1008                 :     PRInt32 selOffset;
    1009               0 :     res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    1010               0 :     NS_ENSURE_SUCCESS(res, res);
    1011               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1012                 :     
    1013                 :     // test start parent hierarchy
    1014               0 :     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(parent), &selOffset);
    1015               0 :     NS_ENSURE_SUCCESS(res, res);
    1016               0 :     while (parent && (parent!=root))
    1017                 :     {
    1018               0 :       if (nsHTMLEditUtils::IsNodeThatCanOutdent(parent))
    1019                 :       {
    1020               0 :         *aCanOutdent = true;
    1021               0 :         break;
    1022                 :       }
    1023               0 :       tmp=parent;
    1024               0 :       tmp->GetParentNode(getter_AddRefs(parent));
    1025                 :     }
    1026                 : 
    1027                 :     // test end parent hierarchy
    1028               0 :     res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(parent), &selOffset);
    1029               0 :     NS_ENSURE_SUCCESS(res, res);
    1030               0 :     while (parent && (parent!=root))
    1031                 :     {
    1032               0 :       if (nsHTMLEditUtils::IsNodeThatCanOutdent(parent))
    1033                 :       {
    1034               0 :         *aCanOutdent = true;
    1035               0 :         break;
    1036                 :       }
    1037               0 :       tmp=parent;
    1038               0 :       tmp->GetParentNode(getter_AddRefs(parent));
    1039                 :     }
    1040                 :   }
    1041               0 :   return res;
    1042                 : }
    1043                 : 
    1044                 : 
    1045                 : nsresult 
    1046               0 : nsHTMLEditRules::GetParagraphState(bool *aMixed, nsAString &outFormat)
    1047                 : {
    1048                 :   // This routine is *heavily* tied to our ui choices in the paragraph
    1049                 :   // style popup.  I can't see a way around that.
    1050               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
    1051               0 :   *aMixed = true;
    1052               0 :   outFormat.Truncate(0);
    1053                 :   
    1054               0 :   bool bMixed = false;
    1055                 :   // using "x" as an uninitialized value, since "" is meaningful
    1056               0 :   nsAutoString formatStr(NS_LITERAL_STRING("x")); 
    1057                 :   
    1058               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    1059               0 :   nsresult res = GetParagraphFormatNodes(arrayOfNodes, true);
    1060               0 :   NS_ENSURE_SUCCESS(res, res);
    1061                 : 
    1062                 :   // post process list.  We need to replace any block nodes that are not format
    1063                 :   // nodes with their content.  This is so we only have to look "up" the hierarchy
    1064                 :   // to find format nodes, instead of both up and down.
    1065               0 :   PRInt32 listCount = arrayOfNodes.Count();
    1066                 :   PRInt32 i;
    1067               0 :   for (i=listCount-1; i>=0; i--)
    1068                 :   {
    1069               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    1070               0 :     nsAutoString format;
    1071                 :     // if it is a known format node we have it easy
    1072               0 :     if (IsBlockNode(curNode) && !nsHTMLEditUtils::IsFormatNode(curNode))
    1073                 :     {
    1074                 :       // arrayOfNodes.RemoveObject(curNode);
    1075               0 :       res = AppendInnerFormatNodes(arrayOfNodes, curNode);
    1076               0 :       NS_ENSURE_SUCCESS(res, res);
    1077                 :     }
    1078                 :   }
    1079                 :   
    1080                 :   // we might have an empty node list.  if so, find selection parent
    1081                 :   // and put that on the list
    1082               0 :   listCount = arrayOfNodes.Count();
    1083               0 :   if (!listCount)
    1084                 :   {
    1085               0 :     nsCOMPtr<nsIDOMNode> selNode;
    1086                 :     PRInt32 selOffset;
    1087               0 :     nsCOMPtr<nsISelection>selection;
    1088               0 :     res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    1089               0 :     NS_ENSURE_SUCCESS(res, res);
    1090               0 :     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
    1091               0 :     NS_ENSURE_SUCCESS(res, res);
    1092               0 :     NS_ENSURE_TRUE(selNode, NS_ERROR_NULL_POINTER);
    1093               0 :     arrayOfNodes.AppendObject(selNode);
    1094               0 :     listCount = 1;
    1095                 :   }
    1096                 : 
    1097                 :   // remember root node
    1098               0 :   nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
    1099               0 :   NS_ENSURE_TRUE(rootElem, NS_ERROR_NULL_POINTER);
    1100                 : 
    1101                 :   // loop through the nodes in selection and examine their paragraph format
    1102               0 :   for (i=listCount-1; i>=0; i--)
    1103                 :   {
    1104               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    1105               0 :     nsAutoString format;
    1106                 :     // if it is a known format node we have it easy
    1107               0 :     if (nsHTMLEditUtils::IsFormatNode(curNode))
    1108               0 :       GetFormatString(curNode, format);
    1109               0 :     else if (IsBlockNode(curNode))
    1110                 :     {
    1111                 :       // this is a div or some other non-format block.
    1112                 :       // we should ignore it.  Its children were appended to this list
    1113                 :       // by AppendInnerFormatNodes() call above.  We will get needed
    1114                 :       // info when we examine them instead.
    1115               0 :       continue;
    1116                 :     }
    1117                 :     else
    1118                 :     {
    1119               0 :       nsCOMPtr<nsIDOMNode> node, tmp = curNode;
    1120               0 :       tmp->GetParentNode(getter_AddRefs(node));
    1121               0 :       while (node)
    1122                 :       {
    1123               0 :         if (node == rootElem)
    1124                 :         {
    1125               0 :           format.Truncate(0);
    1126               0 :           break;
    1127                 :         }
    1128               0 :         else if (nsHTMLEditUtils::IsFormatNode(node))
    1129                 :         {
    1130               0 :           GetFormatString(node, format);
    1131               0 :           break;
    1132                 :         }
    1133                 :         // else keep looking up
    1134               0 :         tmp = node;
    1135               0 :         tmp->GetParentNode(getter_AddRefs(node));
    1136                 :       }
    1137                 :     }
    1138                 :     
    1139                 :     // if this is the first node, we've found, remember it as the format
    1140               0 :     if (formatStr.EqualsLiteral("x"))
    1141               0 :       formatStr = format;
    1142                 :     // else make sure it matches previously found format
    1143               0 :     else if (format != formatStr) 
    1144                 :     {
    1145               0 :       bMixed = true;
    1146                 :       break; 
    1147                 :     }
    1148                 :   }  
    1149                 :   
    1150               0 :   *aMixed = bMixed;
    1151               0 :   outFormat = formatStr;
    1152               0 :   return res;
    1153                 : }
    1154                 : 
    1155                 : nsresult 
    1156               0 : nsHTMLEditRules::AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
    1157                 :                                         nsIDOMNode *aNode)
    1158                 : {
    1159               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1160                 : 
    1161               0 :   nsCOMPtr<nsIDOMNodeList> childList;
    1162               0 :   nsCOMPtr<nsIDOMNode> child;
    1163                 : 
    1164               0 :   aNode->GetChildNodes(getter_AddRefs(childList));
    1165               0 :   NS_ENSURE_TRUE(childList, NS_OK);
    1166               0 :   PRUint32 len, j=0;
    1167               0 :   childList->GetLength(&len);
    1168                 : 
    1169                 :   // we only need to place any one inline inside this node onto 
    1170                 :   // the list.  They are all the same for purposes of determining
    1171                 :   // paragraph style.  We use foundInline to track this as we are 
    1172                 :   // going through the children in the loop below.
    1173               0 :   bool foundInline = false;
    1174               0 :   while (j < len)
    1175                 :   {
    1176               0 :     childList->Item(j, getter_AddRefs(child));
    1177               0 :     bool isBlock = IsBlockNode(child);
    1178               0 :     bool isFormat = nsHTMLEditUtils::IsFormatNode(child);
    1179               0 :     if (isBlock && !isFormat)  // if it's a div, etc, recurse
    1180               0 :       AppendInnerFormatNodes(aArray, child);
    1181               0 :     else if (isFormat)
    1182                 :     {
    1183               0 :       aArray.AppendObject(child);
    1184                 :     }
    1185               0 :     else if (!foundInline)  // if this is the first inline we've found, use it
    1186                 :     {
    1187               0 :       foundInline = true;      
    1188               0 :       aArray.AppendObject(child);
    1189                 :     }
    1190               0 :     j++;
    1191                 :   }
    1192               0 :   return NS_OK;
    1193                 : }
    1194                 : 
    1195                 : nsresult 
    1196               0 : nsHTMLEditRules::GetFormatString(nsIDOMNode *aNode, nsAString &outFormat)
    1197                 : {
    1198               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1199                 : 
    1200               0 :   if (nsHTMLEditUtils::IsFormatNode(aNode))
    1201                 :   {
    1202               0 :     nsCOMPtr<nsIAtom> atom = nsEditor::GetTag(aNode);
    1203               0 :     atom->ToString(outFormat);
    1204                 :   }
    1205                 :   else
    1206               0 :     outFormat.Truncate();
    1207                 : 
    1208               0 :   return NS_OK;
    1209                 : }    
    1210                 : 
    1211                 : /********************************************************
    1212                 :  *  Protected rules methods 
    1213                 :  ********************************************************/
    1214                 : 
    1215                 : nsresult
    1216               0 : nsHTMLEditRules::WillInsert(nsISelection *aSelection, bool *aCancel)
    1217                 : {
    1218               0 :   nsresult res = nsTextEditRules::WillInsert(aSelection, aCancel);
    1219               0 :   NS_ENSURE_SUCCESS(res, res); 
    1220                 :   
    1221                 :   // Adjust selection to prevent insertion after a moz-BR.
    1222                 :   // this next only works for collapsed selections right now,
    1223                 :   // because selection is a pain to work with when not collapsed.
    1224                 :   // (no good way to extend start or end of selection), so we ignore
    1225                 :   // those types of selections.
    1226                 :   bool bCollapsed;
    1227               0 :   res = aSelection->GetIsCollapsed(&bCollapsed);
    1228               0 :   NS_ENSURE_SUCCESS(res, res);
    1229               0 :   if (!bCollapsed) {
    1230               0 :     return NS_OK;
    1231                 :   }
    1232                 : 
    1233                 :   // if we are after a mozBR in the same block, then move selection
    1234                 :   // to be before it
    1235               0 :   nsCOMPtr<nsIDOMNode> selNode, priorNode;
    1236                 :   PRInt32 selOffset;
    1237                 :   // get the (collapsed) selection location
    1238               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode),
    1239               0 :                                            &selOffset);
    1240               0 :   NS_ENSURE_SUCCESS(res, res);
    1241                 :   // get prior node
    1242                 :   res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset,
    1243               0 :                                       address_of(priorNode));
    1244               0 :   if (NS_SUCCEEDED(res) && priorNode && nsTextEditUtils::IsMozBR(priorNode))
    1245                 :   {
    1246               0 :     nsCOMPtr<nsIDOMNode> block1, block2;
    1247               0 :     if (IsBlockNode(selNode)) block1 = selNode;
    1248               0 :     else block1 = mHTMLEditor->GetBlockNodeParent(selNode);
    1249               0 :     block2 = mHTMLEditor->GetBlockNodeParent(priorNode);
    1250                 :   
    1251               0 :     if (block1 == block2)
    1252                 :     {
    1253                 :       // if we are here then the selection is right after a mozBR
    1254                 :       // that is in the same block as the selection.  We need to move
    1255                 :       // the selection start to be before the mozBR.
    1256               0 :       res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset);
    1257               0 :       NS_ENSURE_SUCCESS(res, res);
    1258               0 :       res = aSelection->Collapse(selNode,selOffset);
    1259               0 :       NS_ENSURE_SUCCESS(res, res);
    1260                 :     }
    1261                 :   }
    1262                 : 
    1263                 :   // we need to get the doc
    1264               0 :   nsCOMPtr<nsIDOMDocument>doc;
    1265               0 :   res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
    1266               0 :   NS_ENSURE_SUCCESS(res, res);
    1267               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
    1268                 :     
    1269                 :   // for every property that is set, insert a new inline style node
    1270               0 :   return CreateStyleForInsertText(aSelection, doc);
    1271                 : }    
    1272                 : 
    1273                 : #ifdef XXX_DEAD_CODE
    1274                 : nsresult
    1275                 : nsHTMLEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
    1276                 : {
    1277                 :   return nsTextEditRules::DidInsert(aSelection, aResult);
    1278                 : }
    1279                 : #endif
    1280                 : 
    1281                 : nsresult
    1282               0 : nsHTMLEditRules::WillInsertText(PRInt32          aAction,
    1283                 :                                 nsISelection *aSelection, 
    1284                 :                                 bool            *aCancel,
    1285                 :                                 bool            *aHandled,
    1286                 :                                 const nsAString *inString,
    1287                 :                                 nsAString       *outString,
    1288                 :                                 PRInt32          aMaxLength)
    1289                 : {  
    1290               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    1291                 : 
    1292                 : 
    1293                 : 
    1294               0 :   if (inString->IsEmpty() && (aAction != kInsertTextIME))
    1295                 :   {
    1296                 :     // HACK: this is a fix for bug 19395
    1297                 :     // I can't outlaw all empty insertions
    1298                 :     // because IME transaction depend on them
    1299                 :     // There is more work to do to make the 
    1300                 :     // world safe for IME.
    1301               0 :     *aCancel = true;
    1302               0 :     *aHandled = false;
    1303               0 :     return NS_OK;
    1304                 :   }
    1305                 :   
    1306                 :   // initialize out param
    1307               0 :   *aCancel = false;
    1308               0 :   *aHandled = true;
    1309                 :   nsresult res;
    1310               0 :   nsCOMPtr<nsIDOMNode> selNode;
    1311                 :   PRInt32 selOffset;
    1312                 : 
    1313                 :   // if the selection isn't collapsed, delete it.
    1314                 :   bool bCollapsed;
    1315               0 :   res = aSelection->GetIsCollapsed(&bCollapsed);
    1316               0 :   NS_ENSURE_SUCCESS(res, res);
    1317               0 :   if (!bCollapsed)
    1318                 :   {
    1319               0 :     res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
    1320               0 :     NS_ENSURE_SUCCESS(res, res);
    1321                 :   }
    1322                 : 
    1323               0 :   res = WillInsert(aSelection, aCancel);
    1324               0 :   NS_ENSURE_SUCCESS(res, res);
    1325                 :   // initialize out param
    1326                 :   // we want to ignore result of WillInsert()
    1327               0 :   *aCancel = false;
    1328                 :   
    1329                 :   // get the (collapsed) selection location
    1330               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    1331               0 :   NS_ENSURE_SUCCESS(res, res);
    1332                 : 
    1333                 :   // dont put text in places that can't have it
    1334               0 :   if (!mHTMLEditor->IsTextNode(selNode) &&
    1335               0 :       !mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("#text")))
    1336               0 :     return NS_ERROR_FAILURE;
    1337                 : 
    1338                 :   // we need to get the doc
    1339               0 :   nsCOMPtr<nsIDOMDocument>doc;
    1340               0 :   res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
    1341               0 :   NS_ENSURE_SUCCESS(res, res);
    1342               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
    1343                 :     
    1344               0 :   if (aAction == kInsertTextIME) 
    1345                 :   { 
    1346                 :     // Right now the nsWSRunObject code bails on empty strings, but IME needs 
    1347                 :     // the InsertTextImpl() call to still happen since empty strings are meaningful there.
    1348               0 :     if (inString->IsEmpty())
    1349                 :     {
    1350               0 :       res = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode), &selOffset, doc);
    1351                 :     }
    1352                 :     else
    1353                 :     {
    1354               0 :       nsWSRunObject wsObj(mHTMLEditor, selNode, selOffset);
    1355               0 :       res = wsObj.InsertText(*inString, address_of(selNode), &selOffset, doc);
    1356                 :     }
    1357               0 :     NS_ENSURE_SUCCESS(res, res);
    1358                 :   }
    1359                 :   else // aAction == kInsertText
    1360                 :   {
    1361                 :     // find where we are
    1362               0 :     nsCOMPtr<nsIDOMNode> curNode = selNode;
    1363               0 :     PRInt32 curOffset = selOffset;
    1364                 :     
    1365                 :     // is our text going to be PREformatted?  
    1366                 :     // We remember this so that we know how to handle tabs.
    1367                 :     bool isPRE;
    1368               0 :     res = mHTMLEditor->IsPreformatted(selNode, &isPRE);
    1369               0 :     NS_ENSURE_SUCCESS(res, res);    
    1370                 :     
    1371                 :     // turn off the edit listener: we know how to
    1372                 :     // build the "doc changed range" ourselves, and it's
    1373                 :     // must faster to do it once here than to track all
    1374                 :     // the changes one at a time.
    1375               0 :     nsAutoLockListener lockit(&mListenerEnabled); 
    1376                 :     
    1377                 :     // don't spaz my selection in subtransactions
    1378               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    1379               0 :     nsAutoString tString(*inString);
    1380               0 :     const PRUnichar *unicodeBuf = tString.get();
    1381               0 :     nsCOMPtr<nsIDOMNode> unused;
    1382               0 :     PRInt32 pos = 0;
    1383               0 :     NS_NAMED_LITERAL_STRING(newlineStr, LFSTR);
    1384                 :         
    1385                 :     // for efficiency, break out the pre case separately.  This is because
    1386                 :     // its a lot cheaper to search the input string for only newlines than
    1387                 :     // it is to search for both tabs and newlines.
    1388               0 :     if (isPRE || IsPlaintextEditor())
    1389                 :     {
    1390               0 :       while (unicodeBuf && (pos != -1) && (pos < (PRInt32)(*inString).Length()))
    1391                 :       {
    1392               0 :         PRInt32 oldPos = pos;
    1393                 :         PRInt32 subStrLen;
    1394               0 :         pos = tString.FindChar(nsCRT::LF, oldPos);
    1395                 : 
    1396               0 :         if (pos != -1) 
    1397                 :         {
    1398               0 :           subStrLen = pos - oldPos;
    1399                 :           // if first char is newline, then use just it
    1400               0 :           if (subStrLen == 0)
    1401               0 :             subStrLen = 1;
    1402                 :         }
    1403                 :         else
    1404                 :         {
    1405               0 :           subStrLen = tString.Length() - oldPos;
    1406               0 :           pos = tString.Length();
    1407                 :         }
    1408                 : 
    1409               0 :         nsDependentSubstring subStr(tString, oldPos, subStrLen);
    1410                 :         
    1411                 :         // is it a return?
    1412               0 :         if (subStr.Equals(newlineStr))
    1413                 :         {
    1414               0 :           res = mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
    1415               0 :           pos++;
    1416                 :         }
    1417                 :         else
    1418                 :         {
    1419               0 :           res = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
    1420                 :         }
    1421               0 :         NS_ENSURE_SUCCESS(res, res);
    1422                 :       }
    1423                 :     }
    1424                 :     else
    1425                 :     {
    1426               0 :       NS_NAMED_LITERAL_STRING(tabStr, "\t");
    1427               0 :       NS_NAMED_LITERAL_STRING(spacesStr, "    ");
    1428               0 :       char specialChars[] = {TAB, nsCRT::LF, 0};
    1429               0 :       while (unicodeBuf && (pos != -1) && (pos < (PRInt32)inString->Length()))
    1430                 :       {
    1431               0 :         PRInt32 oldPos = pos;
    1432                 :         PRInt32 subStrLen;
    1433               0 :         pos = tString.FindCharInSet(specialChars, oldPos);
    1434                 :         
    1435               0 :         if (pos != -1) 
    1436                 :         {
    1437               0 :           subStrLen = pos - oldPos;
    1438                 :           // if first char is newline, then use just it
    1439               0 :           if (subStrLen == 0)
    1440               0 :             subStrLen = 1;
    1441                 :         }
    1442                 :         else
    1443                 :         {
    1444               0 :           subStrLen = tString.Length() - oldPos;
    1445               0 :           pos = tString.Length();
    1446                 :         }
    1447                 : 
    1448               0 :         nsDependentSubstring subStr(tString, oldPos, subStrLen);
    1449               0 :         nsWSRunObject wsObj(mHTMLEditor, curNode, curOffset);
    1450                 : 
    1451                 :         // is it a tab?
    1452               0 :         if (subStr.Equals(tabStr))
    1453                 :         {
    1454               0 :           res = wsObj.InsertText(spacesStr, address_of(curNode), &curOffset, doc);
    1455               0 :           NS_ENSURE_SUCCESS(res, res);
    1456               0 :           pos++;
    1457                 :         }
    1458                 :         // is it a return?
    1459               0 :         else if (subStr.Equals(newlineStr))
    1460                 :         {
    1461               0 :           res = wsObj.InsertBreak(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
    1462               0 :           NS_ENSURE_SUCCESS(res, res);
    1463               0 :           pos++;
    1464                 :         }
    1465                 :         else
    1466                 :         {
    1467               0 :           res = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
    1468               0 :           NS_ENSURE_SUCCESS(res, res);
    1469                 :         }
    1470               0 :         NS_ENSURE_SUCCESS(res, res);
    1471                 :       }
    1472                 :     }
    1473               0 :     nsCOMPtr<nsISelection> selection(aSelection);
    1474               0 :     nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    1475               0 :     selPriv->SetInterlinePosition(false);
    1476               0 :     if (curNode) aSelection->Collapse(curNode, curOffset);
    1477                 :     // manually update the doc changed range so that AfterEdit will clean up
    1478                 :     // the correct portion of the document.
    1479               0 :     if (!mDocChangeRange)
    1480                 :     {
    1481               0 :       mDocChangeRange = new nsRange();
    1482                 :     }
    1483               0 :     res = mDocChangeRange->SetStart(selNode, selOffset);
    1484               0 :     NS_ENSURE_SUCCESS(res, res);
    1485               0 :     if (curNode)
    1486               0 :       res = mDocChangeRange->SetEnd(curNode, curOffset);
    1487                 :     else
    1488               0 :       res = mDocChangeRange->SetEnd(selNode, selOffset);
    1489               0 :     NS_ENSURE_SUCCESS(res, res);
    1490                 :   }
    1491               0 :   return res;
    1492                 : }
    1493                 : 
    1494                 : nsresult
    1495               0 : nsHTMLEditRules::WillLoadHTML(nsISelection *aSelection, bool *aCancel)
    1496                 : {
    1497               0 :   NS_ENSURE_TRUE(aSelection && aCancel, NS_ERROR_NULL_POINTER);
    1498                 : 
    1499               0 :   *aCancel = false;
    1500                 : 
    1501                 :   // Delete mBogusNode if it exists. If we really need one,
    1502                 :   // it will be added during post-processing in AfterEditInner().
    1503                 : 
    1504               0 :   if (mBogusNode)
    1505                 :   {
    1506               0 :     mEditor->DeleteNode(mBogusNode);
    1507               0 :     mBogusNode = nsnull;
    1508                 :   }
    1509                 : 
    1510               0 :   return NS_OK;
    1511                 : }
    1512                 : 
    1513                 : nsresult
    1514               0 : nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, bool *aCancel, bool *aHandled)
    1515                 : {
    1516               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    1517                 :   // initialize out param
    1518               0 :   *aCancel = false;
    1519               0 :   *aHandled = false;
    1520                 : 
    1521                 :   // if the selection isn't collapsed, delete it.
    1522                 :   bool bCollapsed;
    1523               0 :   nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
    1524               0 :   NS_ENSURE_SUCCESS(res, res);
    1525               0 :   if (!bCollapsed)
    1526                 :   {
    1527               0 :     res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
    1528               0 :     NS_ENSURE_SUCCESS(res, res);
    1529                 :   }
    1530                 :   
    1531               0 :   res = WillInsert(aSelection, aCancel);
    1532               0 :   NS_ENSURE_SUCCESS(res, res);
    1533                 :   
    1534                 :   // initialize out param
    1535                 :   // we want to ignore result of WillInsert()
    1536               0 :   *aCancel = false;
    1537                 : 
    1538                 :   // split any mailcites in the way.
    1539                 :   // should we abort this if we encounter table cell boundaries?
    1540               0 :   if (IsMailEditor())
    1541                 :   {
    1542               0 :     res = SplitMailCites(aSelection, IsPlaintextEditor(), aHandled);
    1543               0 :     NS_ENSURE_SUCCESS(res, res);
    1544               0 :     if (*aHandled) return NS_OK;
    1545                 :   }
    1546                 : 
    1547                 :   // smart splitting rules
    1548               0 :   nsCOMPtr<nsIDOMNode> node;
    1549                 :   PRInt32 offset;
    1550                 : 
    1551               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
    1552               0 :   NS_ENSURE_SUCCESS(res, res);
    1553               0 :   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    1554                 : 
    1555                 :   // do nothing if the node is read-only
    1556               0 :   if (!mHTMLEditor->IsModifiableNode(node))
    1557                 :   {
    1558               0 :     *aCancel = true;
    1559               0 :     return NS_OK;
    1560                 :   }
    1561                 : 
    1562                 :   // identify the block
    1563               0 :   nsCOMPtr<nsIDOMNode> blockParent;
    1564               0 :   if (IsBlockNode(node)) 
    1565               0 :     blockParent = node;
    1566                 :   else 
    1567               0 :     blockParent = mHTMLEditor->GetBlockNodeParent(node);
    1568               0 :   NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
    1569                 : 
    1570                 :   // if the active editing host is an inline element,
    1571                 :   // or if the active editing host is the block parent itself,
    1572                 :   // just append a br.
    1573               0 :   nsCOMPtr<nsIContent> hostContent = mHTMLEditor->GetActiveEditingHost();
    1574               0 :   nsCOMPtr<nsIDOMNode> hostNode = do_QueryInterface(hostContent);
    1575               0 :   if (!nsEditorUtils::IsDescendantOf(blockParent, hostNode)) 
    1576                 :   {
    1577               0 :     res = StandardBreakImpl(node, offset, aSelection);
    1578               0 :     NS_ENSURE_SUCCESS(res, res);
    1579               0 :     *aHandled = true;
    1580               0 :     return NS_OK;
    1581                 :   }
    1582                 : 
    1583                 :   // if block is empty, populate with br.
    1584                 :   // (for example, imagine a div that contains the word "text".  the user selects
    1585                 :   // "text" and types return.  "text" is deleted leaving an empty block.  we want
    1586                 :   // to put in one br to make block have a line.  then code further below will put 
    1587                 :   // in a second br.)
    1588                 :   bool isEmpty;
    1589               0 :   res = IsEmptyBlock(blockParent, &isEmpty);
    1590               0 :   if (isEmpty)
    1591                 :   {
    1592                 :     PRUint32 blockLen;
    1593               0 :     res = mHTMLEditor->GetLengthOfDOMNode(blockParent, blockLen);
    1594               0 :     NS_ENSURE_SUCCESS(res, res);
    1595               0 :     nsCOMPtr<nsIDOMNode> brNode;
    1596               0 :     res = mHTMLEditor->CreateBR(blockParent, blockLen, address_of(brNode));
    1597               0 :     NS_ENSURE_SUCCESS(res, res);
    1598                 :   }
    1599                 :   
    1600               0 :   nsCOMPtr<nsIDOMNode> listItem = IsInListItem(blockParent);
    1601               0 :   if (listItem && listItem != hostNode)
    1602                 :   {
    1603               0 :     res = ReturnInListItem(aSelection, listItem, node, offset);
    1604               0 :     *aHandled = true;
    1605               0 :     return NS_OK;
    1606                 :   }
    1607                 :   
    1608                 :   // headers: close (or split) header
    1609               0 :   else if (nsHTMLEditUtils::IsHeader(blockParent))
    1610                 :   {
    1611               0 :     res = ReturnInHeader(aSelection, blockParent, node, offset);
    1612               0 :     *aHandled = true;
    1613               0 :     return NS_OK;
    1614                 :   }
    1615                 :   
    1616                 :   // paragraphs: special rules to look for <br>s
    1617               0 :   else if (nsHTMLEditUtils::IsParagraph(blockParent))
    1618                 :   {
    1619               0 :     res = ReturnInParagraph(aSelection, blockParent, node, offset, aCancel, aHandled);
    1620               0 :     NS_ENSURE_SUCCESS(res, res);
    1621                 :     // fall through, we may not have handled it in ReturnInParagraph()
    1622                 :   }
    1623                 :   
    1624                 :   // if not already handled then do the standard thing
    1625               0 :   if (!(*aHandled))
    1626                 :   {
    1627               0 :     res = StandardBreakImpl(node, offset, aSelection);
    1628               0 :     *aHandled = true;
    1629                 :   }
    1630               0 :   return res;
    1631                 : }
    1632                 : 
    1633                 : nsresult
    1634               0 : nsHTMLEditRules::StandardBreakImpl(nsIDOMNode *aNode, PRInt32 aOffset, nsISelection *aSelection)
    1635                 : {
    1636               0 :   nsCOMPtr<nsIDOMNode> brNode;
    1637               0 :   bool bAfterBlock = false;
    1638               0 :   bool bBeforeBlock = false;
    1639               0 :   nsresult res = NS_OK;
    1640               0 :   nsCOMPtr<nsIDOMNode> node(aNode);
    1641               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
    1642                 :   
    1643               0 :   if (IsPlaintextEditor())
    1644                 :   {
    1645               0 :     res = mHTMLEditor->CreateBR(node, aOffset, address_of(brNode));
    1646                 :   }
    1647                 :   else
    1648                 :   {
    1649               0 :     nsWSRunObject wsObj(mHTMLEditor, node, aOffset);
    1650               0 :     nsCOMPtr<nsIDOMNode> visNode, linkNode;
    1651               0 :     PRInt32 visOffset=0, newOffset;
    1652                 :     PRInt16 wsType;
    1653               0 :     res = wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType);
    1654               0 :     NS_ENSURE_SUCCESS(res, res);
    1655               0 :     if (wsType & nsWSRunObject::eBlock)
    1656               0 :       bAfterBlock = true;
    1657               0 :     res = wsObj.NextVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType);
    1658               0 :     NS_ENSURE_SUCCESS(res, res);
    1659               0 :     if (wsType & nsWSRunObject::eBlock)
    1660               0 :       bBeforeBlock = true;
    1661               0 :     if (mHTMLEditor->IsInLink(node, address_of(linkNode)))
    1662                 :     {
    1663                 :       // split the link
    1664               0 :       nsCOMPtr<nsIDOMNode> linkParent;
    1665               0 :       res = linkNode->GetParentNode(getter_AddRefs(linkParent));
    1666               0 :       NS_ENSURE_SUCCESS(res, res);
    1667               0 :       res = mHTMLEditor->SplitNodeDeep(linkNode, node, aOffset, &newOffset, true);
    1668               0 :       NS_ENSURE_SUCCESS(res, res);
    1669                 :       // reset {node,aOffset} to the point where link was split
    1670               0 :       node = linkParent;
    1671               0 :       aOffset = newOffset;
    1672                 :     }
    1673               0 :     res = wsObj.InsertBreak(address_of(node), &aOffset, address_of(brNode), nsIEditor::eNone);
    1674                 :   }
    1675               0 :   NS_ENSURE_SUCCESS(res, res);
    1676               0 :   res = nsEditor::GetNodeLocation(brNode, address_of(node), &aOffset);
    1677               0 :   NS_ENSURE_SUCCESS(res, res);
    1678               0 :   if (bAfterBlock && bBeforeBlock)
    1679                 :   {
    1680                 :     // we just placed a br between block boundaries.  
    1681                 :     // This is the one case where we want the selection to be before 
    1682                 :     // the br we just placed, as the br will be on a new line,
    1683                 :     // rather than at end of prior line.
    1684               0 :     selPriv->SetInterlinePosition(true);
    1685               0 :     res = aSelection->Collapse(node, aOffset);
    1686                 :   }
    1687                 :   else
    1688                 :   {
    1689               0 :      nsWSRunObject wsObj(mHTMLEditor, node, aOffset+1);
    1690               0 :      nsCOMPtr<nsIDOMNode> secondBR;
    1691               0 :      PRInt32 visOffset=0;
    1692                 :      PRInt16 wsType;
    1693               0 :      res = wsObj.NextVisibleNode(node, aOffset+1, address_of(secondBR), &visOffset, &wsType);
    1694               0 :      NS_ENSURE_SUCCESS(res, res);
    1695               0 :      if (wsType==nsWSRunObject::eBreak)
    1696                 :      {
    1697                 :        // the next thing after the break we inserted is another break.  Move the 2nd 
    1698                 :        // break to be the first breaks sibling.  This will prevent them from being
    1699                 :        // in different inline nodes, which would break SetInterlinePosition().  It will
    1700                 :        // also assure that if the user clicks away and then clicks back on their new
    1701                 :        // blank line, they will still get the style from the line above.  
    1702               0 :        nsCOMPtr<nsIDOMNode> brParent;
    1703                 :        PRInt32 brOffset;
    1704               0 :        res = nsEditor::GetNodeLocation(secondBR, address_of(brParent), &brOffset);
    1705               0 :        NS_ENSURE_SUCCESS(res, res);
    1706               0 :        if ((brParent != node) || (brOffset != (aOffset+1)))
    1707                 :        {
    1708               0 :          res = mHTMLEditor->MoveNode(secondBR, node, aOffset+1);
    1709               0 :          NS_ENSURE_SUCCESS(res, res);
    1710                 :        }
    1711                 :      }
    1712                 :     // SetInterlinePosition(true) means we want the caret to stick to the content on the "right".
    1713                 :     // We want the caret to stick to whatever is past the break.  This is
    1714                 :     // because the break is on the same line we were on, but the next content
    1715                 :     // will be on the following line.
    1716                 :     
    1717                 :     // An exception to this is if the break has a next sibling that is a block node.
    1718                 :     // Then we stick to the left to avoid an uber caret.
    1719               0 :     nsCOMPtr<nsIDOMNode> siblingNode;
    1720               0 :     brNode->GetNextSibling(getter_AddRefs(siblingNode));
    1721               0 :     if (siblingNode && IsBlockNode(siblingNode))
    1722               0 :       selPriv->SetInterlinePosition(false);
    1723                 :     else 
    1724               0 :       selPriv->SetInterlinePosition(true);
    1725               0 :     res = aSelection->Collapse(node, aOffset+1);
    1726                 :   }
    1727               0 :   return res;
    1728                 : }
    1729                 : 
    1730                 : nsresult
    1731               0 : nsHTMLEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
    1732                 : {
    1733               0 :   return NS_OK;
    1734                 : }
    1735                 : 
    1736                 : 
    1737                 : nsresult
    1738               0 : nsHTMLEditRules::SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool *aHandled)
    1739                 : {
    1740               0 :   NS_ENSURE_TRUE(aSelection && aHandled, NS_ERROR_NULL_POINTER);
    1741               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
    1742               0 :   nsCOMPtr<nsIDOMNode> citeNode, selNode, leftCite, rightCite;
    1743                 :   PRInt32 selOffset, newOffset;
    1744               0 :   nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    1745               0 :   NS_ENSURE_SUCCESS(res, res);
    1746               0 :   res = GetTopEnclosingMailCite(selNode, address_of(citeNode), aPlaintext);
    1747               0 :   NS_ENSURE_SUCCESS(res, res);
    1748               0 :   if (citeNode)
    1749                 :   {
    1750                 :     // If our selection is just before a break, nudge it to be
    1751                 :     // just after it.  This does two things for us.  It saves us the trouble of having to add
    1752                 :     // a break here ourselves to preserve the "blockness" of the inline span mailquote
    1753                 :     // (in the inline case), and :
    1754                 :     // it means the break won't end up making an empty line that happens to be inside a
    1755                 :     // mailquote (in either inline or block case).  
    1756                 :     // The latter can confuse a user if they click there and start typing,
    1757                 :     // because being in the mailquote may affect wrapping behavior, or font color, etc.
    1758               0 :     nsWSRunObject wsObj(mHTMLEditor, selNode, selOffset);
    1759               0 :     nsCOMPtr<nsIDOMNode> visNode;
    1760               0 :     PRInt32 visOffset=0;
    1761                 :     PRInt16 wsType;
    1762               0 :     res = wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), &visOffset, &wsType);
    1763               0 :     NS_ENSURE_SUCCESS(res, res);
    1764               0 :     if (wsType==nsWSRunObject::eBreak)
    1765                 :     {
    1766                 :       // ok, we are just before a break.  is it inside the mailquote?
    1767                 :       PRInt32 unused;
    1768               0 :       if (nsEditorUtils::IsDescendantOf(visNode, citeNode, &unused))
    1769                 :       {
    1770                 :         // it is.  so lets reset our selection to be just after it.
    1771               0 :         res = mHTMLEditor->GetNodeLocation(visNode, address_of(selNode), &selOffset);
    1772               0 :         NS_ENSURE_SUCCESS(res, res);
    1773               0 :         ++selOffset;
    1774                 :       }
    1775                 :     }
    1776                 :      
    1777               0 :     nsCOMPtr<nsIDOMNode> brNode;
    1778                 :     res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset, 
    1779               0 :                        true, address_of(leftCite), address_of(rightCite));
    1780               0 :     NS_ENSURE_SUCCESS(res, res);
    1781               0 :     res = citeNode->GetParentNode(getter_AddRefs(selNode));
    1782               0 :     NS_ENSURE_SUCCESS(res, res);
    1783               0 :     res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
    1784               0 :     NS_ENSURE_SUCCESS(res, res);
    1785                 :     // want selection before the break, and on same line
    1786               0 :     selPriv->SetInterlinePosition(true);
    1787               0 :     res = aSelection->Collapse(selNode, newOffset);
    1788               0 :     NS_ENSURE_SUCCESS(res, res);
    1789                 :     // if citeNode wasn't a block, we might also want another break before it.
    1790                 :     // We need to examine the content both before the br we just added and also
    1791                 :     // just after it.  If we don't have another br or block boundary adjacent,
    1792                 :     // then we will need a 2nd br added to achieve blank line that user expects.
    1793               0 :     if (IsInlineNode(citeNode))
    1794                 :     {
    1795               0 :       nsWSRunObject wsObj(mHTMLEditor, selNode, newOffset);
    1796               0 :       nsCOMPtr<nsIDOMNode> visNode;
    1797               0 :       PRInt32 visOffset=0;
    1798                 :       PRInt16 wsType;
    1799               0 :       res = wsObj.PriorVisibleNode(selNode, newOffset, address_of(visNode), &visOffset, &wsType);
    1800               0 :       NS_ENSURE_SUCCESS(res, res);
    1801               0 :       if ((wsType==nsWSRunObject::eNormalWS) || 
    1802                 :           (wsType==nsWSRunObject::eText)     ||
    1803                 :           (wsType==nsWSRunObject::eSpecial))
    1804                 :       {
    1805               0 :         nsWSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1);
    1806               0 :         res = wsObjAfterBR.NextVisibleNode(selNode, newOffset+1, address_of(visNode), &visOffset, &wsType);
    1807               0 :         NS_ENSURE_SUCCESS(res, res);
    1808               0 :         if ((wsType==nsWSRunObject::eNormalWS) || 
    1809                 :             (wsType==nsWSRunObject::eText)     ||
    1810                 :             (wsType==nsWSRunObject::eSpecial))
    1811                 :         {
    1812               0 :           res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
    1813               0 :           NS_ENSURE_SUCCESS(res, res);
    1814                 :         }
    1815                 :       }
    1816                 :     }
    1817                 :     // delete any empty cites
    1818               0 :     bool bEmptyCite = false;
    1819               0 :     if (leftCite)
    1820                 :     {
    1821               0 :       res = mHTMLEditor->IsEmptyNode(leftCite, &bEmptyCite, true, false);
    1822               0 :       if (NS_SUCCEEDED(res) && bEmptyCite)
    1823               0 :         res = mHTMLEditor->DeleteNode(leftCite);
    1824               0 :       NS_ENSURE_SUCCESS(res, res);
    1825                 :     }
    1826               0 :     if (rightCite)
    1827                 :     {
    1828               0 :       res = mHTMLEditor->IsEmptyNode(rightCite, &bEmptyCite, true, false);
    1829               0 :       if (NS_SUCCEEDED(res) && bEmptyCite)
    1830               0 :         res = mHTMLEditor->DeleteNode(rightCite);
    1831               0 :       NS_ENSURE_SUCCESS(res, res);
    1832                 :     }
    1833               0 :     *aHandled = true;
    1834                 :   }
    1835               0 :   return NS_OK;
    1836                 : }
    1837                 : 
    1838                 : 
    1839                 : nsresult
    1840               0 : nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, 
    1841                 :                                      nsIEditor::EDirection aAction, 
    1842                 :                                      bool *aCancel,
    1843                 :                                      bool *aHandled)
    1844                 : {
    1845                 : 
    1846               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    1847                 :   // initialize out param
    1848               0 :   *aCancel = false;
    1849               0 :   *aHandled = false;
    1850                 : 
    1851                 :   // remember that we did a selection deletion.  Used by CreateStyleForInsertText()
    1852               0 :   mDidDeleteSelection = true;
    1853                 :   
    1854                 :   // if there is only bogus content, cancel the operation
    1855               0 :   if (mBogusNode) 
    1856                 :   {
    1857               0 :     *aCancel = true;
    1858               0 :     return NS_OK;
    1859                 :   }
    1860                 : 
    1861               0 :   nsresult res = NS_OK;
    1862               0 :   bool bCollapsed, join = false;
    1863               0 :   res = aSelection->GetIsCollapsed(&bCollapsed);
    1864               0 :   NS_ENSURE_SUCCESS(res, res);
    1865                 : 
    1866                 :   // origCollapsed is used later to determine whether we should join 
    1867                 :   // blocks. We don't really care about bCollapsed because it will be 
    1868                 :   // modified by ExtendSelectionForDelete later. JoinBlocks should 
    1869                 :   // happen if the original selection is collapsed and the cursor is 
    1870                 :   // at the end of a block element, in which case ExtendSelectionForDelete 
    1871                 :   // would always make the selection not collapsed.
    1872               0 :   bool origCollapsed = bCollapsed;
    1873               0 :   nsCOMPtr<nsIDOMNode> startNode, selNode;
    1874                 :   PRInt32 startOffset, selOffset;
    1875                 :   
    1876                 :   // first check for table selection mode.  If so,
    1877                 :   // hand off to table editor.
    1878                 :   {
    1879               0 :     nsCOMPtr<nsIDOMElement> cell;
    1880               0 :     res = mHTMLEditor->GetFirstSelectedCell(nsnull, getter_AddRefs(cell));
    1881               0 :     if (NS_SUCCEEDED(res) && cell)
    1882                 :     {
    1883               0 :       res = mHTMLEditor->DeleteTableCellContents();
    1884               0 :       *aHandled = true;
    1885               0 :       return res;
    1886                 :     }
    1887                 :   }
    1888                 : 
    1889               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset);
    1890               0 :   NS_ENSURE_SUCCESS(res, res);
    1891               0 :   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
    1892                 : 
    1893               0 :   if (bCollapsed)
    1894                 :   {
    1895                 :     // if we are inside an empty block, delete it.
    1896               0 :     nsCOMPtr<nsIContent> hostContent = mHTMLEditor->GetActiveEditingHost();
    1897               0 :     nsCOMPtr<nsIDOMNode> hostNode = do_QueryInterface(hostContent);
    1898               0 :     NS_ENSURE_TRUE(hostNode, NS_ERROR_FAILURE);
    1899               0 :     res = CheckForEmptyBlock(startNode, hostNode, aSelection, aHandled);
    1900               0 :     NS_ENSURE_SUCCESS(res, res);
    1901               0 :     if (*aHandled) return NS_OK;
    1902                 : 
    1903                 :     // Test for distance between caret and text that will be deleted
    1904               0 :     res = CheckBidiLevelForDeletion(aSelection, startNode, startOffset, aAction, aCancel);
    1905               0 :     NS_ENSURE_SUCCESS(res, res);
    1906               0 :     if (*aCancel) return NS_OK;
    1907                 : 
    1908               0 :     res = mHTMLEditor->ExtendSelectionForDelete(aSelection, &aAction);
    1909               0 :     NS_ENSURE_SUCCESS(res, res);
    1910                 : 
    1911                 :     // We should delete nothing.
    1912               0 :     if (aAction == nsIEditor::eNone)
    1913               0 :       return NS_OK;
    1914                 : 
    1915                 :     // ExtendSelectionForDelete() may have changed the selection, update it
    1916               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset);
    1917               0 :     NS_ENSURE_SUCCESS(res, res);
    1918               0 :     NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
    1919                 :     
    1920               0 :     res = aSelection->GetIsCollapsed(&bCollapsed);
    1921               0 :     NS_ENSURE_SUCCESS(res, res);
    1922                 :   }
    1923                 : 
    1924               0 :   if (bCollapsed)
    1925                 :   {
    1926                 :     // what's in the direction we are deleting?
    1927               0 :     nsWSRunObject wsObj(mHTMLEditor, startNode, startOffset);
    1928               0 :     nsCOMPtr<nsIDOMNode> visNode;
    1929                 :     PRInt32 visOffset;
    1930                 :     PRInt16 wsType;
    1931                 : 
    1932                 :     // find next visible node
    1933               0 :     if (aAction == nsIEditor::eNext)
    1934               0 :       res = wsObj.NextVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType);
    1935                 :     else
    1936               0 :       res = wsObj.PriorVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType);
    1937               0 :     NS_ENSURE_SUCCESS(res, res);
    1938                 :     
    1939               0 :     if (!visNode) // can't find anything to delete!
    1940                 :     {
    1941               0 :       *aCancel = true;
    1942               0 :       return res;
    1943                 :     }
    1944                 :     
    1945               0 :     if (wsType==nsWSRunObject::eNormalWS)
    1946                 :     {
    1947                 :       // we found some visible ws to delete.  Let ws code handle it.
    1948               0 :       if (aAction == nsIEditor::eNext)
    1949               0 :         res = wsObj.DeleteWSForward();
    1950                 :       else
    1951               0 :         res = wsObj.DeleteWSBackward();
    1952               0 :       *aHandled = true;
    1953               0 :       NS_ENSURE_SUCCESS(res, res);
    1954               0 :       res = InsertBRIfNeeded(aSelection);
    1955               0 :       return res;
    1956                 :     } 
    1957               0 :     else if (wsType==nsWSRunObject::eText)
    1958                 :     {
    1959                 :       // found normal text to delete.  
    1960               0 :       PRInt32 so = visOffset;
    1961               0 :       PRInt32 eo = visOffset+1;
    1962               0 :       if (aAction == nsIEditor::ePrevious) 
    1963                 :       { 
    1964               0 :         if (so == 0) return NS_ERROR_UNEXPECTED;
    1965               0 :         so--; 
    1966               0 :         eo--; 
    1967                 :       }
    1968                 :       else
    1969                 :       {
    1970               0 :         nsCOMPtr<nsIDOMRange> range;
    1971               0 :         res = aSelection->GetRangeAt(0, getter_AddRefs(range));
    1972               0 :         NS_ENSURE_SUCCESS(res, res);
    1973                 : 
    1974                 : #ifdef DEBUG
    1975                 :         nsIDOMNode *container;
    1976                 : 
    1977               0 :         res = range->GetStartContainer(&container);
    1978               0 :         NS_ENSURE_SUCCESS(res, res);
    1979               0 :         NS_ASSERTION(container == visNode, "selection start not in visNode");
    1980                 : 
    1981               0 :         res = range->GetEndContainer(&container);
    1982               0 :         NS_ENSURE_SUCCESS(res, res);
    1983               0 :         NS_ASSERTION(container == visNode, "selection end not in visNode");
    1984                 : #endif
    1985                 : 
    1986               0 :         res = range->GetStartOffset(&so);
    1987               0 :         NS_ENSURE_SUCCESS(res, res);
    1988               0 :         res = range->GetEndOffset(&eo);
    1989               0 :         NS_ENSURE_SUCCESS(res, res);
    1990                 :       }
    1991               0 :       res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, address_of(visNode), &so, address_of(visNode), &eo);
    1992               0 :       NS_ENSURE_SUCCESS(res, res);
    1993               0 :       nsCOMPtr<nsIDOMCharacterData> nodeAsText(do_QueryInterface(visNode));
    1994               0 :       res = mHTMLEditor->DeleteText(nodeAsText, NS_MIN(so, eo), NS_ABS(eo - so));
    1995               0 :       *aHandled = true;
    1996               0 :       NS_ENSURE_SUCCESS(res, res);    
    1997               0 :       res = InsertBRIfNeeded(aSelection);
    1998               0 :       return res;
    1999                 :     }
    2000               0 :     else if ( (wsType==nsWSRunObject::eSpecial)  || 
    2001                 :               (wsType==nsWSRunObject::eBreak)    ||
    2002               0 :               nsHTMLEditUtils::IsHR(visNode) ) 
    2003                 :     {
    2004                 :       // short circuit for invisible breaks.  delete them and recurse.
    2005               0 :       if (nsTextEditUtils::IsBreak(visNode) && !mHTMLEditor->IsVisBreak(visNode))
    2006                 :       {
    2007               0 :         res = mHTMLEditor->DeleteNode(visNode);
    2008               0 :         NS_ENSURE_SUCCESS(res, res);
    2009               0 :         return WillDeleteSelection(aSelection, aAction, aCancel, aHandled);
    2010                 :       }
    2011                 :       
    2012                 :       // special handling for backspace when positioned after <hr>
    2013               0 :       if (aAction == nsIEditor::ePrevious && nsHTMLEditUtils::IsHR(visNode))
    2014                 :       {
    2015                 :         /*
    2016                 :           Only if the caret is positioned at the end-of-hr-line position,
    2017                 :           we want to delete the <hr>.
    2018                 :           
    2019                 :           In other words, we only want to delete, if
    2020                 :           our selection position (indicated by startNode and startOffset)
    2021                 :           is the position directly after the <hr>,
    2022                 :           on the same line as the <hr>.
    2023                 : 
    2024                 :           To detect this case we check:
    2025                 :           startNode == parentOfVisNode
    2026                 :           and
    2027                 :           startOffset -1 == visNodeOffsetToVisNodeParent
    2028                 :           and
    2029                 :           interline position is false (left)
    2030                 : 
    2031                 :           In any other case we set the position to 
    2032                 :           startnode -1 and interlineposition to false,
    2033                 :           only moving the caret to the end-of-hr-line position.
    2034                 :         */
    2035                 : 
    2036               0 :         bool moveOnly = true;
    2037                 : 
    2038               0 :         res = nsEditor::GetNodeLocation(visNode, address_of(selNode), &selOffset);
    2039               0 :         NS_ENSURE_SUCCESS(res, res);
    2040                 : 
    2041                 :         bool interLineIsRight;
    2042               0 :         nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
    2043               0 :         res = selPriv->GetInterlinePosition(&interLineIsRight);
    2044               0 :         NS_ENSURE_SUCCESS(res, res);
    2045                 : 
    2046               0 :         if (startNode == selNode &&
    2047                 :             startOffset -1 == selOffset &&
    2048               0 :             !interLineIsRight)
    2049                 :         {
    2050               0 :           moveOnly = false;
    2051                 :         }
    2052                 :         
    2053               0 :         if (moveOnly)
    2054                 :         {
    2055                 :           // Go to the position after the <hr>, but to the end of the <hr> line
    2056                 :           // by setting the interline position to left.
    2057               0 :           ++selOffset;
    2058               0 :           res = aSelection->Collapse(selNode, selOffset);
    2059               0 :           selPriv->SetInterlinePosition(false);
    2060               0 :           mDidExplicitlySetInterline = true;
    2061               0 :           *aHandled = true;
    2062                 : 
    2063                 :           // There is one exception to the move only case.
    2064                 :           // If the <hr> is followed by a <br> we want to delete the <br>.
    2065                 : 
    2066                 :           PRInt16 otherWSType;
    2067               0 :           nsCOMPtr<nsIDOMNode> otherNode;
    2068                 :           PRInt32 otherOffset;
    2069                 : 
    2070               0 :           res = wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType);
    2071               0 :           NS_ENSURE_SUCCESS(res, res);
    2072                 : 
    2073               0 :           if (otherWSType == nsWSRunObject::eBreak)
    2074                 :           {
    2075                 :             // Delete the <br>
    2076                 : 
    2077               0 :             res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, otherNode);
    2078               0 :             NS_ENSURE_SUCCESS(res, res);
    2079               0 :             res = mHTMLEditor->DeleteNode(otherNode);
    2080               0 :             NS_ENSURE_SUCCESS(res, res);
    2081                 :           }
    2082                 : 
    2083               0 :           return NS_OK;
    2084                 :         }
    2085                 :         // else continue with normal delete code
    2086                 :       }
    2087                 : 
    2088                 :       // found break or image, or hr.  
    2089               0 :       res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, visNode);
    2090               0 :       NS_ENSURE_SUCCESS(res, res);
    2091                 :       // remember sibling to visnode, if any
    2092               0 :       nsCOMPtr<nsIDOMNode> sibling, stepbrother;
    2093               0 :       mHTMLEditor->GetPriorHTMLSibling(visNode, address_of(sibling));
    2094                 :       // delete the node, and join like nodes if appropriate
    2095               0 :       res = mHTMLEditor->DeleteNode(visNode);
    2096               0 :       NS_ENSURE_SUCCESS(res, res);
    2097                 :       // we did something, so lets say so.
    2098               0 :       *aHandled = true;
    2099                 :       // is there a prior node and are they siblings?
    2100               0 :       if (sibling)
    2101               0 :          mHTMLEditor->GetNextHTMLSibling(sibling, address_of(stepbrother));
    2102               0 :       if (startNode == stepbrother) 
    2103                 :       {
    2104                 :         // are they both text nodes?
    2105               0 :         if (mHTMLEditor->IsTextNode(startNode) && mHTMLEditor->IsTextNode(sibling))
    2106                 :         {
    2107                 :           // if so, join them!
    2108               0 :           res = JoinNodesSmart(sibling, startNode, address_of(selNode), &selOffset);
    2109               0 :           NS_ENSURE_SUCCESS(res, res);
    2110                 :           // fix up selection
    2111               0 :           res = aSelection->Collapse(selNode, selOffset);
    2112                 :         }
    2113                 :       }
    2114               0 :       NS_ENSURE_SUCCESS(res, res);    
    2115               0 :       res = InsertBRIfNeeded(aSelection);
    2116               0 :       return res;
    2117                 :     }
    2118               0 :     else if (wsType==nsWSRunObject::eOtherBlock)
    2119                 :     {
    2120                 :       // make sure it's not a table element.  If so, cancel the operation 
    2121                 :       // (translation: users cannot backspace or delete across table cells)
    2122               0 :       if (nsHTMLEditUtils::IsTableElement(visNode))
    2123                 :       {
    2124               0 :         *aCancel = true;
    2125               0 :         return NS_OK;
    2126                 :       }
    2127                 :       
    2128                 :       // next to a block.  See if we are between a block and a br.  If so, we really
    2129                 :       // want to delete the br.  Else join content at selection to the block.
    2130                 :       
    2131               0 :       bool bDeletedBR = false;
    2132                 :       PRInt16 otherWSType;
    2133               0 :       nsCOMPtr<nsIDOMNode> otherNode;
    2134                 :       PRInt32 otherOffset;
    2135                 :       
    2136                 :       // find node in other direction
    2137               0 :       if (aAction == nsIEditor::eNext)
    2138               0 :         res = wsObj.PriorVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType);
    2139                 :       else
    2140               0 :         res = wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType);
    2141               0 :       NS_ENSURE_SUCCESS(res, res);
    2142                 :       
    2143                 :       // first find the adjacent node in the block
    2144               0 :       nsCOMPtr<nsIDOMNode> leafNode, leftNode, rightNode, leftParent, rightParent;
    2145               0 :       if (aAction == nsIEditor::ePrevious) 
    2146                 :       {
    2147               0 :         res = mHTMLEditor->GetLastEditableLeaf( visNode, address_of(leafNode));
    2148               0 :         NS_ENSURE_SUCCESS(res, res);
    2149               0 :         leftNode = leafNode;
    2150               0 :         rightNode = startNode;
    2151                 :       }
    2152                 :       else
    2153                 :       {
    2154               0 :         res = mHTMLEditor->GetFirstEditableLeaf( visNode, address_of(leafNode));
    2155               0 :         NS_ENSURE_SUCCESS(res, res);
    2156               0 :         leftNode = startNode;
    2157               0 :         rightNode = leafNode;
    2158                 :       }
    2159                 :       
    2160               0 :       if (nsTextEditUtils::IsBreak(otherNode))
    2161                 :       {
    2162               0 :         res = mHTMLEditor->DeleteNode(otherNode);
    2163               0 :         NS_ENSURE_SUCCESS(res, res);
    2164               0 :         *aHandled = true;
    2165               0 :         bDeletedBR = true;
    2166                 :       }
    2167                 :       
    2168                 :       // don't cross table boundaries
    2169               0 :       if (leftNode && rightNode)
    2170                 :       {
    2171                 :         bool bInDifTblElems;
    2172               0 :         res = InDifferentTableElements(leftNode, rightNode, &bInDifTblElems);
    2173               0 :         if (NS_FAILED(res) || bInDifTblElems) return res;
    2174                 :       }
    2175                 :       
    2176               0 :       if (bDeletedBR)
    2177                 :       {
    2178                 :         // put selection at edge of block and we are done.
    2179               0 :         nsCOMPtr<nsIDOMNode> newSelNode;
    2180                 :         PRInt32 newSelOffset;
    2181               0 :         res = GetGoodSelPointForNode(leafNode, aAction, address_of(newSelNode), &newSelOffset);
    2182               0 :         NS_ENSURE_SUCCESS(res, res);
    2183               0 :         aSelection->Collapse(newSelNode, newSelOffset);
    2184               0 :         return res;
    2185                 :       }
    2186                 :       
    2187                 :       // else we are joining content to block
    2188                 :       
    2189                 :       // find the relavent blocks
    2190               0 :       if (IsBlockNode(leftNode))
    2191               0 :         leftParent = leftNode;
    2192                 :       else
    2193               0 :         leftParent = mHTMLEditor->GetBlockNodeParent(leftNode);
    2194               0 :       if (IsBlockNode(rightNode))
    2195               0 :         rightParent = rightNode;
    2196                 :       else
    2197               0 :         rightParent = mHTMLEditor->GetBlockNodeParent(rightNode);
    2198                 :       
    2199                 :       // sanity checks
    2200               0 :       NS_ENSURE_TRUE(leftParent && rightParent, NS_ERROR_NULL_POINTER);  
    2201               0 :       if (leftParent == rightParent)
    2202               0 :         return NS_ERROR_UNEXPECTED;  
    2203                 :       
    2204                 :       // now join them
    2205               0 :       nsCOMPtr<nsIDOMNode> selPointNode = startNode;
    2206               0 :       PRInt32 selPointOffset = startOffset;
    2207                 :       {
    2208               0 :         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset);
    2209               0 :         res = JoinBlocks(address_of(leftParent), address_of(rightParent), aCancel);
    2210               0 :         *aHandled = true;
    2211                 :       }
    2212               0 :       aSelection->Collapse(selPointNode, selPointOffset);
    2213               0 :       return res;
    2214                 :     }
    2215               0 :     else if (wsType==nsWSRunObject::eThisBlock)
    2216                 :     {
    2217                 :       // at edge of our block.  Look beside it and see if we can join to an adjacent block
    2218                 :       
    2219                 :       // make sure it's not a table element.  If so, cancel the operation 
    2220                 :       // (translation: users cannot backspace or delete across table cells)
    2221               0 :       if (nsHTMLEditUtils::IsTableElement(visNode))
    2222                 :       {
    2223               0 :         *aCancel = true;
    2224               0 :         return NS_OK;
    2225                 :       }
    2226                 :       
    2227                 :       // first find the relavent nodes
    2228               0 :       nsCOMPtr<nsIDOMNode> leftNode, rightNode, leftParent, rightParent;
    2229               0 :       if (aAction == nsIEditor::ePrevious) 
    2230                 :       {
    2231               0 :         res = mHTMLEditor->GetPriorHTMLNode(visNode, address_of(leftNode));
    2232               0 :         NS_ENSURE_SUCCESS(res, res);
    2233               0 :         rightNode = startNode;
    2234                 :       }
    2235                 :       else
    2236                 :       {
    2237               0 :         res = mHTMLEditor->GetNextHTMLNode( visNode, address_of(rightNode));
    2238               0 :         NS_ENSURE_SUCCESS(res, res);
    2239               0 :         leftNode = startNode;
    2240                 :       }
    2241                 : 
    2242                 :       // nothing to join
    2243               0 :       if (!leftNode || !rightNode)
    2244                 :       {
    2245               0 :         *aCancel = true;
    2246               0 :         return NS_OK;
    2247                 :       }
    2248                 : 
    2249                 :       // don't cross table boundaries
    2250                 :       bool bInDifTblElems;
    2251               0 :       res = InDifferentTableElements(leftNode, rightNode, &bInDifTblElems);
    2252               0 :       if (NS_FAILED(res) || bInDifTblElems) return res;
    2253                 : 
    2254                 :       // find the relavent blocks
    2255               0 :       if (IsBlockNode(leftNode))
    2256               0 :         leftParent = leftNode;
    2257                 :       else
    2258               0 :         leftParent = mHTMLEditor->GetBlockNodeParent(leftNode);
    2259               0 :       if (IsBlockNode(rightNode))
    2260               0 :         rightParent = rightNode;
    2261                 :       else
    2262               0 :         rightParent = mHTMLEditor->GetBlockNodeParent(rightNode);
    2263                 :       
    2264                 :       // sanity checks
    2265               0 :       NS_ENSURE_TRUE(leftParent && rightParent, NS_ERROR_NULL_POINTER);  
    2266               0 :       if (leftParent == rightParent)
    2267               0 :         return NS_ERROR_UNEXPECTED;  
    2268                 :       
    2269                 :       // now join them
    2270               0 :       nsCOMPtr<nsIDOMNode> selPointNode = startNode;
    2271               0 :       PRInt32 selPointOffset = startOffset;
    2272                 :       {
    2273               0 :         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset);
    2274               0 :         res = JoinBlocks(address_of(leftParent), address_of(rightParent), aCancel);
    2275               0 :         *aHandled = true;
    2276                 :       }
    2277               0 :       aSelection->Collapse(selPointNode, selPointOffset);
    2278               0 :       return res;
    2279                 :     }
    2280                 :   }
    2281                 : 
    2282                 :   
    2283                 :   // else we have a non collapsed selection
    2284                 :   // first adjust the selection
    2285               0 :   res = ExpandSelectionForDeletion(aSelection);
    2286               0 :   NS_ENSURE_SUCCESS(res, res);
    2287                 :   
    2288                 :   // remember that we did a ranged delete for the benefit of AfterEditInner().
    2289               0 :   mDidRangedDelete = true;
    2290                 :   
    2291                 :   // refresh start and end points
    2292               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset);
    2293               0 :   NS_ENSURE_SUCCESS(res, res);
    2294               0 :   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
    2295               0 :   nsCOMPtr<nsIDOMNode> endNode;
    2296                 :   PRInt32 endOffset;
    2297               0 :   res = mHTMLEditor->GetEndNodeAndOffset(aSelection, getter_AddRefs(endNode), &endOffset);
    2298               0 :   NS_ENSURE_SUCCESS(res, res); 
    2299               0 :   NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
    2300                 : 
    2301                 :   // figure out if the endpoints are in nodes that can be merged  
    2302                 :   // adjust surrounding whitespace in preperation to delete selection
    2303               0 :   if (!IsPlaintextEditor())
    2304                 :   {
    2305               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    2306                 :     res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor,
    2307                 :                                             address_of(startNode), &startOffset, 
    2308               0 :                                             address_of(endNode), &endOffset);
    2309               0 :     NS_ENSURE_SUCCESS(res, res); 
    2310                 :   }
    2311                 :   
    2312                 :   {
    2313                 :     // track end location of where we are deleting
    2314               0 :     nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset);
    2315                 :     // we are handling all ranged deletions directly now.
    2316               0 :     *aHandled = true;
    2317                 :     
    2318               0 :     if (endNode == startNode)
    2319                 :     {
    2320               0 :       res = mHTMLEditor->DeleteSelectionImpl(aAction);
    2321               0 :       NS_ENSURE_SUCCESS(res, res); 
    2322                 :     }
    2323                 :     else
    2324                 :     {
    2325                 :       // figure out mailcite ancestors
    2326               0 :       nsCOMPtr<nsIDOMNode> endCiteNode, startCiteNode;
    2327                 :       res = GetTopEnclosingMailCite(startNode, address_of(startCiteNode), 
    2328               0 :                                     IsPlaintextEditor());
    2329               0 :       NS_ENSURE_SUCCESS(res, res); 
    2330                 :       res = GetTopEnclosingMailCite(endNode, address_of(endCiteNode), 
    2331               0 :                                     IsPlaintextEditor());
    2332               0 :       NS_ENSURE_SUCCESS(res, res); 
    2333                 :       
    2334                 :       // if we only have a mailcite at one of the two endpoints, set the directionality
    2335                 :       // of the deletion so that the selection will end up outside the mailcite.
    2336               0 :       if (startCiteNode && !endCiteNode)
    2337                 :       {
    2338               0 :         aAction = nsIEditor::eNext;
    2339                 :       }
    2340               0 :       else if (!startCiteNode && endCiteNode)
    2341                 :       {
    2342               0 :         aAction = nsIEditor::ePrevious;
    2343                 :       }
    2344                 :       
    2345                 :       // figure out block parents
    2346               0 :       nsCOMPtr<nsIDOMNode> leftParent;
    2347               0 :       nsCOMPtr<nsIDOMNode> rightParent;
    2348               0 :       if (IsBlockNode(startNode))
    2349               0 :         leftParent = startNode;
    2350                 :       else
    2351               0 :         leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
    2352               0 :       if (IsBlockNode(endNode))
    2353               0 :         rightParent = endNode;
    2354                 :       else
    2355               0 :         rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
    2356                 :         
    2357                 :       // are endpoint block parents the same?  use default deletion
    2358               0 :       if (leftParent == rightParent) 
    2359                 :       {
    2360               0 :         res = mHTMLEditor->DeleteSelectionImpl(aAction);
    2361                 :       }
    2362                 :       else
    2363                 :       {
    2364                 :         // deleting across blocks
    2365                 :         // are the blocks of same type?
    2366               0 :         NS_ENSURE_STATE(leftParent && rightParent);
    2367                 :         
    2368                 :         // are the blocks siblings?
    2369               0 :         nsCOMPtr<nsIDOMNode> leftBlockParent;
    2370               0 :         nsCOMPtr<nsIDOMNode> rightBlockParent;
    2371               0 :         leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
    2372               0 :         rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
    2373                 : 
    2374                 :         // MOOSE: this could conceivably screw up a table.. fix me.
    2375               0 :         if (   (leftBlockParent == rightBlockParent)
    2376               0 :             && (mHTMLEditor->NodesSameType(leftParent, rightParent))  )
    2377                 :         {
    2378               0 :           if (nsHTMLEditUtils::IsParagraph(leftParent))
    2379                 :           {
    2380                 :             // first delete the selection
    2381               0 :             res = mHTMLEditor->DeleteSelectionImpl(aAction);
    2382               0 :             NS_ENSURE_SUCCESS(res, res);
    2383                 :             // then join para's, insert break
    2384               0 :             res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
    2385               0 :             NS_ENSURE_SUCCESS(res, res);
    2386                 :             // fix up selection
    2387               0 :             res = aSelection->Collapse(selNode,selOffset);
    2388               0 :             return res;
    2389                 :           }
    2390               0 :           if (nsHTMLEditUtils::IsListItem(leftParent)
    2391               0 :               || nsHTMLEditUtils::IsHeader(leftParent))
    2392                 :           {
    2393                 :             // first delete the selection
    2394               0 :             res = mHTMLEditor->DeleteSelectionImpl(aAction);
    2395               0 :             NS_ENSURE_SUCCESS(res, res);
    2396                 :             // join blocks
    2397               0 :             res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
    2398               0 :             NS_ENSURE_SUCCESS(res, res);
    2399                 :             // fix up selection
    2400               0 :             res = aSelection->Collapse(selNode,selOffset);
    2401               0 :             return res;
    2402                 :           }
    2403                 :         }
    2404                 :         
    2405                 :         // else blocks not same type, or not siblings.  Delete everything except
    2406                 :         // table elements.
    2407               0 :         nsCOMPtr<nsIEnumerator> enumerator;
    2408               0 :         nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
    2409               0 :         res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    2410               0 :         NS_ENSURE_SUCCESS(res, res);
    2411               0 :         NS_ENSURE_TRUE(enumerator, NS_ERROR_UNEXPECTED);
    2412                 : 
    2413               0 :         join = true;
    2414                 : 
    2415               0 :         for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
    2416                 :         {
    2417               0 :           nsCOMPtr<nsISupports> currentItem;
    2418               0 :           res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    2419               0 :           NS_ENSURE_SUCCESS(res, res);
    2420               0 :           NS_ENSURE_TRUE(currentItem, NS_ERROR_UNEXPECTED);
    2421                 : 
    2422                 :           // build a list of nodes in the range
    2423               0 :           nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    2424               0 :           nsCOMArray<nsIDOMNode> arrayOfNodes;
    2425               0 :           nsTrivialFunctor functor;
    2426               0 :           nsDOMSubtreeIterator iter;
    2427               0 :           res = iter.Init(range);
    2428               0 :           NS_ENSURE_SUCCESS(res, res);
    2429               0 :           res = iter.AppendList(functor, arrayOfNodes);
    2430               0 :           NS_ENSURE_SUCCESS(res, res);
    2431                 :       
    2432                 :           // now that we have the list, delete non table elements
    2433               0 :           PRInt32 listCount = arrayOfNodes.Count();
    2434               0 :           for (PRInt32 j = 0; j < listCount; j++) {
    2435               0 :             nsIDOMNode* somenode = arrayOfNodes[0];
    2436               0 :             res = DeleteNonTableElements(somenode);
    2437               0 :             arrayOfNodes.RemoveObjectAt(0);
    2438                 :             // If something visible is deleted, no need to join.
    2439                 :             // Visible means all nodes except non-visible textnodes and breaks.
    2440               0 :             if (join && origCollapsed) {
    2441               0 :               nsCOMPtr<nsIContent> content = do_QueryInterface(somenode);
    2442               0 :               if (!content) {
    2443               0 :                 join = false;
    2444               0 :               } else if (content->NodeType() == nsIDOMNode::TEXT_NODE) {
    2445               0 :                 mHTMLEditor->IsVisTextNode(content, &join, true);
    2446                 :               } else {
    2447               0 :                 join = content->IsHTML(nsGkAtoms::br) &&
    2448               0 :                        !mHTMLEditor->IsVisBreak(somenode);
    2449                 :               }
    2450                 :             }
    2451                 :           }
    2452                 :         }
    2453                 :         
    2454                 :         // check endopints for possible text deletion.
    2455                 :         // we can assume that if text node is found, we can
    2456                 :         // delete to end or to begining as appropriate,
    2457                 :         // since the case where both sel endpoints in same
    2458                 :         // text node was already handled (we wouldn't be here)
    2459               0 :         if ( mHTMLEditor->IsTextNode(startNode) )
    2460                 :         {
    2461                 :           // delete to last character
    2462               0 :           nsCOMPtr<nsIDOMCharacterData>nodeAsText;
    2463                 :           PRUint32 len;
    2464               0 :           nodeAsText = do_QueryInterface(startNode);
    2465               0 :           nodeAsText->GetLength(&len);
    2466               0 :           if (len > (PRUint32)startOffset)
    2467                 :           {
    2468               0 :             res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
    2469               0 :             NS_ENSURE_SUCCESS(res, res);
    2470                 :           }
    2471                 :         }
    2472               0 :         if ( mHTMLEditor->IsTextNode(endNode) )
    2473                 :         {
    2474                 :           // delete to first character
    2475               0 :           nsCOMPtr<nsIDOMCharacterData>nodeAsText;
    2476               0 :           nodeAsText = do_QueryInterface(endNode);
    2477               0 :           if (endOffset)
    2478                 :           {
    2479               0 :             res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
    2480               0 :             NS_ENSURE_SUCCESS(res, res);
    2481                 :           }
    2482                 :         }
    2483                 : 
    2484               0 :         if (join) {
    2485                 :           res = JoinBlocks(address_of(leftParent), address_of(rightParent),
    2486               0 :                            aCancel);
    2487               0 :           NS_ENSURE_SUCCESS(res, res);
    2488                 :         }
    2489                 :       }
    2490                 :     }
    2491                 :   }
    2492                 :   //If we're joining blocks: if deleting forward the selection should be 
    2493                 :   //collapsed to the end of the selection, if deleting backward the selection 
    2494                 :   //should be collapsed to the beginning of the selection. But if we're not 
    2495                 :   //joining then the selection should collapse to the beginning of the 
    2496                 :   //selection if we'redeleting forward, because the end of the selection will 
    2497                 :   //still be in the next block. And same thing for deleting backwards 
    2498                 :   //(selection should collapse to the end, because the beginning will still 
    2499                 :   //be in the first block). See Bug 507936
    2500               0 :   if (join ? aAction == nsIEditor::eNext : aAction == nsIEditor::ePrevious)
    2501                 :   {
    2502               0 :     res = aSelection->Collapse(endNode,endOffset);
    2503                 :   }
    2504                 :   else
    2505                 :   {
    2506               0 :     res = aSelection->Collapse(startNode,startOffset);
    2507                 :   }
    2508               0 :   return res;
    2509                 : }  
    2510                 : 
    2511                 : 
    2512                 : /*****************************************************************************************************
    2513                 : *    InsertBRIfNeeded: determines if a br is needed for current selection to not be spastic.
    2514                 : *    If so, it inserts one.  Callers responsibility to only call with collapsed selection.
    2515                 : *         nsISelection *aSelection      the collapsed selection 
    2516                 : */
    2517                 : nsresult
    2518               0 : nsHTMLEditRules::InsertBRIfNeeded(nsISelection *aSelection)
    2519                 : {
    2520               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    2521                 :   
    2522                 :   // get selection  
    2523               0 :   nsCOMPtr<nsIDOMNode> node;
    2524                 :   PRInt32 offset;
    2525               0 :   nsresult res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
    2526               0 :   NS_ENSURE_SUCCESS(res, res);
    2527               0 :   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    2528                 : 
    2529                 :   // inline elements don't need any br
    2530               0 :   if (!IsBlockNode(node))
    2531               0 :     return res;
    2532                 : 
    2533                 :   // examine selection
    2534               0 :   nsWSRunObject wsObj(mHTMLEditor, node, offset);
    2535               0 :   if (((wsObj.mStartReason & nsWSRunObject::eBlock) || (wsObj.mStartReason & nsWSRunObject::eBreak))
    2536                 :       && (wsObj.mEndReason & nsWSRunObject::eBlock))
    2537                 :   {
    2538                 :     // if we are tucked between block boundaries then insert a br
    2539                 :     // first check that we are allowed to
    2540               0 :     if (mHTMLEditor->CanContainTag(node, NS_LITERAL_STRING("br")))
    2541                 :     {
    2542               0 :       nsCOMPtr<nsIDOMNode> brNode;
    2543               0 :       res = mHTMLEditor->CreateBR(node, offset, address_of(brNode), nsIEditor::ePrevious);
    2544                 :     }
    2545                 :   }
    2546               0 :   return res;
    2547                 : }
    2548                 : 
    2549                 : /*****************************************************************************************************
    2550                 : *    GetGoodSelPointForNode: Finds where at a node you would want to set the selection if you were
    2551                 : *    trying to have a caret next to it.
    2552                 : *         nsIDOMNode *aNode                  the node 
    2553                 : *         nsIEditor::EDirection aAction      which edge to find: eNext indicates beginning, ePrevious ending
    2554                 : *         nsCOMPtr<nsIDOMNode> *outSelNode   desired sel node
    2555                 : *         PRInt32 *outSelOffset              desired sel offset
    2556                 : */
    2557                 : nsresult
    2558               0 : nsHTMLEditRules::GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction, 
    2559                 :                                         nsCOMPtr<nsIDOMNode> *outSelNode, PRInt32 *outSelOffset)
    2560                 : {
    2561               0 :   NS_ENSURE_TRUE(aNode && outSelNode && outSelOffset, NS_ERROR_NULL_POINTER);
    2562                 :   
    2563               0 :   nsresult res = NS_OK;
    2564                 :   
    2565                 :   // default values
    2566               0 :   *outSelNode = aNode;
    2567               0 :   *outSelOffset = 0;
    2568                 :   
    2569               0 :   if (mHTMLEditor->IsTextNode(aNode) || mHTMLEditor->IsContainer(aNode))
    2570                 :   {
    2571               0 :     if (aAction == nsIEditor::ePrevious)
    2572                 :     {
    2573                 :       PRUint32 len;
    2574               0 :       res = mHTMLEditor->GetLengthOfDOMNode(aNode, len);
    2575               0 :       *outSelOffset = PRInt32(len);
    2576               0 :       NS_ENSURE_SUCCESS(res, res);
    2577                 :     }
    2578                 :   }
    2579                 :   else 
    2580                 :   {
    2581               0 :     res = nsEditor::GetNodeLocation(aNode, outSelNode, outSelOffset);
    2582               0 :     NS_ENSURE_SUCCESS(res, res);
    2583               0 :     if (!nsTextEditUtils::IsBreak(aNode) || mHTMLEditor->IsVisBreak(aNode))
    2584                 :     {
    2585               0 :       if (aAction == nsIEditor::ePrevious)
    2586               0 :         (*outSelOffset)++;
    2587                 :     }
    2588                 :   }
    2589               0 :   return res;
    2590                 : }
    2591                 : 
    2592                 : 
    2593                 : /*****************************************************************************************************
    2594                 : *    JoinBlocks: this method is used to join two block elements.  The right element is always joined
    2595                 : *    to the left element.  If the elements are the same type and not nested within each other, 
    2596                 : *    JoinNodesSmart is called (example, joining two list items together into one).  If the elements
    2597                 : *    are not the same type, or one is a descendant of the other, we instead destroy the right block
    2598                 : *    placing its children into leftblock.  DTD containment rules are followed throughout.
    2599                 : *         nsCOMPtr<nsIDOMNode> *aLeftBlock         pointer to the left block
    2600                 : *         nsCOMPtr<nsIDOMNode> *aRightBlock        pointer to the right block; will have contents moved to left block
    2601                 : *         bool *aCanceled                        return TRUE if we had to cancel operation
    2602                 : */
    2603                 : nsresult
    2604               0 : nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock, 
    2605                 :                             nsCOMPtr<nsIDOMNode> *aRightBlock, 
    2606                 :                             bool *aCanceled)
    2607                 : {
    2608               0 :   NS_ENSURE_TRUE(aLeftBlock && aRightBlock && *aLeftBlock  && *aRightBlock, NS_ERROR_NULL_POINTER);
    2609               0 :   if (nsHTMLEditUtils::IsTableElement(*aLeftBlock) || nsHTMLEditUtils::IsTableElement(*aRightBlock))
    2610                 :   {
    2611                 :     // do not try to merge table elements
    2612               0 :     *aCanceled = true;
    2613               0 :     return NS_OK;
    2614                 :   }
    2615                 : 
    2616                 :   // make sure we don't try to move thing's into HR's, which look like blocks but aren't containers
    2617               0 :   if (nsHTMLEditUtils::IsHR(*aLeftBlock))
    2618                 :   {
    2619               0 :     nsCOMPtr<nsIDOMNode> realLeft = mHTMLEditor->GetBlockNodeParent(*aLeftBlock);
    2620               0 :     *aLeftBlock = realLeft;
    2621                 :   }
    2622               0 :   if (nsHTMLEditUtils::IsHR(*aRightBlock))
    2623                 :   {
    2624               0 :     nsCOMPtr<nsIDOMNode> realRight = mHTMLEditor->GetBlockNodeParent(*aRightBlock);
    2625               0 :     *aRightBlock = realRight;
    2626                 :   }
    2627                 : 
    2628                 :   // bail if both blocks the same
    2629               0 :   if (*aLeftBlock == *aRightBlock)
    2630                 :   {
    2631               0 :     *aCanceled = true;
    2632               0 :     return NS_OK;
    2633                 :   }
    2634                 :   
    2635                 :   // Joining a list item to its parent is a NOP.
    2636               0 :   if (nsHTMLEditUtils::IsList(*aLeftBlock) && nsHTMLEditUtils::IsListItem(*aRightBlock))
    2637                 :   {
    2638               0 :     nsCOMPtr<nsIDOMNode> rightParent;
    2639               0 :     (*aRightBlock)->GetParentNode(getter_AddRefs(rightParent));
    2640               0 :     if (rightParent == *aLeftBlock)
    2641               0 :       return NS_OK;
    2642                 :   }
    2643                 : 
    2644                 :   // special rule here: if we are trying to join list items, and they are in different lists,
    2645                 :   // join the lists instead.
    2646               0 :   bool bMergeLists = false;
    2647               0 :   nsAutoString existingListStr;
    2648                 :   PRInt32 theOffset;
    2649               0 :   nsCOMPtr<nsIDOMNode> leftList, rightList;
    2650               0 :   if (nsHTMLEditUtils::IsListItem(*aLeftBlock) && nsHTMLEditUtils::IsListItem(*aRightBlock))
    2651                 :   {
    2652               0 :     (*aLeftBlock)->GetParentNode(getter_AddRefs(leftList));
    2653               0 :     (*aRightBlock)->GetParentNode(getter_AddRefs(rightList));
    2654               0 :     if (leftList && rightList && (leftList!=rightList))
    2655                 :     {
    2656                 :       // there are some special complications if the lists are descendants of
    2657                 :       // the other lists' items.  Note that it is ok for them to be descendants
    2658                 :       // of the other lists themselves, which is the usual case for sublists
    2659                 :       // in our impllementation.
    2660               0 :       if (!nsEditorUtils::IsDescendantOf(leftList, *aRightBlock, &theOffset) &&
    2661               0 :           !nsEditorUtils::IsDescendantOf(rightList, *aLeftBlock, &theOffset))
    2662                 :       {
    2663               0 :         *aLeftBlock = leftList;
    2664               0 :         *aRightBlock = rightList;
    2665               0 :         bMergeLists = true;
    2666               0 :         mHTMLEditor->GetTagString(leftList, existingListStr);
    2667               0 :         ToLowerCase(existingListStr);
    2668                 :       }
    2669                 :     }
    2670                 :   }
    2671                 :   
    2672               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    2673                 :   
    2674               0 :   nsresult res = NS_OK;
    2675               0 :   PRInt32  rightOffset = 0;
    2676               0 :   PRInt32  leftOffset  = -1;
    2677                 : 
    2678                 :   // theOffset below is where you find yourself in aRightBlock when you traverse upwards
    2679                 :   // from aLeftBlock
    2680               0 :   if (nsEditorUtils::IsDescendantOf(*aLeftBlock, *aRightBlock, &rightOffset))
    2681                 :   {
    2682                 :     // tricky case.  left block is inside right block.
    2683                 :     // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
    2684               0 :     rightOffset++;
    2685               0 :     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aLeftBlock, nsWSRunObject::kBlockEnd);
    2686               0 :     NS_ENSURE_SUCCESS(res, res);
    2687               0 :     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aRightBlock, nsWSRunObject::kAfterBlock, &rightOffset);
    2688               0 :     NS_ENSURE_SUCCESS(res, res);
    2689                 :     // Do br adjustment.
    2690               0 :     nsCOMPtr<nsIDOMNode> brNode;
    2691               0 :     res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
    2692               0 :     NS_ENSURE_SUCCESS(res, res);
    2693               0 :     if (bMergeLists)
    2694                 :     {
    2695                 :       // idea here is to take all children in  rightList that are past
    2696                 :       // theOffset, and pull them into leftlist.
    2697               0 :       nsCOMPtr<nsIDOMNode> childToMove;
    2698               0 :       nsCOMPtr<nsIContent> parent(do_QueryInterface(rightList));
    2699               0 :       NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
    2700                 : 
    2701               0 :       nsIContent *child = parent->GetChildAt(theOffset);
    2702               0 :       while (child)
    2703                 :       {
    2704               0 :         childToMove = do_QueryInterface(child);
    2705               0 :         res = mHTMLEditor->MoveNode(childToMove, leftList, -1);
    2706               0 :         NS_ENSURE_SUCCESS(res, res);
    2707                 : 
    2708               0 :         child = parent->GetChildAt(rightOffset);
    2709                 :       }
    2710                 :     }
    2711                 :     else
    2712                 :     {
    2713               0 :       res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
    2714                 :     }
    2715               0 :     if (brNode) mHTMLEditor->DeleteNode(brNode);
    2716                 :   }
    2717                 :   // theOffset below is where you find yourself in aLeftBlock when you traverse upwards
    2718                 :   // from aRightBlock
    2719               0 :   else if (nsEditorUtils::IsDescendantOf(*aRightBlock, *aLeftBlock, &leftOffset))
    2720                 :   {
    2721                 :     // tricky case.  right block is inside left block.
    2722                 :     // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
    2723               0 :     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aRightBlock, nsWSRunObject::kBlockStart);
    2724               0 :     NS_ENSURE_SUCCESS(res, res);
    2725               0 :     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aLeftBlock, nsWSRunObject::kBeforeBlock, &leftOffset);
    2726               0 :     NS_ENSURE_SUCCESS(res, res);
    2727                 :     // Do br adjustment.
    2728               0 :     nsCOMPtr<nsIDOMNode> brNode;
    2729               0 :     res = CheckForInvisibleBR(*aLeftBlock, kBeforeBlock, address_of(brNode), leftOffset);
    2730               0 :     NS_ENSURE_SUCCESS(res, res);
    2731               0 :     if (bMergeLists)
    2732                 :     {
    2733               0 :       res = MoveContents(rightList, leftList, &leftOffset);
    2734                 :     }
    2735                 :     else
    2736                 :     {
    2737               0 :       res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
    2738                 :     }
    2739               0 :     if (brNode) mHTMLEditor->DeleteNode(brNode);
    2740                 :   }
    2741                 :   else
    2742                 :   {
    2743                 :     // normal case.  blocks are siblings, or at least close enough to siblings.  An example
    2744                 :     // of the latter is a <p>paragraph</p><ul><li>one<li>two<li>three</ul>.  The first
    2745                 :     // li and the p are not true siblings, but we still want to join them if you backspace
    2746                 :     // from li into p.
    2747                 :     
    2748                 :     // adjust whitespace at block boundaries
    2749               0 :     res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, *aLeftBlock, *aRightBlock);
    2750               0 :     NS_ENSURE_SUCCESS(res, res);
    2751                 :     // Do br adjustment.
    2752               0 :     nsCOMPtr<nsIDOMNode> brNode;
    2753               0 :     res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
    2754               0 :     NS_ENSURE_SUCCESS(res, res);
    2755               0 :     if (bMergeLists || mHTMLEditor->NodesSameType(*aLeftBlock, *aRightBlock))
    2756                 :     {
    2757                 :       // nodes are same type.  merge them.
    2758               0 :       nsCOMPtr<nsIDOMNode> parent;
    2759                 :       PRInt32 offset;
    2760               0 :       res = JoinNodesSmart(*aLeftBlock, *aRightBlock, address_of(parent), &offset);
    2761               0 :       if (NS_SUCCEEDED(res) && bMergeLists)
    2762                 :       {
    2763               0 :         nsCOMPtr<nsIDOMNode> newBlock;
    2764               0 :         res = ConvertListType(*aRightBlock, address_of(newBlock), existingListStr, NS_LITERAL_STRING("li"));
    2765                 :       }
    2766                 :     }
    2767                 :     else
    2768                 :     {
    2769                 :       // nodes are disimilar types. 
    2770               0 :       res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
    2771                 :     }
    2772               0 :     if (NS_SUCCEEDED(res) && brNode)
    2773                 :     {
    2774               0 :       res = mHTMLEditor->DeleteNode(brNode);
    2775                 :     }
    2776                 :   }
    2777               0 :   return res;
    2778                 : }
    2779                 : 
    2780                 : 
    2781                 : /*****************************************************************************************************
    2782                 : *    MoveBlock: this method is used to move the content from rightBlock into leftBlock
    2783                 : *    Note that the "block" might merely be inline nodes between <br>s, or between blocks, etc.
    2784                 : *    DTD containment rules are followed throughout.
    2785                 : *         nsIDOMNode *aLeftBlock         parent to receive moved content
    2786                 : *         nsIDOMNode *aRightBlock        parent to provide moved content
    2787                 : *         PRInt32 aLeftOffset            offset in aLeftBlock to move content to
    2788                 : *         PRInt32 aRightOffset           offset in aRightBlock to move content from
    2789                 : */
    2790                 : nsresult
    2791               0 : nsHTMLEditRules::MoveBlock(nsIDOMNode *aLeftBlock, nsIDOMNode *aRightBlock, PRInt32 aLeftOffset, PRInt32 aRightOffset)
    2792                 : {
    2793               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    2794               0 :   nsCOMPtr<nsISupports> isupports;
    2795                 :   // GetNodesFromPoint is the workhorse that figures out what we wnat to move.
    2796               0 :   nsresult res = GetNodesFromPoint(DOMPoint(aRightBlock,aRightOffset), kMakeList, arrayOfNodes, true);
    2797               0 :   NS_ENSURE_SUCCESS(res, res);
    2798               0 :   PRInt32 listCount = arrayOfNodes.Count();
    2799                 :   PRInt32 i;
    2800               0 :   for (i=0; i<listCount; i++)
    2801                 :   {
    2802                 :     // get the node to act on
    2803               0 :     nsIDOMNode* curNode = arrayOfNodes[i];
    2804               0 :     if (IsBlockNode(curNode))
    2805                 :     {
    2806                 :       // For block nodes, move their contents only, then delete block.
    2807               0 :       res = MoveContents(curNode, aLeftBlock, &aLeftOffset); 
    2808               0 :       NS_ENSURE_SUCCESS(res, res);
    2809               0 :       res = mHTMLEditor->DeleteNode(curNode);
    2810                 :     }
    2811                 :     else
    2812                 :     {
    2813                 :       // otherwise move the content as is, checking against the dtd.
    2814               0 :       res = MoveNodeSmart(curNode, aLeftBlock, &aLeftOffset);
    2815                 :     }
    2816                 :   }
    2817               0 :   return res;
    2818                 : }
    2819                 : 
    2820                 : /*****************************************************************************************************
    2821                 : *    MoveNodeSmart: this method is used to move node aSource to (aDest,aOffset).
    2822                 : *    DTD containment rules are followed throughout.  aOffset is updated to point _after_
    2823                 : *    inserted content.
    2824                 : *         nsIDOMNode *aSource       the selection.  
    2825                 : *         nsIDOMNode *aDest         parent to receive moved content
    2826                 : *         PRInt32 *aOffset          offset in aDest to move content to
    2827                 : */
    2828                 : nsresult
    2829               0 : nsHTMLEditRules::MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset)
    2830                 : {
    2831               0 :   NS_ENSURE_TRUE(aSource && aDest && aOffset, NS_ERROR_NULL_POINTER);
    2832                 : 
    2833               0 :   nsAutoString tag;
    2834                 :   nsresult res;
    2835               0 :   res = mHTMLEditor->GetTagString(aSource, tag);
    2836               0 :   NS_ENSURE_SUCCESS(res, res);
    2837               0 :   ToLowerCase(tag);
    2838                 :   // check if this node can go into the destination node
    2839               0 :   if (mHTMLEditor->CanContainTag(aDest, tag))
    2840                 :   {
    2841                 :     // if it can, move it there
    2842               0 :     res = mHTMLEditor->MoveNode(aSource, aDest, *aOffset);
    2843               0 :     NS_ENSURE_SUCCESS(res, res);
    2844               0 :     if (*aOffset != -1) ++(*aOffset);
    2845                 :   }
    2846                 :   else
    2847                 :   {
    2848                 :     // if it can't, move its children, and then delete it.
    2849               0 :     res = MoveContents(aSource, aDest, aOffset);
    2850               0 :     NS_ENSURE_SUCCESS(res, res);
    2851               0 :     res = mHTMLEditor->DeleteNode(aSource);
    2852               0 :     NS_ENSURE_SUCCESS(res, res);
    2853                 :   }
    2854               0 :   return NS_OK;
    2855                 : }
    2856                 : 
    2857                 : /*****************************************************************************************************
    2858                 : *    MoveContents: this method is used to move node the _contents_ of aSource to (aDest,aOffset).
    2859                 : *    DTD containment rules are followed throughout.  aOffset is updated to point _after_
    2860                 : *    inserted content.  aSource is deleted.
    2861                 : *         nsIDOMNode *aSource       the selection.  
    2862                 : *         nsIDOMNode *aDest         parent to receive moved content
    2863                 : *         PRInt32 *aOffset          offset in aDest to move content to
    2864                 : */
    2865                 : nsresult
    2866               0 : nsHTMLEditRules::MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset)
    2867                 : {
    2868               0 :   NS_ENSURE_TRUE(aSource && aDest && aOffset, NS_ERROR_NULL_POINTER);
    2869               0 :   if (aSource == aDest) return NS_ERROR_ILLEGAL_VALUE;
    2870               0 :   NS_ASSERTION(!mHTMLEditor->IsTextNode(aSource), "#text does not have contents");
    2871                 :   
    2872               0 :   nsCOMPtr<nsIDOMNode> child;
    2873               0 :   nsAutoString tag;
    2874                 :   nsresult res;
    2875               0 :   aSource->GetFirstChild(getter_AddRefs(child));
    2876               0 :   while (child)
    2877                 :   {
    2878               0 :     res = MoveNodeSmart(child, aDest, aOffset);
    2879               0 :     NS_ENSURE_SUCCESS(res, res);
    2880               0 :     aSource->GetFirstChild(getter_AddRefs(child));
    2881                 :   }
    2882               0 :   return NS_OK;
    2883                 : }
    2884                 : 
    2885                 : 
    2886                 : nsresult
    2887               0 : nsHTMLEditRules::DeleteNonTableElements(nsIDOMNode *aNode)
    2888                 : {
    2889               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    2890               0 :   nsresult res = NS_OK;
    2891               0 :   if (nsHTMLEditUtils::IsTableElementButNotTable(aNode))
    2892                 :   {
    2893               0 :     nsCOMPtr<nsIDOMNodeList> children;
    2894               0 :     aNode->GetChildNodes(getter_AddRefs(children));
    2895               0 :     if (children)
    2896                 :     {
    2897                 :       PRUint32 len;
    2898               0 :       children->GetLength(&len);
    2899               0 :       NS_ENSURE_TRUE(len, NS_OK);
    2900                 :       PRInt32 j;
    2901               0 :       for (j=len-1; j>=0; j--)
    2902                 :       {
    2903               0 :         nsCOMPtr<nsIDOMNode> node;
    2904               0 :         children->Item(j,getter_AddRefs(node));
    2905               0 :         res = DeleteNonTableElements(node);
    2906               0 :         NS_ENSURE_SUCCESS(res, res);
    2907                 : 
    2908                 :       }
    2909                 :     }
    2910                 :   }
    2911                 :   else
    2912                 :   {
    2913               0 :     res = mHTMLEditor->DeleteNode(aNode);
    2914               0 :     NS_ENSURE_SUCCESS(res, res);
    2915                 :   }
    2916               0 :   return res;
    2917                 : }
    2918                 : 
    2919                 : nsresult
    2920               0 : nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection, 
    2921                 :                                     nsIEditor::EDirection aDir, 
    2922                 :                                     nsresult aResult)
    2923                 : {
    2924               0 :   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
    2925                 :   
    2926                 :   // find where we are
    2927               0 :   nsCOMPtr<nsIDOMNode> startNode;
    2928                 :   PRInt32 startOffset;
    2929               0 :   nsresult res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset);
    2930               0 :   NS_ENSURE_SUCCESS(res, res);
    2931               0 :   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
    2932                 :   
    2933                 :   // find any enclosing mailcite
    2934               0 :   nsCOMPtr<nsIDOMNode> citeNode;
    2935                 :   res = GetTopEnclosingMailCite(startNode, address_of(citeNode), 
    2936               0 :                                 IsPlaintextEditor());
    2937               0 :   NS_ENSURE_SUCCESS(res, res);
    2938               0 :   if (citeNode) {
    2939               0 :     nsCOMPtr<nsINode> cite = do_QueryInterface(citeNode);
    2940               0 :     bool isEmpty = true, seenBR = false;
    2941               0 :     mHTMLEditor->IsEmptyNodeImpl(cite, &isEmpty, true, true, false, &seenBR);
    2942               0 :     if (isEmpty)
    2943                 :     {
    2944               0 :       nsCOMPtr<nsIDOMNode> parent, brNode;
    2945                 :       PRInt32 offset;
    2946               0 :       nsEditor::GetNodeLocation(citeNode, address_of(parent), &offset);
    2947               0 :       res = mHTMLEditor->DeleteNode(citeNode);
    2948               0 :       NS_ENSURE_SUCCESS(res, res);
    2949               0 :       if (parent && seenBR)
    2950                 :       {
    2951               0 :         res = mHTMLEditor->CreateBR(parent, offset, address_of(brNode));
    2952               0 :         NS_ENSURE_SUCCESS(res, res);
    2953               0 :         aSelection->Collapse(parent, offset);
    2954                 :       }
    2955                 :     }
    2956                 :   }
    2957                 :   
    2958                 :   // call through to base class
    2959               0 :   return nsTextEditRules::DidDeleteSelection(aSelection, aDir, aResult);
    2960                 : }
    2961                 : 
    2962                 : nsresult
    2963               0 : nsHTMLEditRules::WillMakeList(nsISelection *aSelection, 
    2964                 :                               const nsAString *aListType, 
    2965                 :                               bool aEntireList,
    2966                 :                               const nsAString *aBulletType,
    2967                 :                               bool *aCancel,
    2968                 :                               bool *aHandled,
    2969                 :                               const nsAString *aItemType)
    2970                 : {
    2971               0 :   if (!aSelection || !aListType || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    2972                 : 
    2973               0 :   nsresult res = WillInsert(aSelection, aCancel);
    2974               0 :   NS_ENSURE_SUCCESS(res, res);
    2975                 : 
    2976                 :   // initialize out param
    2977                 :   // we want to ignore result of WillInsert()
    2978               0 :   *aCancel = false;
    2979               0 :   *aHandled = false;
    2980                 : 
    2981                 :   // deduce what tag to use for list items
    2982               0 :   nsAutoString itemType;
    2983               0 :   if (aItemType) 
    2984               0 :     itemType = *aItemType;
    2985               0 :   else if (aListType->LowerCaseEqualsLiteral("dl"))
    2986               0 :     itemType.AssignLiteral("dd");
    2987                 :   else
    2988               0 :     itemType.AssignLiteral("li");
    2989                 :     
    2990                 :   // convert the selection ranges into "promoted" selection ranges:
    2991                 :   // this basically just expands the range to include the immediate
    2992                 :   // block parent, and then further expands to include any ancestors
    2993                 :   // whose children are all in the range
    2994                 :   
    2995               0 :   *aHandled = true;
    2996                 : 
    2997               0 :   res = NormalizeSelection(aSelection);
    2998               0 :   NS_ENSURE_SUCCESS(res, res);
    2999               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3000                 :   
    3001               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    3002               0 :   res = GetListActionNodes(arrayOfNodes, aEntireList);
    3003               0 :   NS_ENSURE_SUCCESS(res, res);
    3004                 :   
    3005               0 :   PRInt32 listCount = arrayOfNodes.Count();
    3006                 :   
    3007                 :   // check if all our nodes are <br>s, or empty inlines
    3008               0 :   bool bOnlyBreaks = true;
    3009                 :   PRInt32 j;
    3010               0 :   for (j=0; j<listCount; j++)
    3011                 :   {
    3012               0 :     nsIDOMNode* curNode = arrayOfNodes[j];
    3013                 :     // if curNode is not a Break or empty inline, we're done
    3014               0 :     if ( (!nsTextEditUtils::IsBreak(curNode)) && (!IsEmptyInline(curNode)) )
    3015                 :     {
    3016               0 :       bOnlyBreaks = false;
    3017               0 :       break;
    3018                 :     }
    3019                 :   }
    3020                 :   
    3021                 :   // if no nodes, we make empty list.  Ditto if the user tried to make a list of some # of breaks.
    3022               0 :   if (!listCount || bOnlyBreaks) 
    3023                 :   {
    3024               0 :     nsCOMPtr<nsIDOMNode> parent, theList, theListItem;
    3025                 :     PRInt32 offset;
    3026                 : 
    3027                 :     // if only breaks, delete them
    3028               0 :     if (bOnlyBreaks)
    3029                 :     {
    3030               0 :       for (j=0; j<(PRInt32)listCount; j++)
    3031                 :       {
    3032               0 :         res = mHTMLEditor->DeleteNode(arrayOfNodes[j]);
    3033               0 :         NS_ENSURE_SUCCESS(res, res);
    3034                 :       }
    3035                 :     }
    3036                 :     
    3037                 :     // get selection location
    3038               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    3039               0 :     NS_ENSURE_SUCCESS(res, res);
    3040                 :     
    3041                 :     // make sure we can put a list here
    3042               0 :     if (!mHTMLEditor->CanContainTag(parent, *aListType)) {
    3043               0 :       *aCancel = true;
    3044               0 :       return NS_OK;
    3045                 :     }
    3046               0 :     res = SplitAsNeeded(aListType, address_of(parent), &offset);
    3047               0 :     NS_ENSURE_SUCCESS(res, res);
    3048               0 :     res = mHTMLEditor->CreateNode(*aListType, parent, offset, getter_AddRefs(theList));
    3049               0 :     NS_ENSURE_SUCCESS(res, res);
    3050               0 :     res = mHTMLEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
    3051               0 :     NS_ENSURE_SUCCESS(res, res);
    3052                 :     // remember our new block for postprocessing
    3053               0 :     mNewBlock = theListItem;
    3054                 :     // put selection in new list item
    3055               0 :     res = aSelection->Collapse(theListItem,0);
    3056               0 :     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    3057               0 :     *aHandled = true;
    3058               0 :     return res;
    3059                 :   }
    3060                 : 
    3061                 :   // if there is only one node in the array, and it is a list, div, or blockquote,
    3062                 :   // then look inside of it until we find inner list or content.
    3063                 : 
    3064               0 :   res = LookInsideDivBQandList(arrayOfNodes);
    3065               0 :   NS_ENSURE_SUCCESS(res, res);                                 
    3066                 : 
    3067                 :   // Ok, now go through all the nodes and put then in the list, 
    3068                 :   // or whatever is approriate.  Wohoo!
    3069                 : 
    3070               0 :   listCount = arrayOfNodes.Count();
    3071               0 :   nsCOMPtr<nsIDOMNode> curParent;
    3072               0 :   nsCOMPtr<nsIDOMNode> curList;
    3073               0 :   nsCOMPtr<nsIDOMNode> prevListItem;
    3074                 :   
    3075                 :   PRInt32 i;
    3076               0 :   for (i=0; i<listCount; i++)
    3077                 :   {
    3078                 :     // here's where we actually figure out what to do
    3079               0 :     nsCOMPtr<nsIDOMNode> newBlock;
    3080               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    3081                 :     PRInt32 offset;
    3082               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    3083               0 :     NS_ENSURE_SUCCESS(res, res);
    3084                 :   
    3085                 :     // make sure we don't assemble content that is in different table cells into the same list.
    3086                 :     // respect table cell boundaries when listifying.
    3087               0 :     if (curList)
    3088                 :     {
    3089                 :       bool bInDifTblElems;
    3090               0 :       res = InDifferentTableElements(curList, curNode, &bInDifTblElems);
    3091               0 :       NS_ENSURE_SUCCESS(res, res);
    3092               0 :       if (bInDifTblElems)
    3093               0 :         curList = nsnull;
    3094                 :     }
    3095                 :     
    3096                 :     // if curNode is a Break, delete it, and quit remembering prev list item
    3097               0 :     if (nsTextEditUtils::IsBreak(curNode)) 
    3098                 :     {
    3099               0 :       res = mHTMLEditor->DeleteNode(curNode);
    3100               0 :       NS_ENSURE_SUCCESS(res, res);
    3101               0 :       prevListItem = 0;
    3102               0 :       continue;
    3103                 :     }
    3104                 :     // if curNode is an empty inline container, delete it
    3105               0 :     else if (IsEmptyInline(curNode)) 
    3106                 :     {
    3107               0 :       res = mHTMLEditor->DeleteNode(curNode);
    3108               0 :       NS_ENSURE_SUCCESS(res, res);
    3109               0 :       continue;
    3110                 :     }
    3111                 :     
    3112               0 :     if (nsHTMLEditUtils::IsList(curNode))
    3113                 :     {
    3114               0 :       nsAutoString existingListStr;
    3115               0 :       res = mHTMLEditor->GetTagString(curNode, existingListStr);
    3116               0 :       ToLowerCase(existingListStr);
    3117                 :       // do we have a curList already?
    3118               0 :       if (curList && !nsEditorUtils::IsDescendantOf(curNode, curList))
    3119                 :       {
    3120                 :         // move all of our children into curList.
    3121                 :         // cheezy way to do it: move whole list and then
    3122                 :         // RemoveContainer() on the list.
    3123                 :         // ConvertListType first: that routine
    3124                 :         // handles converting the list item types, if needed
    3125               0 :         res = mHTMLEditor->MoveNode(curNode, curList, -1);
    3126               0 :         NS_ENSURE_SUCCESS(res, res);
    3127               0 :         res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
    3128               0 :         NS_ENSURE_SUCCESS(res, res);
    3129               0 :         res = mHTMLEditor->RemoveBlockContainer(newBlock);
    3130               0 :         NS_ENSURE_SUCCESS(res, res);
    3131                 :       }
    3132                 :       else
    3133                 :       {
    3134                 :         // replace list with new list type
    3135               0 :         res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
    3136               0 :         NS_ENSURE_SUCCESS(res, res);
    3137               0 :         curList = newBlock;
    3138                 :       }
    3139               0 :       prevListItem = 0;
    3140               0 :       continue;
    3141                 :     }
    3142                 : 
    3143               0 :     if (nsHTMLEditUtils::IsListItem(curNode))
    3144                 :     {
    3145               0 :       nsAutoString existingListStr;
    3146               0 :       res = mHTMLEditor->GetTagString(curParent, existingListStr);
    3147               0 :       ToLowerCase(existingListStr);
    3148               0 :       if ( existingListStr != *aListType )
    3149                 :       {
    3150                 :         // list item is in wrong type of list.  
    3151                 :         // if we don't have a curList, split the old list
    3152                 :         // and make a new list of correct type.
    3153               0 :         if (!curList || nsEditorUtils::IsDescendantOf(curNode, curList))
    3154                 :         {
    3155               0 :           res = mHTMLEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
    3156               0 :           NS_ENSURE_SUCCESS(res, res);
    3157               0 :           nsCOMPtr<nsIDOMNode> p;
    3158                 :           PRInt32 o;
    3159               0 :           res = nsEditor::GetNodeLocation(curParent, address_of(p), &o);
    3160               0 :           NS_ENSURE_SUCCESS(res, res);
    3161               0 :           res = mHTMLEditor->CreateNode(*aListType, p, o, getter_AddRefs(curList));
    3162               0 :           NS_ENSURE_SUCCESS(res, res);
    3163                 :         }
    3164                 :         // move list item to new list
    3165               0 :         res = mHTMLEditor->MoveNode(curNode, curList, -1);
    3166               0 :         NS_ENSURE_SUCCESS(res, res);
    3167                 :         // convert list item type if needed
    3168               0 :         if (!mHTMLEditor->NodeIsTypeString(curNode,itemType))
    3169                 :         {
    3170               0 :           res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
    3171               0 :           NS_ENSURE_SUCCESS(res, res);
    3172                 :         }
    3173                 :       }
    3174                 :       else
    3175                 :       {
    3176                 :         // item is in right type of list.  But we might still have to move it.
    3177                 :         // and we might need to convert list item types.
    3178               0 :         if (!curList)
    3179               0 :           curList = curParent;
    3180                 :         else
    3181                 :         {
    3182               0 :           if (curParent != curList)
    3183                 :           {
    3184                 :             // move list item to new list
    3185               0 :             res = mHTMLEditor->MoveNode(curNode, curList, -1);
    3186               0 :             NS_ENSURE_SUCCESS(res, res);
    3187                 :           }
    3188                 :         }
    3189               0 :         if (!mHTMLEditor->NodeIsTypeString(curNode,itemType))
    3190                 :         {
    3191               0 :           res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
    3192               0 :           NS_ENSURE_SUCCESS(res, res);
    3193                 :         }
    3194                 :       }
    3195               0 :       nsCOMPtr<nsIDOMElement> curElement = do_QueryInterface(curNode);
    3196               0 :       NS_NAMED_LITERAL_STRING(typestr, "type");
    3197               0 :       if (aBulletType && !aBulletType->IsEmpty()) {
    3198               0 :         res = mHTMLEditor->SetAttribute(curElement, typestr, *aBulletType);
    3199                 :       }
    3200                 :       else {
    3201               0 :         res = mHTMLEditor->RemoveAttribute(curElement, typestr);
    3202                 :       }
    3203               0 :       NS_ENSURE_SUCCESS(res, res);
    3204               0 :       continue;
    3205                 :     }
    3206                 :     
    3207                 :     // if we hit a div clear our prevListItem, insert divs contents
    3208                 :     // into our node array, and remove the div
    3209               0 :     if (nsHTMLEditUtils::IsDiv(curNode))
    3210                 :     {
    3211               0 :       prevListItem = nsnull;
    3212               0 :       PRInt32 j=i+1;
    3213               0 :       res = GetInnerContent(curNode, arrayOfNodes, &j);
    3214               0 :       NS_ENSURE_SUCCESS(res, res);
    3215               0 :       res = mHTMLEditor->RemoveContainer(curNode);
    3216               0 :       NS_ENSURE_SUCCESS(res, res);
    3217               0 :       listCount = arrayOfNodes.Count();
    3218               0 :       continue;
    3219                 :     }
    3220                 :       
    3221                 :     // need to make a list to put things in if we haven't already,
    3222               0 :     if (!curList)
    3223                 :     {
    3224               0 :       res = SplitAsNeeded(aListType, address_of(curParent), &offset);
    3225               0 :       NS_ENSURE_SUCCESS(res, res);
    3226               0 :       res = mHTMLEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
    3227               0 :       NS_ENSURE_SUCCESS(res, res);
    3228                 :       // remember our new block for postprocessing
    3229               0 :       mNewBlock = curList;
    3230                 :       // curList is now the correct thing to put curNode in
    3231               0 :       prevListItem = 0;
    3232                 :     }
    3233                 :   
    3234                 :     // if curNode isn't a list item, we must wrap it in one
    3235               0 :     nsCOMPtr<nsIDOMNode> listItem;
    3236               0 :     if (!nsHTMLEditUtils::IsListItem(curNode))
    3237                 :     {
    3238               0 :       if (IsInlineNode(curNode) && prevListItem)
    3239                 :       {
    3240                 :         // this is a continuation of some inline nodes that belong together in
    3241                 :         // the same list item.  use prevListItem
    3242               0 :         res = mHTMLEditor->MoveNode(curNode, prevListItem, -1);
    3243               0 :         NS_ENSURE_SUCCESS(res, res);
    3244                 :       }
    3245                 :       else
    3246                 :       {
    3247                 :         // don't wrap li around a paragraph.  instead replace paragraph with li
    3248               0 :         if (nsHTMLEditUtils::IsParagraph(curNode))
    3249                 :         {
    3250               0 :           res = mHTMLEditor->ReplaceContainer(curNode, address_of(listItem), itemType);
    3251                 :         }
    3252                 :         else
    3253                 :         {
    3254               0 :           res = mHTMLEditor->InsertContainerAbove(curNode, address_of(listItem), itemType);
    3255                 :         }
    3256               0 :         NS_ENSURE_SUCCESS(res, res);
    3257               0 :         if (IsInlineNode(curNode)) 
    3258               0 :           prevListItem = listItem;
    3259                 :         else
    3260               0 :           prevListItem = nsnull;
    3261                 :       }
    3262                 :     }
    3263                 :     else
    3264                 :     {
    3265               0 :       listItem = curNode;
    3266                 :     }
    3267                 :   
    3268               0 :     if (listItem)  // if we made a new list item, deal with it
    3269                 :     {
    3270                 :       // tuck the listItem into the end of the active list
    3271               0 :       res = mHTMLEditor->MoveNode(listItem, curList, -1);
    3272               0 :       NS_ENSURE_SUCCESS(res, res);
    3273                 :     }
    3274                 :   }
    3275                 : 
    3276               0 :   return res;
    3277                 : }
    3278                 : 
    3279                 : 
    3280                 : nsresult
    3281               0 : nsHTMLEditRules::WillRemoveList(nsISelection *aSelection, 
    3282                 :                                 bool aOrdered, 
    3283                 :                                 bool *aCancel,
    3284                 :                                 bool *aHandled)
    3285                 : {
    3286               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    3287                 :   // initialize out param
    3288               0 :   *aCancel = false;
    3289               0 :   *aHandled = true;
    3290                 :   
    3291               0 :   nsresult res = NormalizeSelection(aSelection);
    3292               0 :   NS_ENSURE_SUCCESS(res, res);
    3293               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3294                 :   
    3295               0 :   nsCOMArray<nsIDOMRange> arrayOfRanges;
    3296               0 :   res = GetPromotedRanges(aSelection, arrayOfRanges, kMakeList);
    3297               0 :   NS_ENSURE_SUCCESS(res, res);
    3298                 :   
    3299                 :   // use these ranges to contruct a list of nodes to act on.
    3300               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    3301               0 :   res = GetListActionNodes(arrayOfNodes, false);
    3302               0 :   NS_ENSURE_SUCCESS(res, res);                                 
    3303                 :                                      
    3304                 :   // Remove all non-editable nodes.  Leave them be.
    3305               0 :   PRInt32 listCount = arrayOfNodes.Count();
    3306                 :   PRInt32 i;
    3307               0 :   for (i=listCount-1; i>=0; i--)
    3308                 :   {
    3309               0 :     nsIDOMNode* testNode = arrayOfNodes[i];
    3310               0 :     if (!mHTMLEditor->IsEditable(testNode))
    3311                 :     {
    3312               0 :       arrayOfNodes.RemoveObjectAt(i);
    3313                 :     }
    3314                 :   }
    3315                 :   
    3316                 :   // reset list count
    3317               0 :   listCount = arrayOfNodes.Count();
    3318                 :   
    3319                 :   // Only act on lists or list items in the array
    3320               0 :   nsCOMPtr<nsIDOMNode> curParent;
    3321               0 :   for (i=0; i<listCount; i++)
    3322                 :   {
    3323                 :     // here's where we actually figure out what to do
    3324               0 :     nsIDOMNode* curNode = arrayOfNodes[i];
    3325                 :     PRInt32 offset;
    3326               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    3327               0 :     NS_ENSURE_SUCCESS(res, res);
    3328                 :     
    3329               0 :     if (nsHTMLEditUtils::IsListItem(curNode))  // unlist this listitem
    3330                 :     {
    3331                 :       bool bOutOfList;
    3332               0 :       do
    3333                 :       {
    3334               0 :         res = PopListItem(curNode, &bOutOfList);
    3335               0 :         NS_ENSURE_SUCCESS(res, res);
    3336               0 :       } while (!bOutOfList); // keep popping it out until it's not in a list anymore
    3337                 :     }
    3338               0 :     else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, move list items out
    3339                 :     {
    3340               0 :       res = RemoveListStructure(curNode);
    3341               0 :       NS_ENSURE_SUCCESS(res, res);
    3342                 :     }
    3343                 :   }
    3344               0 :   return res;
    3345                 : }
    3346                 : 
    3347                 : 
    3348                 : nsresult
    3349               0 : nsHTMLEditRules::WillMakeDefListItem(nsISelection *aSelection, 
    3350                 :                                      const nsAString *aItemType, 
    3351                 :                                      bool aEntireList, 
    3352                 :                                      bool *aCancel,
    3353                 :                                      bool *aHandled)
    3354                 : {
    3355                 :   // for now we let WillMakeList handle this
    3356               0 :   NS_NAMED_LITERAL_STRING(listType, "dl");
    3357               0 :   return WillMakeList(aSelection, &listType, aEntireList, nsnull, aCancel, aHandled, aItemType);
    3358                 : }
    3359                 : 
    3360                 : nsresult
    3361               0 : nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection, 
    3362                 :                                     const nsAString *aBlockType, 
    3363                 :                                     bool *aCancel,
    3364                 :                                     bool *aHandled)
    3365                 : {
    3366               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    3367                 :   // initialize out param
    3368               0 :   *aCancel = false;
    3369               0 :   *aHandled = false;
    3370                 :   
    3371               0 :   nsresult res = WillInsert(aSelection, aCancel);
    3372               0 :   NS_ENSURE_SUCCESS(res, res);
    3373                 :   // initialize out param
    3374                 :   // we want to ignore result of WillInsert()
    3375               0 :   *aCancel = false;
    3376               0 :   res = NormalizeSelection(aSelection);
    3377               0 :   NS_ENSURE_SUCCESS(res, res);
    3378               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3379               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    3380               0 :   *aHandled = true;
    3381               0 :   nsString tString(*aBlockType);
    3382                 : 
    3383                 :   // contruct a list of nodes to act on.
    3384               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    3385               0 :   res = GetNodesFromSelection(aSelection, kMakeBasicBlock, arrayOfNodes);
    3386               0 :   NS_ENSURE_SUCCESS(res, res);
    3387                 : 
    3388                 :   // Remove all non-editable nodes.  Leave them be.
    3389               0 :   PRInt32 listCount = arrayOfNodes.Count();
    3390                 :   PRInt32 i;
    3391               0 :   for (i=listCount-1; i>=0; i--)
    3392                 :   {
    3393               0 :     if (!mHTMLEditor->IsEditable(arrayOfNodes[i]))
    3394                 :     {
    3395               0 :       arrayOfNodes.RemoveObjectAt(i);
    3396                 :     }
    3397                 :   }
    3398                 :   
    3399                 :   // reset list count
    3400               0 :   listCount = arrayOfNodes.Count();
    3401                 :   
    3402                 :   // if nothing visible in list, make an empty block
    3403               0 :   if (ListIsEmptyLine(arrayOfNodes))
    3404                 :   {
    3405               0 :     nsCOMPtr<nsIDOMNode> parent, theBlock;
    3406                 :     PRInt32 offset;
    3407                 :     
    3408                 :     // get selection location
    3409               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    3410               0 :     NS_ENSURE_SUCCESS(res, res);
    3411               0 :     if (tString.EqualsLiteral("normal") ||
    3412               0 :         tString.IsEmpty() ) // we are removing blocks (going to "body text")
    3413                 :     {
    3414               0 :       nsCOMPtr<nsIDOMNode> curBlock = parent;
    3415               0 :       if (!IsBlockNode(curBlock))
    3416               0 :         curBlock = mHTMLEditor->GetBlockNodeParent(parent);
    3417               0 :       nsCOMPtr<nsIDOMNode> curBlockPar;
    3418               0 :       NS_ENSURE_TRUE(curBlock, NS_ERROR_NULL_POINTER);
    3419               0 :       curBlock->GetParentNode(getter_AddRefs(curBlockPar));
    3420               0 :       if (nsHTMLEditUtils::IsFormatNode(curBlock))
    3421                 :       {
    3422                 :         // if the first editable node after selection is a br, consume it.  Otherwise
    3423                 :         // it gets pushed into a following block after the split, which is visually bad.
    3424               0 :         nsCOMPtr<nsIDOMNode> brNode;
    3425               0 :         res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode));
    3426               0 :         NS_ENSURE_SUCCESS(res, res);        
    3427               0 :         if (brNode && nsTextEditUtils::IsBreak(brNode))
    3428                 :         {
    3429               0 :           res = mHTMLEditor->DeleteNode(brNode);
    3430               0 :           NS_ENSURE_SUCCESS(res, res); 
    3431                 :         }
    3432                 :         // do the splits!
    3433               0 :         res = mHTMLEditor->SplitNodeDeep(curBlock, parent, offset, &offset, true);
    3434               0 :         NS_ENSURE_SUCCESS(res, res);
    3435                 :         // put a br at the split point
    3436               0 :         res = mHTMLEditor->CreateBR(curBlockPar, offset, address_of(brNode));
    3437               0 :         NS_ENSURE_SUCCESS(res, res);
    3438                 :         // put selection at the split point
    3439               0 :         res = aSelection->Collapse(curBlockPar, offset);
    3440               0 :         selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    3441               0 :         *aHandled = true;
    3442                 :       }
    3443                 :       // else nothing to do!
    3444                 :     }
    3445                 :     else  // we are making a block
    3446                 :     {   
    3447                 :       // consume a br, if needed
    3448               0 :       nsCOMPtr<nsIDOMNode> brNode;
    3449               0 :       res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode), true);
    3450               0 :       NS_ENSURE_SUCCESS(res, res);
    3451               0 :       if (brNode && nsTextEditUtils::IsBreak(brNode))
    3452                 :       {
    3453               0 :         res = mHTMLEditor->DeleteNode(brNode);
    3454               0 :         NS_ENSURE_SUCCESS(res, res);
    3455                 :         // we don't need to act on this node any more
    3456               0 :         arrayOfNodes.RemoveObject(brNode);
    3457                 :       }
    3458                 :       // make sure we can put a block here
    3459               0 :       res = SplitAsNeeded(aBlockType, address_of(parent), &offset);
    3460               0 :       NS_ENSURE_SUCCESS(res, res);
    3461               0 :       res = mHTMLEditor->CreateNode(*aBlockType, parent, offset, getter_AddRefs(theBlock));
    3462               0 :       NS_ENSURE_SUCCESS(res, res);
    3463                 :       // remember our new block for postprocessing
    3464               0 :       mNewBlock = theBlock;
    3465                 :       // delete anything that was in the list of nodes
    3466               0 :       for (PRInt32 j = arrayOfNodes.Count() - 1; j >= 0; --j) 
    3467                 :       {
    3468               0 :         nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
    3469               0 :         res = mHTMLEditor->DeleteNode(curNode);
    3470               0 :         NS_ENSURE_SUCCESS(res, res);
    3471               0 :         res = arrayOfNodes.RemoveObjectAt(0);
    3472               0 :         NS_ENSURE_SUCCESS(res, res);
    3473                 :       }
    3474                 :       // put selection in new block
    3475               0 :       res = aSelection->Collapse(theBlock,0);
    3476               0 :       selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    3477               0 :       *aHandled = true;
    3478                 :     }
    3479               0 :     return res;    
    3480                 :   }
    3481                 :   else
    3482                 :   {
    3483                 :     // Ok, now go through all the nodes and make the right kind of blocks, 
    3484                 :     // or whatever is approriate.  Wohoo! 
    3485                 :     // Note: blockquote is handled a little differently
    3486               0 :     if (tString.EqualsLiteral("blockquote"))
    3487               0 :       res = MakeBlockquote(arrayOfNodes);
    3488               0 :     else if (tString.EqualsLiteral("normal") ||
    3489               0 :              tString.IsEmpty() )
    3490               0 :       res = RemoveBlockStyle(arrayOfNodes);
    3491                 :     else
    3492               0 :       res = ApplyBlockStyle(arrayOfNodes, aBlockType);
    3493               0 :     return res;
    3494                 :   }
    3495                 :   return res;
    3496                 : }
    3497                 : 
    3498                 : nsresult 
    3499               0 : nsHTMLEditRules::DidMakeBasicBlock(nsISelection *aSelection,
    3500                 :                                    nsRulesInfo *aInfo, nsresult aResult)
    3501                 : {
    3502               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    3503                 :   // check for empty block.  if so, put a moz br in it.
    3504                 :   bool isCollapsed;
    3505               0 :   nsresult res = aSelection->GetIsCollapsed(&isCollapsed);
    3506               0 :   NS_ENSURE_SUCCESS(res, res);
    3507               0 :   if (!isCollapsed) {
    3508               0 :     return NS_OK;
    3509                 :   }
    3510                 : 
    3511               0 :   nsCOMPtr<nsIDOMNode> parent;
    3512                 :   PRInt32 offset;
    3513               0 :   res = nsEditor::GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    3514               0 :   NS_ENSURE_SUCCESS(res, res);
    3515               0 :   res = InsertMozBRIfNeeded(parent);
    3516               0 :   return res;
    3517                 : }
    3518                 : 
    3519                 : nsresult
    3520               0 : nsHTMLEditRules::WillIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
    3521                 : {
    3522                 :   nsresult res;
    3523               0 :   if (mHTMLEditor->IsCSSEnabled()) {
    3524               0 :     res = WillCSSIndent(aSelection, aCancel, aHandled);
    3525                 :   }
    3526                 :   else {
    3527               0 :     res = WillHTMLIndent(aSelection, aCancel, aHandled);
    3528                 :   }
    3529               0 :   return res;
    3530                 : }
    3531                 : 
    3532                 : nsresult
    3533               0 : nsHTMLEditRules::WillCSSIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
    3534                 : {
    3535               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    3536                 :   
    3537               0 :   nsresult res = WillInsert(aSelection, aCancel);
    3538               0 :   NS_ENSURE_SUCCESS(res, res);
    3539                 : 
    3540                 :   // initialize out param
    3541                 :   // we want to ignore result of WillInsert()
    3542               0 :   *aCancel = false;
    3543               0 :   *aHandled = true;
    3544                 : 
    3545               0 :   res = NormalizeSelection(aSelection);
    3546               0 :   NS_ENSURE_SUCCESS(res, res);
    3547               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3548               0 :   nsCOMArray<nsIDOMRange>  arrayOfRanges;
    3549               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    3550                 :   
    3551                 :   // short circuit: detect case of collapsed selection inside an <li>.
    3552                 :   // just sublist that <li>.  This prevents bug 97797.
    3553                 :   
    3554                 :   bool bCollapsed;
    3555               0 :   nsCOMPtr<nsIDOMNode> liNode;
    3556               0 :   res = aSelection->GetIsCollapsed(&bCollapsed);
    3557               0 :   NS_ENSURE_SUCCESS(res, res);
    3558               0 :   if (bCollapsed) 
    3559                 :   {
    3560               0 :     nsCOMPtr<nsIDOMNode> node, block;
    3561                 :     PRInt32 offset;
    3562               0 :     nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
    3563               0 :     NS_ENSURE_SUCCESS(res, res);
    3564               0 :     if (IsBlockNode(node)) 
    3565               0 :       block = node;
    3566                 :     else
    3567               0 :       block = mHTMLEditor->GetBlockNodeParent(node);
    3568               0 :     if (block && nsHTMLEditUtils::IsListItem(block))
    3569               0 :       liNode = block;
    3570                 :   }
    3571                 :   
    3572               0 :   if (liNode)
    3573                 :   {
    3574               0 :     arrayOfNodes.AppendObject(liNode);
    3575                 :   }
    3576                 :   else
    3577                 :   {
    3578                 :     // convert the selection ranges into "promoted" selection ranges:
    3579                 :     // this basically just expands the range to include the immediate
    3580                 :     // block parent, and then further expands to include any ancestors
    3581                 :     // whose children are all in the range
    3582               0 :     res = GetNodesFromSelection(aSelection, kIndent, arrayOfNodes);
    3583               0 :     NS_ENSURE_SUCCESS(res, res);
    3584                 :   }
    3585                 :   
    3586               0 :   NS_NAMED_LITERAL_STRING(quoteType, "blockquote");
    3587                 :   // if nothing visible in list, make an empty block
    3588               0 :   if (ListIsEmptyLine(arrayOfNodes))
    3589                 :   {
    3590               0 :     nsCOMPtr<nsIDOMNode> parent, theBlock;
    3591                 :     PRInt32 offset;
    3592               0 :     nsAutoString quoteType(NS_LITERAL_STRING("div"));
    3593                 :     // get selection location
    3594               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    3595               0 :     NS_ENSURE_SUCCESS(res, res);
    3596                 :     // make sure we can put a block here
    3597               0 :     res = SplitAsNeeded(&quoteType, address_of(parent), &offset);
    3598               0 :     NS_ENSURE_SUCCESS(res, res);
    3599               0 :     res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock));
    3600               0 :     NS_ENSURE_SUCCESS(res, res);
    3601                 :     // remember our new block for postprocessing
    3602               0 :     mNewBlock = theBlock;
    3603               0 :     RelativeChangeIndentationOfElementNode(theBlock, +1);
    3604                 :     // delete anything that was in the list of nodes
    3605               0 :     for (PRInt32 j = arrayOfNodes.Count() - 1; j >= 0; --j) 
    3606                 :     {
    3607               0 :       nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
    3608               0 :       res = mHTMLEditor->DeleteNode(curNode);
    3609               0 :       NS_ENSURE_SUCCESS(res, res);
    3610               0 :       res = arrayOfNodes.RemoveObjectAt(0);
    3611               0 :       NS_ENSURE_SUCCESS(res, res);
    3612                 :     }
    3613                 :     // put selection in new block
    3614               0 :     res = aSelection->Collapse(theBlock,0);
    3615               0 :     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    3616               0 :     *aHandled = true;
    3617               0 :     return res;
    3618                 :   }
    3619                 :   
    3620                 :   // Ok, now go through all the nodes and put them in a blockquote, 
    3621                 :   // or whatever is appropriate.  Wohoo!
    3622                 :   PRInt32 i;
    3623               0 :   nsCOMPtr<nsIDOMNode> curParent;
    3624               0 :   nsCOMPtr<nsIDOMNode> curQuote;
    3625               0 :   nsCOMPtr<nsIDOMNode> curList;
    3626               0 :   nsCOMPtr<nsIDOMNode> sibling;
    3627               0 :   PRInt32 listCount = arrayOfNodes.Count();
    3628               0 :   for (i=0; i<listCount; i++)
    3629                 :   {
    3630                 :     // here's where we actually figure out what to do
    3631               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    3632                 : 
    3633                 :     // Ignore all non-editable nodes.  Leave them be.
    3634               0 :     if (!mHTMLEditor->IsEditable(curNode)) continue;
    3635                 : 
    3636                 :     PRInt32 offset;
    3637               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    3638               0 :     NS_ENSURE_SUCCESS(res, res);
    3639                 :     
    3640                 :     // some logic for putting list items into nested lists...
    3641               0 :     if (nsHTMLEditUtils::IsList(curParent))
    3642                 :     {
    3643               0 :       sibling = nsnull;
    3644                 : 
    3645                 :       // Check for whether we should join a list that follows curNode.
    3646                 :       // We do this if the next element is a list, and the list is of the
    3647                 :       // same type (li/ol) as curNode was a part it.
    3648               0 :       mHTMLEditor->GetNextHTMLSibling(curNode, address_of(sibling));
    3649               0 :       if (sibling && nsHTMLEditUtils::IsList(sibling))
    3650                 :       {
    3651               0 :         nsAutoString curListTag, siblingListTag;
    3652               0 :         nsEditor::GetTagString(curParent, curListTag);
    3653               0 :         nsEditor::GetTagString(sibling, siblingListTag);
    3654               0 :         if (curListTag == siblingListTag)
    3655                 :         {
    3656               0 :           res = mHTMLEditor->MoveNode(curNode, sibling, 0);
    3657               0 :           NS_ENSURE_SUCCESS(res, res);
    3658               0 :           continue;
    3659                 :         }
    3660                 :       }
    3661                 :       // Check for whether we should join a list that preceeds curNode.
    3662                 :       // We do this if the previous element is a list, and the list is of
    3663                 :       // the same type (li/ol) as curNode was a part of.
    3664               0 :       mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    3665               0 :       if (sibling && nsHTMLEditUtils::IsList(sibling))
    3666                 :       {
    3667               0 :         nsAutoString curListTag, siblingListTag;
    3668               0 :         nsEditor::GetTagString(curParent, curListTag);
    3669               0 :         nsEditor::GetTagString(sibling, siblingListTag);
    3670               0 :         if (curListTag == siblingListTag)
    3671                 :         {
    3672               0 :           res = mHTMLEditor->MoveNode(curNode, sibling, -1);
    3673               0 :           NS_ENSURE_SUCCESS(res, res);
    3674               0 :           continue;
    3675                 :         }
    3676                 :       }
    3677               0 :       sibling = nsnull;
    3678                 :       
    3679                 :       // check to see if curList is still appropriate.  Which it is if
    3680                 :       // curNode is still right after it in the same list.
    3681               0 :       if (curList)
    3682               0 :         mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    3683                 : 
    3684               0 :       if (!curList || (sibling && sibling != curList))
    3685                 :       {
    3686               0 :         nsAutoString listTag;
    3687               0 :         nsEditor::GetTagString(curParent,listTag);
    3688               0 :         ToLowerCase(listTag);
    3689                 :         // create a new nested list of correct type
    3690               0 :         res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
    3691               0 :         NS_ENSURE_SUCCESS(res, res);
    3692               0 :         res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
    3693               0 :         NS_ENSURE_SUCCESS(res, res);
    3694                 :         // curList is now the correct thing to put curNode in
    3695                 :         // remember our new block for postprocessing
    3696               0 :         mNewBlock = curList;
    3697                 :       }
    3698                 :       // tuck the node into the end of the active list
    3699                 :       PRUint32 listLen;
    3700               0 :       res = mHTMLEditor->GetLengthOfDOMNode(curList, listLen);
    3701               0 :       NS_ENSURE_SUCCESS(res, res);
    3702               0 :       res = mHTMLEditor->MoveNode(curNode, curList, listLen);
    3703               0 :       NS_ENSURE_SUCCESS(res, res);
    3704                 :     }
    3705                 :     
    3706                 :     else // not a list item
    3707                 :     {
    3708               0 :       if (IsBlockNode(curNode)) {
    3709               0 :         RelativeChangeIndentationOfElementNode(curNode, +1);
    3710               0 :         curQuote = nsnull;
    3711                 :       }
    3712                 :       else {
    3713               0 :         if (!curQuote)
    3714                 :         {
    3715                 :           // First, check that our element can contain a div.
    3716               0 :           NS_NAMED_LITERAL_STRING(divquoteType, "div");
    3717               0 :           if (!mEditor->CanContainTag(curParent, divquoteType))
    3718               0 :             return NS_OK; // cancelled
    3719                 : 
    3720               0 :           res = SplitAsNeeded(&divquoteType, address_of(curParent), &offset);
    3721               0 :           NS_ENSURE_SUCCESS(res, res);
    3722               0 :           res = mHTMLEditor->CreateNode(divquoteType, curParent, offset, getter_AddRefs(curQuote));
    3723               0 :           NS_ENSURE_SUCCESS(res, res);
    3724               0 :           RelativeChangeIndentationOfElementNode(curQuote, +1);
    3725                 :           // remember our new block for postprocessing
    3726               0 :           mNewBlock = curQuote;
    3727                 :           // curQuote is now the correct thing to put curNode in
    3728                 :         }
    3729                 :         
    3730                 :         // tuck the node into the end of the active blockquote
    3731                 :         PRUint32 quoteLen;
    3732               0 :         res = mHTMLEditor->GetLengthOfDOMNode(curQuote, quoteLen);
    3733               0 :         NS_ENSURE_SUCCESS(res, res);
    3734               0 :         res = mHTMLEditor->MoveNode(curNode, curQuote, quoteLen);
    3735               0 :         NS_ENSURE_SUCCESS(res, res);
    3736                 :       }
    3737                 :     }
    3738                 :   }
    3739               0 :   return res;
    3740                 : }
    3741                 : 
    3742                 : nsresult
    3743               0 : nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
    3744                 : {
    3745               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    3746               0 :   nsresult res = WillInsert(aSelection, aCancel);
    3747               0 :   NS_ENSURE_SUCCESS(res, res);
    3748                 : 
    3749                 :   // initialize out param
    3750                 :   // we want to ignore result of WillInsert()
    3751               0 :   *aCancel = false;
    3752               0 :   *aHandled = true;
    3753                 : 
    3754               0 :   res = NormalizeSelection(aSelection);
    3755               0 :   NS_ENSURE_SUCCESS(res, res);
    3756               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3757                 :   
    3758                 :   // convert the selection ranges into "promoted" selection ranges:
    3759                 :   // this basically just expands the range to include the immediate
    3760                 :   // block parent, and then further expands to include any ancestors
    3761                 :   // whose children are all in the range
    3762                 :   
    3763               0 :   nsCOMArray<nsIDOMRange> arrayOfRanges;
    3764               0 :   res = GetPromotedRanges(aSelection, arrayOfRanges, kIndent);
    3765               0 :   NS_ENSURE_SUCCESS(res, res);
    3766                 :   
    3767                 :   // use these ranges to contruct a list of nodes to act on.
    3768               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    3769               0 :   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, kIndent);
    3770               0 :   NS_ENSURE_SUCCESS(res, res);                                 
    3771                 :                                      
    3772               0 :   NS_NAMED_LITERAL_STRING(quoteType, "blockquote");
    3773                 : 
    3774                 :   // if nothing visible in list, make an empty block
    3775               0 :   if (ListIsEmptyLine(arrayOfNodes))
    3776                 :   {
    3777               0 :     nsCOMPtr<nsIDOMNode> parent, theBlock;
    3778                 :     PRInt32 offset;
    3779                 :     
    3780                 :     // get selection location
    3781               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    3782               0 :     NS_ENSURE_SUCCESS(res, res);
    3783                 :     // make sure we can put a block here
    3784               0 :     res = SplitAsNeeded(&quoteType, address_of(parent), &offset);
    3785               0 :     NS_ENSURE_SUCCESS(res, res);
    3786               0 :     res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock));
    3787               0 :     NS_ENSURE_SUCCESS(res, res);
    3788                 :     // remember our new block for postprocessing
    3789               0 :     mNewBlock = theBlock;
    3790                 :     // delete anything that was in the list of nodes
    3791               0 :     for (PRInt32 j = arrayOfNodes.Count() - 1; j >= 0; --j) 
    3792                 :     {
    3793               0 :       nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
    3794               0 :       res = mHTMLEditor->DeleteNode(curNode);
    3795               0 :       NS_ENSURE_SUCCESS(res, res);
    3796               0 :       res = arrayOfNodes.RemoveObjectAt(0);
    3797               0 :       NS_ENSURE_SUCCESS(res, res);
    3798                 :     }
    3799                 :     // put selection in new block
    3800               0 :     res = aSelection->Collapse(theBlock,0);
    3801               0 :     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    3802               0 :     *aHandled = true;
    3803               0 :     return res;
    3804                 :   }
    3805                 : 
    3806                 :   // Ok, now go through all the nodes and put them in a blockquote, 
    3807                 :   // or whatever is appropriate.  Wohoo!
    3808                 :   PRInt32 i;
    3809               0 :   nsCOMPtr<nsIDOMNode> curParent, curQuote, curList, indentedLI, sibling;
    3810               0 :   PRInt32 listCount = arrayOfNodes.Count();
    3811               0 :   for (i=0; i<listCount; i++)
    3812                 :   {
    3813                 :     // here's where we actually figure out what to do
    3814               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    3815                 : 
    3816                 :     // Ignore all non-editable nodes.  Leave them be.
    3817               0 :     if (!mHTMLEditor->IsEditable(curNode)) continue;
    3818                 : 
    3819                 :     PRInt32 offset;
    3820               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    3821               0 :     NS_ENSURE_SUCCESS(res, res);
    3822                 :      
    3823                 :     // some logic for putting list items into nested lists...
    3824               0 :     if (nsHTMLEditUtils::IsList(curParent))
    3825                 :     {
    3826               0 :       sibling = nsnull;
    3827                 : 
    3828                 :       // Check for whether we should join a list that follows curNode.
    3829                 :       // We do this if the next element is a list, and the list is of the
    3830                 :       // same type (li/ol) as curNode was a part it.
    3831               0 :       mHTMLEditor->GetNextHTMLSibling(curNode, address_of(sibling));
    3832               0 :       if (sibling && nsHTMLEditUtils::IsList(sibling))
    3833                 :       {
    3834               0 :         nsAutoString curListTag, siblingListTag;
    3835               0 :         nsEditor::GetTagString(curParent, curListTag);
    3836               0 :         nsEditor::GetTagString(sibling, siblingListTag);
    3837               0 :         if (curListTag == siblingListTag)
    3838                 :         {
    3839               0 :           res = mHTMLEditor->MoveNode(curNode, sibling, 0);
    3840               0 :           NS_ENSURE_SUCCESS(res, res);
    3841               0 :           continue;
    3842                 :         }
    3843                 :       }
    3844                 : 
    3845                 :       // Check for whether we should join a list that preceeds curNode.
    3846                 :       // We do this if the previous element is a list, and the list is of
    3847                 :       // the same type (li/ol) as curNode was a part of.
    3848               0 :       mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    3849               0 :       if (sibling && nsHTMLEditUtils::IsList(sibling))
    3850                 :       {
    3851               0 :         nsAutoString curListTag, siblingListTag;
    3852               0 :         nsEditor::GetTagString(curParent, curListTag);
    3853               0 :         nsEditor::GetTagString(sibling, siblingListTag);
    3854               0 :         if (curListTag == siblingListTag)
    3855                 :         {
    3856               0 :           res = mHTMLEditor->MoveNode(curNode, sibling, -1);
    3857               0 :           NS_ENSURE_SUCCESS(res, res);
    3858               0 :           continue;
    3859                 :         }
    3860                 :       }
    3861                 : 
    3862               0 :       sibling = nsnull;
    3863                 : 
    3864                 :       // check to see if curList is still appropriate.  Which it is if
    3865                 :       // curNode is still right after it in the same list.
    3866               0 :       if (curList)
    3867               0 :         mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    3868                 : 
    3869               0 :       if (!curList || (sibling && sibling != curList) )
    3870                 :       {
    3871               0 :         nsAutoString listTag;
    3872               0 :         nsEditor::GetTagString(curParent,listTag);
    3873               0 :         ToLowerCase(listTag);
    3874                 :         // create a new nested list of correct type
    3875               0 :         res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
    3876               0 :         NS_ENSURE_SUCCESS(res, res);
    3877               0 :         res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
    3878               0 :         NS_ENSURE_SUCCESS(res, res);
    3879                 :         // curList is now the correct thing to put curNode in
    3880                 :         // remember our new block for postprocessing
    3881               0 :         mNewBlock = curList;
    3882                 :       }
    3883                 :       // tuck the node into the end of the active list
    3884               0 :       res = mHTMLEditor->MoveNode(curNode, curList, -1);
    3885               0 :       NS_ENSURE_SUCCESS(res, res);
    3886                 :       // forget curQuote, if any
    3887               0 :       curQuote = nsnull;
    3888                 :     }
    3889                 :     
    3890                 :     else // not a list item, use blockquote?
    3891                 :     {
    3892                 :       // if we are inside a list item, we don't want to blockquote, we want
    3893                 :       // to sublist the list item.  We may have several nodes listed in the
    3894                 :       // array of nodes to act on, that are in the same list item.  Since
    3895                 :       // we only want to indent that li once, we must keep track of the most
    3896                 :       // recent indented list item, and not indent it if we find another node
    3897                 :       // to act on that is still inside the same li.
    3898               0 :       nsCOMPtr<nsIDOMNode> listitem=IsInListItem(curNode);
    3899               0 :       if (listitem)
    3900                 :       {
    3901               0 :         if (indentedLI == listitem) continue;  // already indented this list item
    3902               0 :         res = nsEditor::GetNodeLocation(listitem, address_of(curParent), &offset);
    3903               0 :         NS_ENSURE_SUCCESS(res, res);
    3904                 :         // check to see if curList is still appropriate.  Which it is if
    3905                 :         // curNode is still right after it in the same list.
    3906               0 :         if (curList)
    3907                 :         {
    3908               0 :           sibling = nsnull;
    3909               0 :           mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    3910                 :         }
    3911                 :          
    3912               0 :         if (!curList || (sibling && sibling != curList) )
    3913                 :         {
    3914               0 :           nsAutoString listTag;
    3915               0 :           nsEditor::GetTagString(curParent,listTag);
    3916               0 :           ToLowerCase(listTag);
    3917                 :           // create a new nested list of correct type
    3918               0 :           res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
    3919               0 :           NS_ENSURE_SUCCESS(res, res);
    3920               0 :           res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
    3921               0 :           NS_ENSURE_SUCCESS(res, res);
    3922                 :         }
    3923               0 :         res = mHTMLEditor->MoveNode(listitem, curList, -1);
    3924               0 :         NS_ENSURE_SUCCESS(res, res);
    3925                 :         // remember we indented this li
    3926               0 :         indentedLI = listitem;
    3927                 :       }
    3928                 :       
    3929                 :       else
    3930                 :       {
    3931                 :         // need to make a blockquote to put things in if we haven't already,
    3932                 :         // or if this node doesn't go in blockquote we used earlier.
    3933                 :         // One reason it might not go in prio blockquote is if we are now
    3934                 :         // in a different table cell. 
    3935               0 :         if (curQuote)
    3936                 :         {
    3937                 :           bool bInDifTblElems;
    3938               0 :           res = InDifferentTableElements(curQuote, curNode, &bInDifTblElems);
    3939               0 :           NS_ENSURE_SUCCESS(res, res);
    3940               0 :           if (bInDifTblElems)
    3941               0 :             curQuote = nsnull;
    3942                 :         }
    3943                 :         
    3944               0 :         if (!curQuote) 
    3945                 :         {
    3946                 :           // First, check that our element can contain a blockquote.
    3947               0 :           if (!mEditor->CanContainTag(curParent, quoteType))
    3948               0 :             return NS_OK; // cancelled
    3949                 : 
    3950               0 :           res = SplitAsNeeded(&quoteType, address_of(curParent), &offset);
    3951               0 :           NS_ENSURE_SUCCESS(res, res);
    3952               0 :           res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
    3953               0 :           NS_ENSURE_SUCCESS(res, res);
    3954                 :           // remember our new block for postprocessing
    3955               0 :           mNewBlock = curQuote;
    3956                 :           // curQuote is now the correct thing to put curNode in
    3957                 :         }
    3958                 :           
    3959                 :         // tuck the node into the end of the active blockquote
    3960               0 :         res = mHTMLEditor->MoveNode(curNode, curQuote, -1);
    3961               0 :         NS_ENSURE_SUCCESS(res, res);
    3962                 :         // forget curList, if any
    3963               0 :         curList = nsnull;
    3964                 :       }
    3965                 :     }
    3966                 :   }
    3967               0 :   return res;
    3968                 : }
    3969                 : 
    3970                 : 
    3971                 : nsresult
    3972               0 : nsHTMLEditRules::WillOutdent(nsISelection *aSelection, bool *aCancel, bool *aHandled)
    3973                 : {
    3974               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    3975                 :   // initialize out param
    3976               0 :   *aCancel = false;
    3977               0 :   *aHandled = true;
    3978               0 :   nsresult res = NS_OK;
    3979               0 :   nsCOMPtr<nsIDOMNode> rememberedLeftBQ, rememberedRightBQ;
    3980               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    3981                 : 
    3982               0 :   res = NormalizeSelection(aSelection);
    3983               0 :   NS_ENSURE_SUCCESS(res, res);
    3984                 :   // some scoping for selection resetting - we may need to tweak it
    3985                 :   {
    3986               0 :     nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    3987                 :     
    3988                 :     // convert the selection ranges into "promoted" selection ranges:
    3989                 :     // this basically just expands the range to include the immediate
    3990                 :     // block parent, and then further expands to include any ancestors
    3991                 :     // whose children are all in the range
    3992               0 :     nsCOMArray<nsIDOMNode> arrayOfNodes;
    3993               0 :     res = GetNodesFromSelection(aSelection, kOutdent, arrayOfNodes);
    3994               0 :     NS_ENSURE_SUCCESS(res, res);
    3995                 : 
    3996                 :     // Ok, now go through all the nodes and remove a level of blockquoting, 
    3997                 :     // or whatever is appropriate.  Wohoo!
    3998                 : 
    3999               0 :     nsCOMPtr<nsIDOMNode> curBlockQuote, firstBQChild, lastBQChild;
    4000               0 :     bool curBlockQuoteIsIndentedWithCSS = false;
    4001               0 :     PRInt32 listCount = arrayOfNodes.Count();
    4002                 :     PRInt32 i;
    4003               0 :     nsCOMPtr<nsIDOMNode> curParent;
    4004               0 :     for (i=0; i<listCount; i++)
    4005                 :     {
    4006                 :       // here's where we actually figure out what to do
    4007               0 :       nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    4008                 :       PRInt32 offset;
    4009               0 :       res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    4010               0 :       NS_ENSURE_SUCCESS(res, res);
    4011                 :       
    4012                 :       // is it a blockquote?
    4013               0 :       if (nsHTMLEditUtils::IsBlockquote(curNode)) 
    4014                 :       {
    4015                 :         // if it is a blockquote, remove it.
    4016                 :         // So we need to finish up dealng with any curBlockQuote first.
    4017               0 :         if (curBlockQuote)
    4018                 :         {
    4019                 :           res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
    4020                 :                                    curBlockQuoteIsIndentedWithCSS,
    4021                 :                                    address_of(rememberedLeftBQ),
    4022               0 :                                    address_of(rememberedRightBQ));
    4023               0 :           NS_ENSURE_SUCCESS(res, res);
    4024               0 :           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
    4025               0 :           curBlockQuoteIsIndentedWithCSS = false;
    4026                 :         }
    4027               0 :         res = mHTMLEditor->RemoveBlockContainer(curNode);
    4028               0 :         NS_ENSURE_SUCCESS(res, res);
    4029               0 :         continue;
    4030                 :       }
    4031                 :       // is it a block with a 'margin' property?
    4032               0 :       if (useCSS && IsBlockNode(curNode))
    4033                 :       {
    4034               0 :         nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
    4035               0 :         nsAutoString value;
    4036               0 :         mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, marginProperty, value);
    4037                 :         float f;
    4038               0 :         nsCOMPtr<nsIAtom> unit;
    4039               0 :         mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
    4040               0 :         if (f > 0)
    4041                 :         {
    4042               0 :           RelativeChangeIndentationOfElementNode(curNode, -1);
    4043               0 :           continue;
    4044                 :         }
    4045                 :       }
    4046                 :       // is it a list item?
    4047               0 :       if (nsHTMLEditUtils::IsListItem(curNode)) 
    4048                 :       {
    4049                 :         // if it is a list item, that means we are not outdenting whole list.
    4050                 :         // So we need to finish up dealing with any curBlockQuote, and then
    4051                 :         // pop this list item.
    4052               0 :         if (curBlockQuote)
    4053                 :         {
    4054                 :           res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
    4055                 :                                    curBlockQuoteIsIndentedWithCSS,
    4056                 :                                    address_of(rememberedLeftBQ),
    4057               0 :                                    address_of(rememberedRightBQ));
    4058               0 :           NS_ENSURE_SUCCESS(res, res);
    4059               0 :           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
    4060               0 :           curBlockQuoteIsIndentedWithCSS = false;
    4061                 :         }
    4062                 :         bool bOutOfList;
    4063               0 :         res = PopListItem(curNode, &bOutOfList);
    4064               0 :         NS_ENSURE_SUCCESS(res, res);
    4065               0 :         continue;
    4066                 :       }
    4067                 :       // do we have a blockquote that we are already committed to removing?
    4068               0 :       if (curBlockQuote)
    4069                 :       {
    4070                 :         // if so, is this node a descendant?
    4071               0 :         if (nsEditorUtils::IsDescendantOf(curNode, curBlockQuote))
    4072                 :         {
    4073               0 :           lastBQChild = curNode;
    4074               0 :           continue;  // then we don't need to do anything different for this node
    4075                 :         }
    4076                 :         else
    4077                 :         {
    4078                 :           // otherwise, we have progressed beyond end of curBlockQuote,
    4079                 :           // so lets handle it now.  We need to remove the portion of 
    4080                 :           // curBlockQuote that contains [firstBQChild - lastBQChild].
    4081                 :           res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
    4082                 :                                    curBlockQuoteIsIndentedWithCSS,
    4083                 :                                    address_of(rememberedLeftBQ),
    4084               0 :                                    address_of(rememberedRightBQ));
    4085               0 :           NS_ENSURE_SUCCESS(res, res);
    4086               0 :           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
    4087               0 :           curBlockQuoteIsIndentedWithCSS = false;
    4088                 :           // fall out and handle curNode
    4089                 :         }
    4090                 :       }
    4091                 :       
    4092                 :       // are we inside a blockquote?
    4093               0 :       nsCOMPtr<nsIDOMNode> n = curNode;
    4094               0 :       nsCOMPtr<nsIDOMNode> tmp;
    4095               0 :       curBlockQuoteIsIndentedWithCSS = false;
    4096                 :       // keep looking up the hierarchy as long as we don't hit the body or the
    4097                 :       // active editing host or a table element (other than an entire table)
    4098               0 :       while (!nsTextEditUtils::IsBody(n) && mHTMLEditor->IsNodeInActiveEditor(n)
    4099               0 :           && (nsHTMLEditUtils::IsTable(n) || !nsHTMLEditUtils::IsTableElement(n)))
    4100                 :       {
    4101               0 :         n->GetParentNode(getter_AddRefs(tmp));
    4102               0 :         if (!tmp) {
    4103               0 :           break;
    4104                 :         }
    4105               0 :         n = tmp;
    4106               0 :         if (nsHTMLEditUtils::IsBlockquote(n))
    4107                 :         {
    4108                 :           // if so, remember it, and remember first node we are taking out of it.
    4109               0 :           curBlockQuote = n;
    4110               0 :           firstBQChild  = curNode;
    4111               0 :           lastBQChild   = curNode;
    4112               0 :           break;
    4113                 :         }
    4114               0 :         else if (useCSS)
    4115                 :         {
    4116               0 :           nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
    4117               0 :           nsAutoString value;
    4118               0 :           mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(n, marginProperty, value);
    4119                 :           float f;
    4120               0 :           nsCOMPtr<nsIAtom> unit;
    4121               0 :           mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
    4122               0 :           if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && nsHTMLEditUtils::IsList(curNode)))
    4123                 :           {
    4124               0 :             curBlockQuote = n;
    4125               0 :             firstBQChild  = curNode;
    4126               0 :             lastBQChild   = curNode;
    4127               0 :             curBlockQuoteIsIndentedWithCSS = true;
    4128                 :             break;
    4129                 :           }
    4130                 :         }
    4131                 :       }
    4132                 : 
    4133               0 :       if (!curBlockQuote)
    4134                 :       {
    4135                 :         // could not find an enclosing blockquote for this node.  handle list cases.
    4136               0 :         if (nsHTMLEditUtils::IsList(curParent))  // move node out of list
    4137                 :         {
    4138               0 :           if (nsHTMLEditUtils::IsList(curNode))  // just unwrap this sublist
    4139                 :           {
    4140               0 :             res = mHTMLEditor->RemoveBlockContainer(curNode);
    4141               0 :             NS_ENSURE_SUCCESS(res, res);
    4142                 :           }
    4143                 :           // handled list item case above
    4144                 :         }
    4145               0 :         else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
    4146                 :         {
    4147               0 :           nsCOMPtr<nsIDOMNode> child;
    4148               0 :           curNode->GetLastChild(getter_AddRefs(child));
    4149               0 :           while (child)
    4150                 :           {
    4151               0 :             if (nsHTMLEditUtils::IsListItem(child))
    4152                 :             {
    4153                 :               bool bOutOfList;
    4154               0 :               res = PopListItem(child, &bOutOfList);
    4155               0 :               NS_ENSURE_SUCCESS(res, res);
    4156                 :             }
    4157               0 :             else if (nsHTMLEditUtils::IsList(child))
    4158                 :             {
    4159                 :               // We have an embedded list, so move it out from under the
    4160                 :               // parent list. Be sure to put it after the parent list
    4161                 :               // because this loop iterates backwards through the parent's
    4162                 :               // list of children.
    4163                 : 
    4164               0 :               res = mHTMLEditor->MoveNode(child, curParent, offset + 1);
    4165               0 :               NS_ENSURE_SUCCESS(res, res);
    4166                 :             }
    4167                 :             else
    4168                 :             {
    4169                 :               // delete any non- list items for now
    4170               0 :               res = mHTMLEditor->DeleteNode(child);
    4171               0 :               NS_ENSURE_SUCCESS(res, res);
    4172                 :             }
    4173               0 :             curNode->GetLastChild(getter_AddRefs(child));
    4174                 :           }
    4175                 :           // delete the now-empty list
    4176               0 :           res = mHTMLEditor->RemoveBlockContainer(curNode);
    4177               0 :           NS_ENSURE_SUCCESS(res, res);
    4178                 :         }
    4179               0 :         else if (useCSS) {
    4180               0 :           nsCOMPtr<nsIDOMElement> element;
    4181               0 :           nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(curNode);
    4182               0 :           if (textNode) {
    4183                 :             // We want to outdent the parent of text nodes
    4184               0 :             nsCOMPtr<nsIDOMNode> parent;
    4185               0 :             textNode->GetParentNode(getter_AddRefs(parent));
    4186               0 :             element = do_QueryInterface(parent);
    4187                 :           } else {
    4188               0 :             element = do_QueryInterface(curNode);
    4189                 :           }
    4190               0 :           if (element) {
    4191               0 :             RelativeChangeIndentationOfElementNode(element, -1);
    4192                 :           }
    4193                 :         }
    4194                 :       }
    4195                 :     }
    4196               0 :     if (curBlockQuote)
    4197                 :     {
    4198                 :       // we have a blockquote we haven't finished handling
    4199                 :       res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
    4200                 :                                curBlockQuoteIsIndentedWithCSS,
    4201                 :                                address_of(rememberedLeftBQ),
    4202               0 :                                address_of(rememberedRightBQ));
    4203               0 :       NS_ENSURE_SUCCESS(res, res);
    4204                 :     }
    4205                 :   }
    4206                 :   // make sure selection didn't stick to last piece of content in old bq
    4207                 :   // (only a problem for collapsed selections)
    4208               0 :   if (rememberedLeftBQ || rememberedRightBQ)
    4209                 :   {
    4210                 :     bool bCollapsed;
    4211               0 :     res = aSelection->GetIsCollapsed(&bCollapsed);
    4212               0 :     if (bCollapsed)
    4213                 :     {
    4214                 :       // push selection past end of rememberedLeftBQ
    4215               0 :       nsCOMPtr<nsIDOMNode> sNode;
    4216                 :       PRInt32 sOffset;
    4217               0 :       mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(sNode), &sOffset);
    4218               0 :       if (rememberedLeftBQ &&
    4219               0 :           ((sNode == rememberedLeftBQ) || nsEditorUtils::IsDescendantOf(sNode, rememberedLeftBQ)))
    4220                 :       {
    4221                 :         // selection is inside rememberedLeftBQ - push it past it.
    4222               0 :         nsEditor::GetNodeLocation(rememberedLeftBQ, address_of(sNode), &sOffset);
    4223               0 :         sOffset++;
    4224               0 :         aSelection->Collapse(sNode, sOffset);
    4225                 :       }
    4226                 :       // and pull selection before beginning of rememberedRightBQ
    4227               0 :       mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(sNode), &sOffset);
    4228               0 :       if (rememberedRightBQ &&
    4229               0 :           ((sNode == rememberedRightBQ) || nsEditorUtils::IsDescendantOf(sNode, rememberedRightBQ)))
    4230                 :       {
    4231                 :         // selection is inside rememberedRightBQ - push it before it.
    4232               0 :         nsEditor::GetNodeLocation(rememberedRightBQ, address_of(sNode), &sOffset);
    4233               0 :         aSelection->Collapse(sNode, sOffset);
    4234                 :       }
    4235                 :     }
    4236                 :   }
    4237               0 :   return res;
    4238                 : }
    4239                 : 
    4240                 : 
    4241                 : ///////////////////////////////////////////////////////////////////////////
    4242                 : // RemovePartOfBlock:  split aBlock and move aStartChild to aEndChild out
    4243                 : //                     of aBlock.  return left side of block (if any) in
    4244                 : //                     aLeftNode.  return right side of block (if any) in
    4245                 : //                     aRightNode.  
    4246                 : //                  
    4247                 : nsresult 
    4248               0 : nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock, 
    4249                 :                                    nsIDOMNode *aStartChild, 
    4250                 :                                    nsIDOMNode *aEndChild,
    4251                 :                                    nsCOMPtr<nsIDOMNode> *aLeftNode,
    4252                 :                                    nsCOMPtr<nsIDOMNode> *aRightNode)
    4253                 : {
    4254               0 :   nsCOMPtr<nsIDOMNode> middleNode;
    4255                 :   nsresult res = SplitBlock(aBlock, aStartChild, aEndChild,
    4256                 :                             aLeftNode, aRightNode,
    4257               0 :                             address_of(middleNode));
    4258               0 :   NS_ENSURE_SUCCESS(res, res);
    4259                 :   // get rid of part of blockquote we are outdenting
    4260                 : 
    4261               0 :   return mHTMLEditor->RemoveBlockContainer(aBlock);
    4262                 : }
    4263                 : 
    4264                 : nsresult 
    4265               0 : nsHTMLEditRules::SplitBlock(nsIDOMNode *aBlock, 
    4266                 :                             nsIDOMNode *aStartChild, 
    4267                 :                             nsIDOMNode *aEndChild,
    4268                 :                             nsCOMPtr<nsIDOMNode> *aLeftNode,
    4269                 :                             nsCOMPtr<nsIDOMNode> *aRightNode,
    4270                 :                             nsCOMPtr<nsIDOMNode> *aMiddleNode)
    4271                 : {
    4272               0 :   NS_ENSURE_TRUE(aBlock && aStartChild && aEndChild, NS_ERROR_NULL_POINTER);
    4273                 :   
    4274               0 :   nsCOMPtr<nsIDOMNode> startParent, endParent, leftNode, rightNode;
    4275                 :   PRInt32 startOffset, endOffset, offset;
    4276                 :   nsresult res;
    4277                 : 
    4278                 :   // get split point location
    4279               0 :   res = nsEditor::GetNodeLocation(aStartChild, address_of(startParent), &startOffset);
    4280               0 :   NS_ENSURE_SUCCESS(res, res);
    4281                 :   
    4282                 :   // do the splits!
    4283                 :   res = mHTMLEditor->SplitNodeDeep(aBlock, startParent, startOffset, &offset, 
    4284               0 :                                    true, address_of(leftNode), address_of(rightNode));
    4285               0 :   NS_ENSURE_SUCCESS(res, res);
    4286               0 :   if (rightNode)  aBlock = rightNode;
    4287                 : 
    4288                 :   // remember left portion of block if caller requested
    4289               0 :   if (aLeftNode) 
    4290               0 :     *aLeftNode = leftNode;
    4291                 : 
    4292                 :   // get split point location
    4293               0 :   res = nsEditor::GetNodeLocation(aEndChild, address_of(endParent), &endOffset);
    4294               0 :   NS_ENSURE_SUCCESS(res, res);
    4295               0 :   endOffset++;  // want to be after lastBQChild
    4296                 : 
    4297                 :   // do the splits!
    4298                 :   res = mHTMLEditor->SplitNodeDeep(aBlock, endParent, endOffset, &offset, 
    4299               0 :                                    true, address_of(leftNode), address_of(rightNode));
    4300               0 :   NS_ENSURE_SUCCESS(res, res);
    4301               0 :   if (leftNode)  aBlock = leftNode;
    4302                 :   
    4303                 :   // remember right portion of block if caller requested
    4304               0 :   if (aRightNode) 
    4305               0 :     *aRightNode = rightNode;
    4306                 : 
    4307               0 :   if (aMiddleNode)
    4308               0 :     *aMiddleNode = aBlock;
    4309                 : 
    4310               0 :   return NS_OK;
    4311                 : }
    4312                 : 
    4313                 : nsresult
    4314               0 : nsHTMLEditRules::OutdentPartOfBlock(nsIDOMNode *aBlock, 
    4315                 :                                     nsIDOMNode *aStartChild, 
    4316                 :                                     nsIDOMNode *aEndChild,
    4317                 :                                     bool aIsBlockIndentedWithCSS,
    4318                 :                                     nsCOMPtr<nsIDOMNode> *aLeftNode,
    4319                 :                                     nsCOMPtr<nsIDOMNode> *aRightNode)
    4320                 : {
    4321               0 :   nsCOMPtr<nsIDOMNode> middleNode;
    4322                 :   nsresult res = SplitBlock(aBlock, aStartChild, aEndChild, 
    4323                 :                             aLeftNode,
    4324                 :                             aRightNode,
    4325               0 :                             address_of(middleNode));
    4326               0 :   NS_ENSURE_SUCCESS(res, res);
    4327               0 :   if (aIsBlockIndentedWithCSS)
    4328               0 :     res = RelativeChangeIndentationOfElementNode(middleNode, -1);
    4329                 :   else
    4330               0 :     res = mHTMLEditor->RemoveBlockContainer(middleNode);
    4331               0 :   return res;
    4332                 : }
    4333                 : 
    4334                 : ///////////////////////////////////////////////////////////////////////////
    4335                 : // ConvertListType:  convert list type and list item type.
    4336                 : //                
    4337                 : //                  
    4338                 : nsresult 
    4339               0 : nsHTMLEditRules::ConvertListType(nsIDOMNode *aList, 
    4340                 :                                  nsCOMPtr<nsIDOMNode> *outList,
    4341                 :                                  const nsAString& aListType, 
    4342                 :                                  const nsAString& aItemType) 
    4343                 : {
    4344               0 :   NS_ENSURE_TRUE(aList && outList, NS_ERROR_NULL_POINTER);
    4345               0 :   *outList = aList;  // we might not need to change the list
    4346               0 :   nsresult res = NS_OK;
    4347               0 :   nsCOMPtr<nsIDOMNode> child, temp;
    4348               0 :   aList->GetFirstChild(getter_AddRefs(child));
    4349               0 :   while (child)
    4350                 :   {
    4351               0 :     if (nsHTMLEditUtils::IsListItem(child) && !nsEditor::NodeIsTypeString(child, aItemType))
    4352                 :     {
    4353               0 :       res = mHTMLEditor->ReplaceContainer(child, address_of(temp), aItemType);
    4354               0 :       NS_ENSURE_SUCCESS(res, res);
    4355               0 :       child = temp;
    4356                 :     }
    4357               0 :     else if (nsHTMLEditUtils::IsList(child) && !nsEditor::NodeIsTypeString(child, aListType))
    4358                 :     {
    4359               0 :       res = ConvertListType(child, address_of(temp), aListType, aItemType);
    4360               0 :       NS_ENSURE_SUCCESS(res, res);
    4361               0 :       child = temp;
    4362                 :     }
    4363               0 :     child->GetNextSibling(getter_AddRefs(temp));
    4364               0 :     child = temp;
    4365                 :   }
    4366               0 :   if (!nsEditor::NodeIsTypeString(aList, aListType))
    4367                 :   {
    4368               0 :     res = mHTMLEditor->ReplaceContainer(aList, outList, aListType);
    4369                 :   }
    4370               0 :   return res;
    4371                 : }
    4372                 : 
    4373                 : 
    4374                 : ///////////////////////////////////////////////////////////////////////////
    4375                 : // CreateStyleForInsertText:  take care of clearing and setting appropriate
    4376                 : //                            style nodes for text insertion.
    4377                 : //                
    4378                 : //                  
    4379                 : nsresult 
    4380               0 : nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc) 
    4381                 : {
    4382               0 :   NS_ENSURE_TRUE(aSelection && aDoc, NS_ERROR_NULL_POINTER);
    4383               0 :   NS_ENSURE_TRUE(mHTMLEditor->mTypeInState, NS_ERROR_NULL_POINTER);
    4384                 :   
    4385               0 :   bool weDidSometing = false;
    4386               0 :   nsCOMPtr<nsIDOMNode> node, tmp;
    4387                 :   PRInt32 offset;
    4388               0 :   nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
    4389               0 :   NS_ENSURE_SUCCESS(res, res);
    4390               0 :   nsAutoPtr<PropItem> item;
    4391                 :   
    4392                 :   // if we deleted selection then also for cached styles
    4393               0 :   if (mDidDeleteSelection && 
    4394                 :       ((mTheAction == nsEditor::kOpInsertText ) ||
    4395                 :        (mTheAction == nsEditor::kOpInsertIMEText) ||
    4396                 :        (mTheAction == nsEditor::kOpInsertBreak) ||
    4397                 :        (mTheAction == nsEditor::kOpDeleteSelection)))
    4398                 :   {
    4399               0 :     res = ReapplyCachedStyles();
    4400               0 :     NS_ENSURE_SUCCESS(res, res);
    4401                 :   }
    4402                 :   // either way we clear the cached styles array
    4403               0 :   res = ClearCachedStyles();  
    4404               0 :   NS_ENSURE_SUCCESS(res, res);
    4405                 : 
    4406                 :   // next examine our present style and make sure default styles are either present or
    4407                 :   // explicitly overridden.  If neither, add the default style to the TypeInState
    4408               0 :   PRInt32 j, defcon = mHTMLEditor->mDefaultStyles.Length();
    4409               0 :   for (j=0; j<defcon; j++)
    4410                 :   {
    4411               0 :     PropItem *propItem = mHTMLEditor->mDefaultStyles[j];
    4412               0 :     NS_ENSURE_TRUE(propItem, NS_ERROR_NULL_POINTER);
    4413                 :     bool bFirst, bAny, bAll;
    4414                 : 
    4415                 :     // GetInlineProperty also examine TypeInState.  The only gotcha here is that a cleared
    4416                 :     // property looks like an unset property.  For now I'm assuming that's not a problem:
    4417                 :     // that default styles will always be multivalue styles (like font face or size) where
    4418                 :     // clearing the style means we want to go back to the default.  If we ever wanted a 
    4419                 :     // "toggle" style like bold for a default, though, I'll have to add code to detect the
    4420                 :     // difference between unset and explicitly cleared, else user would never be able to
    4421                 :     // unbold, for instance.
    4422               0 :     nsAutoString curValue;
    4423                 :     res = mHTMLEditor->GetInlinePropertyBase(propItem->tag, &(propItem->attr), nsnull, 
    4424               0 :                                              &bFirst, &bAny, &bAll, &curValue, false);
    4425               0 :     NS_ENSURE_SUCCESS(res, res);
    4426                 :     
    4427               0 :     if (!bAny)  // no style set for this prop/attr
    4428                 :     {
    4429               0 :       mHTMLEditor->mTypeInState->SetProp(propItem->tag, propItem->attr, propItem->value);
    4430                 :     }
    4431                 :   }
    4432                 :   
    4433               0 :   nsCOMPtr<nsIDOMElement> rootElement;
    4434               0 :   res = aDoc->GetDocumentElement(getter_AddRefs(rootElement));
    4435               0 :   NS_ENSURE_SUCCESS(res, res);
    4436                 : 
    4437                 :   // process clearing any styles first
    4438               0 :   mHTMLEditor->mTypeInState->TakeClearProperty(getter_Transfers(item));
    4439               0 :   while (item && node != rootElement)
    4440                 :   {
    4441               0 :     nsCOMPtr<nsIDOMNode> leftNode, rightNode, secondSplitParent, newSelParent, savedBR;
    4442               0 :     res = mHTMLEditor->SplitStyleAbovePoint(address_of(node), &offset, item->tag, &item->attr, address_of(leftNode), address_of(rightNode));
    4443               0 :     NS_ENSURE_SUCCESS(res, res);
    4444                 :     bool bIsEmptyNode;
    4445               0 :     if (leftNode)
    4446                 :     {
    4447               0 :       mHTMLEditor->IsEmptyNode(leftNode, &bIsEmptyNode, false, true);
    4448               0 :       if (bIsEmptyNode)
    4449                 :       {
    4450                 :         // delete leftNode if it became empty
    4451               0 :         res = mEditor->DeleteNode(leftNode);
    4452               0 :         NS_ENSURE_SUCCESS(res, res);
    4453                 :       }
    4454                 :     }
    4455               0 :     if (rightNode)
    4456                 :     {
    4457               0 :       secondSplitParent = mHTMLEditor->GetLeftmostChild(rightNode);
    4458                 :       // don't try to split non-containers (br's, images, hr's, etc)
    4459               0 :       if (!secondSplitParent) secondSplitParent = rightNode;
    4460               0 :       if (!mHTMLEditor->IsContainer(secondSplitParent))
    4461                 :       {
    4462               0 :         if (nsTextEditUtils::IsBreak(secondSplitParent))
    4463               0 :           savedBR = secondSplitParent;
    4464                 : 
    4465               0 :         secondSplitParent->GetParentNode(getter_AddRefs(tmp));
    4466               0 :         secondSplitParent = tmp;
    4467                 :       }
    4468               0 :       offset = 0;
    4469               0 :       res = mHTMLEditor->SplitStyleAbovePoint(address_of(secondSplitParent), &offset, item->tag, &(item->attr), address_of(leftNode), address_of(rightNode));
    4470               0 :       NS_ENSURE_SUCCESS(res, res);
    4471                 :       // should be impossible to not get a new leftnode here
    4472               0 :       NS_ENSURE_TRUE(leftNode, NS_ERROR_FAILURE);
    4473               0 :       newSelParent = mHTMLEditor->GetLeftmostChild(leftNode);
    4474               0 :       if (!newSelParent) newSelParent = leftNode;
    4475                 :       // if rightNode starts with a br, suck it out of right node and into leftNode.
    4476                 :       // This is so we you don't revert back to the previous style if you happen to click at the end of a line.
    4477               0 :       if (savedBR)
    4478                 :       {
    4479               0 :         res = mEditor->MoveNode(savedBR, newSelParent, 0);
    4480               0 :         NS_ENSURE_SUCCESS(res, res);
    4481                 :       }
    4482               0 :       mHTMLEditor->IsEmptyNode(rightNode, &bIsEmptyNode, false, true);
    4483               0 :       if (bIsEmptyNode)
    4484                 :       {
    4485                 :         // delete rightNode if it became empty
    4486               0 :         res = mEditor->DeleteNode(rightNode);
    4487               0 :         NS_ENSURE_SUCCESS(res, res);
    4488                 :       }
    4489                 :       // remove the style on this new hierarchy
    4490               0 :       PRInt32 newSelOffset = 0;
    4491                 :       {
    4492                 :         // track the point at the new hierarchy.
    4493                 :         // This is so we can know where to put the selection after we call
    4494                 :         // RemoveStyleInside().  RemoveStyleInside() could remove any and all of those nodes,
    4495                 :         // so I have to use the range tracking system to find the right spot to put selection.
    4496               0 :         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(newSelParent), &newSelOffset);
    4497               0 :         res = mHTMLEditor->RemoveStyleInside(leftNode, item->tag, &(item->attr));
    4498               0 :         NS_ENSURE_SUCCESS(res, res);
    4499                 :       }
    4500                 :       // reset our node offset values to the resulting new sel point
    4501               0 :       node = newSelParent;
    4502               0 :       offset = newSelOffset;
    4503                 :     }
    4504               0 :     mHTMLEditor->mTypeInState->TakeClearProperty(getter_Transfers(item));
    4505               0 :     weDidSometing = true;
    4506                 :   }
    4507                 :   
    4508                 :   // then process setting any styles
    4509                 :   PRInt32 relFontSize;
    4510                 :   
    4511               0 :   res = mHTMLEditor->mTypeInState->TakeRelativeFontSize(&relFontSize);
    4512               0 :   NS_ENSURE_SUCCESS(res, res);
    4513               0 :   res = mHTMLEditor->mTypeInState->TakeSetProperty(getter_Transfers(item));
    4514               0 :   NS_ENSURE_SUCCESS(res, res);
    4515                 :   
    4516               0 :   if (item || relFontSize) // we have at least one style to add; make a
    4517                 :   {                        // new text node to insert style nodes above.
    4518               0 :     if (mHTMLEditor->IsTextNode(node))
    4519                 :     {
    4520                 :       // if we are in a text node, split it
    4521               0 :       res = mHTMLEditor->SplitNodeDeep(node, node, offset, &offset);
    4522               0 :       NS_ENSURE_SUCCESS(res, res);
    4523               0 :       node->GetParentNode(getter_AddRefs(tmp));
    4524               0 :       node = tmp;
    4525                 :     }
    4526               0 :     if (!mHTMLEditor->IsContainer(node))
    4527                 :     {
    4528               0 :       return NS_OK;
    4529                 :     }
    4530               0 :     nsCOMPtr<nsIDOMNode> newNode;
    4531               0 :     nsCOMPtr<nsIDOMText> nodeAsText;
    4532               0 :     res = aDoc->CreateTextNode(EmptyString(), getter_AddRefs(nodeAsText));
    4533               0 :     NS_ENSURE_SUCCESS(res, res);
    4534               0 :     NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER);
    4535               0 :     newNode = do_QueryInterface(nodeAsText);
    4536               0 :     res = mHTMLEditor->InsertNode(newNode, node, offset);
    4537               0 :     NS_ENSURE_SUCCESS(res, res);
    4538               0 :     node = newNode;
    4539               0 :     offset = 0;
    4540               0 :     weDidSometing = true;
    4541                 : 
    4542               0 :     if (relFontSize)
    4543                 :     {
    4544                 :       PRInt32 j, dir;
    4545                 :       // dir indicated bigger versus smaller.  1 = bigger, -1 = smaller
    4546               0 :       if (relFontSize > 0) dir=1;
    4547               0 :       else dir = -1;
    4548               0 :       for (j=0; j<abs(relFontSize); j++)
    4549                 :       {
    4550               0 :         res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, 0, -1);
    4551               0 :         NS_ENSURE_SUCCESS(res, res);
    4552                 :       }
    4553                 :     }
    4554                 :     
    4555               0 :     while (item)
    4556                 :     {
    4557               0 :       res = mHTMLEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
    4558               0 :       NS_ENSURE_SUCCESS(res, res);
    4559               0 :       mHTMLEditor->mTypeInState->TakeSetProperty(getter_Transfers(item));
    4560                 :     }
    4561                 :   }
    4562               0 :   if (weDidSometing)
    4563               0 :     return aSelection->Collapse(node, offset);
    4564                 :     
    4565               0 :   return res;
    4566                 : }
    4567                 : 
    4568                 : 
    4569                 : ///////////////////////////////////////////////////////////////////////////
    4570                 : // IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
    4571                 : //               A block can have children and still be considered empty,
    4572                 : //               if the children are empty or non-editable.
    4573                 : //                  
    4574                 : nsresult 
    4575               0 : nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, 
    4576                 :                               bool *outIsEmptyBlock, 
    4577                 :                               bool aMozBRDoesntCount,
    4578                 :                               bool aListItemsNotEmpty) 
    4579                 : {
    4580               0 :   NS_ENSURE_TRUE(aNode && outIsEmptyBlock, NS_ERROR_NULL_POINTER);
    4581               0 :   *outIsEmptyBlock = true;
    4582                 :   
    4583                 : //  nsresult res = NS_OK;
    4584               0 :   nsCOMPtr<nsIDOMNode> nodeToTest;
    4585               0 :   if (IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
    4586                 : //  else nsCOMPtr<nsIDOMElement> block;
    4587                 : //  looks like I forgot to finish this.  Wonder what I was going to do?
    4588                 : 
    4589               0 :   NS_ENSURE_TRUE(nodeToTest, NS_ERROR_NULL_POINTER);
    4590                 :   return mHTMLEditor->IsEmptyNode(nodeToTest, outIsEmptyBlock,
    4591               0 :                      aMozBRDoesntCount, aListItemsNotEmpty);
    4592                 : }
    4593                 : 
    4594                 : 
    4595                 : nsresult
    4596               0 : nsHTMLEditRules::WillAlign(nsISelection *aSelection, 
    4597                 :                            const nsAString *alignType, 
    4598                 :                            bool *aCancel,
    4599                 :                            bool *aHandled)
    4600                 : {
    4601               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    4602                 : 
    4603               0 :   nsresult res = WillInsert(aSelection, aCancel);
    4604               0 :   NS_ENSURE_SUCCESS(res, res);
    4605                 : 
    4606                 :   // initialize out param
    4607                 :   // we want to ignore result of WillInsert()
    4608               0 :   *aCancel = false;
    4609               0 :   *aHandled = false;
    4610                 : 
    4611               0 :   res = NormalizeSelection(aSelection);
    4612               0 :   NS_ENSURE_SUCCESS(res, res);
    4613               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    4614                 : 
    4615                 :   // convert the selection ranges into "promoted" selection ranges:
    4616                 :   // this basically just expands the range to include the immediate
    4617                 :   // block parent, and then further expands to include any ancestors
    4618                 :   // whose children are all in the range
    4619               0 :   *aHandled = true;
    4620               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    4621               0 :   res = GetNodesFromSelection(aSelection, kAlign, arrayOfNodes);
    4622               0 :   NS_ENSURE_SUCCESS(res, res);
    4623                 : 
    4624                 :   // if we don't have any nodes, or we have only a single br, then we are
    4625                 :   // creating an empty alignment div.  We have to do some different things for these.
    4626               0 :   bool emptyDiv = false;
    4627               0 :   PRInt32 listCount = arrayOfNodes.Count();
    4628               0 :   if (!listCount) emptyDiv = true;
    4629               0 :   if (listCount == 1)
    4630                 :   {
    4631               0 :     nsCOMPtr<nsIDOMNode> theNode = arrayOfNodes[0];
    4632                 : 
    4633               0 :     if (nsHTMLEditUtils::SupportsAlignAttr(theNode))
    4634                 :     {
    4635                 :       // the node is a table element, an horiz rule, a paragraph, a div
    4636                 :       // or a section header; in HTML 4, it can directly carry the ALIGN
    4637                 :       // attribute and we don't need to make a div! If we are in CSS mode,
    4638                 :       // all the work is done in AlignBlock
    4639               0 :       nsCOMPtr<nsIDOMElement> theElem = do_QueryInterface(theNode);
    4640               0 :       res = AlignBlock(theElem, alignType, true);
    4641               0 :       NS_ENSURE_SUCCESS(res, res);
    4642               0 :       return NS_OK;
    4643                 :     }
    4644                 : 
    4645               0 :     if (nsTextEditUtils::IsBreak(theNode))
    4646                 :     {
    4647                 :       // The special case emptyDiv code (below) that consumes BRs can
    4648                 :       // cause tables to split if the start node of the selection is
    4649                 :       // not in a table cell or caption, for example parent is a <tr>.
    4650                 :       // Avoid this unnecessary splitting if possible by leaving emptyDiv
    4651                 :       // FALSE so that we fall through to the normal case alignment code.
    4652                 :       //
    4653                 :       // XXX: It seems a little error prone for the emptyDiv special
    4654                 :       //      case code to assume that the start node of the selection
    4655                 :       //      is the parent of the single node in the arrayOfNodes, as
    4656                 :       //      the paragraph above points out. Do we rely on the selection
    4657                 :       //      start node because of the fact that arrayOfNodes can be empty?
    4658                 :       //      We should probably revisit this issue. - kin
    4659                 : 
    4660               0 :       nsCOMPtr<nsIDOMNode> parent;
    4661                 :       PRInt32 offset;
    4662               0 :       res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    4663                 : 
    4664               0 :       if (!nsHTMLEditUtils::IsTableElement(parent) || nsHTMLEditUtils::IsTableCellOrCaption(parent))
    4665               0 :         emptyDiv = true;
    4666                 :     }
    4667                 :   }
    4668               0 :   if (emptyDiv)
    4669                 :   {
    4670                 :     PRInt32 offset;
    4671               0 :     nsCOMPtr<nsIDOMNode> brNode, parent, theDiv, sib;
    4672               0 :     NS_NAMED_LITERAL_STRING(divType, "div");
    4673               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    4674               0 :     NS_ENSURE_SUCCESS(res, res);
    4675               0 :     res = SplitAsNeeded(&divType, address_of(parent), &offset);
    4676               0 :     NS_ENSURE_SUCCESS(res, res);
    4677                 :     // consume a trailing br, if any.  This is to keep an alignment from
    4678                 :     // creating extra lines, if possible.
    4679               0 :     res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode));
    4680               0 :     NS_ENSURE_SUCCESS(res, res);
    4681               0 :     if (brNode && nsTextEditUtils::IsBreak(brNode))
    4682                 :     {
    4683                 :       // making use of html structure... if next node after where
    4684                 :       // we are putting our div is not a block, then the br we 
    4685                 :       // found is in same block we are, so its safe to consume it.
    4686               0 :       res = mHTMLEditor->GetNextHTMLSibling(parent, offset, address_of(sib));
    4687               0 :       NS_ENSURE_SUCCESS(res, res);
    4688               0 :       if (!IsBlockNode(sib))
    4689                 :       {
    4690               0 :         res = mHTMLEditor->DeleteNode(brNode);
    4691               0 :         NS_ENSURE_SUCCESS(res, res);
    4692                 :       }
    4693                 :     }
    4694               0 :     res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(theDiv));
    4695               0 :     NS_ENSURE_SUCCESS(res, res);
    4696                 :     // remember our new block for postprocessing
    4697               0 :     mNewBlock = theDiv;
    4698                 :     // set up the alignment on the div, using HTML or CSS
    4699               0 :     nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(theDiv);
    4700               0 :     res = AlignBlock(divElem, alignType, true);
    4701               0 :     NS_ENSURE_SUCCESS(res, res);
    4702               0 :     *aHandled = true;
    4703                 :     // put in a moz-br so that it won't get deleted
    4704               0 :     res = CreateMozBR(theDiv, 0, address_of(brNode));
    4705               0 :     NS_ENSURE_SUCCESS(res, res);
    4706               0 :     res = aSelection->Collapse(theDiv, 0);
    4707               0 :     selectionResetter.Abort();  // don't reset our selection in this case.
    4708               0 :     return res;
    4709                 :   }
    4710                 : 
    4711                 :   // Next we detect all the transitions in the array, where a transition
    4712                 :   // means that adjacent nodes in the array don't have the same parent.
    4713                 : 
    4714               0 :   nsTArray<bool> transitionList;
    4715               0 :   res = MakeTransitionList(arrayOfNodes, transitionList);
    4716               0 :   NS_ENSURE_SUCCESS(res, res);                                 
    4717                 : 
    4718                 :   // Ok, now go through all the nodes and give them an align attrib or put them in a div, 
    4719                 :   // or whatever is appropriate.  Wohoo!
    4720                 : 
    4721               0 :   nsCOMPtr<nsIDOMNode> curParent;
    4722               0 :   nsCOMPtr<nsIDOMNode> curDiv;
    4723               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    4724               0 :   for (PRInt32 i = 0; i < listCount; ++i) {
    4725                 :     // here's where we actually figure out what to do
    4726               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    4727                 : 
    4728                 :     // Ignore all non-editable nodes.  Leave them be.
    4729               0 :     if (!mHTMLEditor->IsEditable(curNode)) continue;
    4730                 : 
    4731                 :     PRInt32 offset;
    4732               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    4733               0 :     NS_ENSURE_SUCCESS(res, res);
    4734                 : 
    4735                 :     // the node is a table element, an horiz rule, a paragraph, a div
    4736                 :     // or a section header; in HTML 4, it can directly carry the ALIGN
    4737                 :     // attribute and we don't need to nest it, just set the alignment.
    4738                 :     // In CSS, assign the corresponding CSS styles in AlignBlock
    4739               0 :     if (nsHTMLEditUtils::SupportsAlignAttr(curNode))
    4740                 :     {
    4741               0 :       nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(curNode);
    4742               0 :       res = AlignBlock(curElem, alignType, false);
    4743               0 :       NS_ENSURE_SUCCESS(res, res);
    4744                 :       // clear out curDiv so that we don't put nodes after this one into it
    4745               0 :       curDiv = 0;
    4746               0 :       continue;
    4747                 :     }
    4748                 : 
    4749                 :     // Skip insignificant formatting text nodes to prevent
    4750                 :     // unnecessary structure splitting!
    4751               0 :     if (nsEditor::IsTextNode(curNode) &&
    4752               0 :        ((nsHTMLEditUtils::IsTableElement(curParent) && !nsHTMLEditUtils::IsTableCellOrCaption(curParent)) ||
    4753               0 :         nsHTMLEditUtils::IsList(curParent)))
    4754               0 :       continue;
    4755                 : 
    4756                 :     // if it's a list item, or a list
    4757                 :     // inside a list, forget any "current" div, and instead put divs inside
    4758                 :     // the appropriate block (td, li, etc)
    4759               0 :     if ( nsHTMLEditUtils::IsListItem(curNode)
    4760               0 :          || nsHTMLEditUtils::IsList(curNode))
    4761                 :     {
    4762               0 :       res = RemoveAlignment(curNode, *alignType, true);
    4763               0 :       NS_ENSURE_SUCCESS(res, res);
    4764               0 :       if (useCSS) {
    4765               0 :         nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(curNode);
    4766               0 :         NS_NAMED_LITERAL_STRING(attrName, "align");
    4767                 :         PRInt32 count;
    4768                 :         mHTMLEditor->mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(curNode, nsnull,
    4769                 :                                                                 &attrName, alignType,
    4770               0 :                                                                 &count, false);
    4771               0 :         curDiv = 0;
    4772               0 :         continue;
    4773                 :       }
    4774               0 :       else if (nsHTMLEditUtils::IsList(curParent)) {
    4775                 :         // if we don't use CSS, add a contraint to list element : they have
    4776                 :         // to be inside another list, ie >= second level of nesting
    4777               0 :         res = AlignInnerBlocks(curNode, alignType);
    4778               0 :         NS_ENSURE_SUCCESS(res, res);
    4779               0 :         curDiv = 0;
    4780               0 :         continue;
    4781                 :       }
    4782                 :       // clear out curDiv so that we don't put nodes after this one into it
    4783                 :     }      
    4784                 : 
    4785                 :     // need to make a div to put things in if we haven't already,
    4786                 :     // or if this node doesn't go in div we used earlier.
    4787               0 :     if (!curDiv || transitionList[i])
    4788                 :     {
    4789                 :       // First, check that our element can contain a div.
    4790               0 :       NS_NAMED_LITERAL_STRING(divType, "div");
    4791               0 :       if (!mEditor->CanContainTag(curParent, divType))
    4792               0 :         return NS_OK; // cancelled
    4793                 : 
    4794               0 :       res = SplitAsNeeded(&divType, address_of(curParent), &offset);
    4795               0 :       NS_ENSURE_SUCCESS(res, res);
    4796               0 :       res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv));
    4797               0 :       NS_ENSURE_SUCCESS(res, res);
    4798                 :       // remember our new block for postprocessing
    4799               0 :       mNewBlock = curDiv;
    4800                 :       // set up the alignment on the div
    4801               0 :       nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curDiv);
    4802               0 :       res = AlignBlock(divElem, alignType, true);
    4803                 :       //nsAutoString attr(NS_LITERAL_STRING("align"));
    4804                 :       //res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
    4805                 :       //NS_ENSURE_SUCCESS(res, res);
    4806                 :       // curDiv is now the correct thing to put curNode in
    4807                 :     }
    4808                 : 
    4809                 :     // tuck the node into the end of the active div
    4810               0 :     res = mHTMLEditor->MoveNode(curNode, curDiv, -1);
    4811               0 :     NS_ENSURE_SUCCESS(res, res);
    4812                 :   }
    4813                 : 
    4814               0 :   return res;
    4815                 : }
    4816                 : 
    4817                 : 
    4818                 : ///////////////////////////////////////////////////////////////////////////
    4819                 : // AlignInnerBlocks: align inside table cells or list items
    4820                 : //       
    4821                 : nsresult
    4822               0 : nsHTMLEditRules::AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType)
    4823                 : {
    4824               0 :   NS_ENSURE_TRUE(aNode && alignType, NS_ERROR_NULL_POINTER);
    4825                 :   nsresult res;
    4826                 :   
    4827                 :   // gather list of table cells or list items
    4828               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    4829               0 :   nsTableCellAndListItemFunctor functor;
    4830               0 :   nsDOMIterator iter;
    4831               0 :   res = iter.Init(aNode);
    4832               0 :   NS_ENSURE_SUCCESS(res, res);
    4833               0 :   res = iter.AppendList(functor, arrayOfNodes);
    4834               0 :   NS_ENSURE_SUCCESS(res, res);
    4835                 :   
    4836                 :   // now that we have the list, align their contents as requested
    4837               0 :   PRInt32 listCount = arrayOfNodes.Count();
    4838                 :   PRInt32 j;
    4839                 : 
    4840               0 :   for (j = 0; j < listCount; j++)
    4841                 :   {
    4842               0 :     nsIDOMNode* node = arrayOfNodes[0];
    4843               0 :     res = AlignBlockContents(node, alignType);
    4844               0 :     NS_ENSURE_SUCCESS(res, res);
    4845               0 :     arrayOfNodes.RemoveObjectAt(0);
    4846                 :   }
    4847                 : 
    4848               0 :   return res;  
    4849                 : }
    4850                 : 
    4851                 : 
    4852                 : ///////////////////////////////////////////////////////////////////////////
    4853                 : // AlignBlockContents: align contents of a block element
    4854                 : //                  
    4855                 : nsresult
    4856               0 : nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType)
    4857                 : {
    4858               0 :   NS_ENSURE_TRUE(aNode && alignType, NS_ERROR_NULL_POINTER);
    4859                 :   nsresult res;
    4860               0 :   nsCOMPtr <nsIDOMNode> firstChild, lastChild, divNode;
    4861                 :   
    4862               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    4863                 : 
    4864               0 :   res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(firstChild));
    4865               0 :   NS_ENSURE_SUCCESS(res, res);
    4866               0 :   res = mHTMLEditor->GetLastEditableChild(aNode, address_of(lastChild));
    4867               0 :   NS_ENSURE_SUCCESS(res, res);
    4868               0 :   NS_NAMED_LITERAL_STRING(attr, "align");
    4869               0 :   if (!firstChild)
    4870                 :   {
    4871                 :     // this cell has no content, nothing to align
    4872                 :   }
    4873               0 :   else if ((firstChild==lastChild) && nsHTMLEditUtils::IsDiv(firstChild))
    4874                 :   {
    4875                 :     // the cell already has a div containing all of its content: just
    4876                 :     // act on this div.
    4877               0 :     nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(firstChild);
    4878               0 :     if (useCSS) {
    4879               0 :       res = mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, *alignType, false); 
    4880                 :     }
    4881                 :     else {
    4882               0 :       res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
    4883                 :     }
    4884               0 :     NS_ENSURE_SUCCESS(res, res);
    4885                 :   }
    4886                 :   else
    4887                 :   {
    4888                 :     // else we need to put in a div, set the alignment, and toss in all the children
    4889               0 :     res = mHTMLEditor->CreateNode(NS_LITERAL_STRING("div"), aNode, 0, getter_AddRefs(divNode));
    4890               0 :     NS_ENSURE_SUCCESS(res, res);
    4891                 :     // set up the alignment on the div
    4892               0 :     nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(divNode);
    4893               0 :     if (useCSS) {
    4894               0 :       res = mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, *alignType, false); 
    4895                 :     }
    4896                 :     else {
    4897               0 :       res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
    4898                 :     }
    4899               0 :     NS_ENSURE_SUCCESS(res, res);
    4900                 :     // tuck the children into the end of the active div
    4901               0 :     while (lastChild && (lastChild != divNode))
    4902                 :     {
    4903               0 :       res = mHTMLEditor->MoveNode(lastChild, divNode, 0);
    4904               0 :       NS_ENSURE_SUCCESS(res, res);
    4905               0 :       res = mHTMLEditor->GetLastEditableChild(aNode, address_of(lastChild));
    4906               0 :       NS_ENSURE_SUCCESS(res, res);
    4907                 :     }
    4908                 :   }
    4909               0 :   return res;
    4910                 : }
    4911                 : 
    4912                 : ///////////////////////////////////////////////////////////////////////////
    4913                 : // CheckForEmptyBlock: Called by WillDeleteSelection to detect and handle
    4914                 : //                     case of deleting from inside an empty block.
    4915                 : //                  
    4916                 : nsresult
    4917               0 : nsHTMLEditRules::CheckForEmptyBlock(nsIDOMNode *aStartNode, 
    4918                 :                                     nsIDOMNode *aBodyNode,
    4919                 :                                     nsISelection *aSelection,
    4920                 :                                     bool *aHandled)
    4921                 : {
    4922                 :   // If the editing host is an inline element, bail out early.
    4923               0 :   if (IsInlineNode(aBodyNode)) {
    4924               0 :     return NS_OK;
    4925                 :   }
    4926                 :   // if we are inside an empty block, delete it.
    4927                 :   // Note: do NOT delete table elements this way.
    4928               0 :   nsresult res = NS_OK;
    4929               0 :   nsCOMPtr<nsIDOMNode> block, emptyBlock;
    4930               0 :   if (IsBlockNode(aStartNode)) 
    4931               0 :     block = aStartNode;
    4932                 :   else
    4933               0 :     block = mHTMLEditor->GetBlockNodeParent(aStartNode);
    4934                 :   bool bIsEmptyNode;
    4935               0 :   if (block != aBodyNode)  // efficiency hack. avoiding IsEmptyNode() call when in body
    4936                 :   {
    4937               0 :     res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
    4938               0 :     NS_ENSURE_SUCCESS(res, res);
    4939               0 :     while (bIsEmptyNode && !nsHTMLEditUtils::IsTableElement(block) && (block != aBodyNode))
    4940                 :     {
    4941               0 :       emptyBlock = block;
    4942               0 :       block = mHTMLEditor->GetBlockNodeParent(emptyBlock);
    4943               0 :       res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
    4944               0 :       NS_ENSURE_SUCCESS(res, res);
    4945                 :     }
    4946                 :   }
    4947                 : 
    4948               0 :   nsCOMPtr<nsIContent> emptyContent = do_QueryInterface(emptyBlock);
    4949               0 :   if (emptyBlock && emptyContent->IsEditable())
    4950                 :   {
    4951               0 :     nsCOMPtr<nsIDOMNode> blockParent;
    4952                 :     PRInt32 offset;
    4953               0 :     res = nsEditor::GetNodeLocation(emptyBlock, address_of(blockParent), &offset);
    4954               0 :     NS_ENSURE_SUCCESS(res, res);
    4955               0 :     NS_ENSURE_TRUE(blockParent && offset >= 0, NS_ERROR_FAILURE);
    4956                 : 
    4957               0 :     if (nsHTMLEditUtils::IsListItem(emptyBlock))
    4958                 :     {
    4959                 :       // are we the first list item in the list?
    4960                 :       bool bIsFirst;
    4961               0 :       res = mHTMLEditor->IsFirstEditableChild(emptyBlock, &bIsFirst);
    4962               0 :       NS_ENSURE_SUCCESS(res, res);
    4963               0 :       if (bIsFirst)
    4964                 :       {
    4965               0 :         nsCOMPtr<nsIDOMNode> listParent;
    4966                 :         PRInt32 listOffset;
    4967               0 :         res = nsEditor::GetNodeLocation(blockParent, address_of(listParent), &listOffset);
    4968               0 :         NS_ENSURE_SUCCESS(res, res);
    4969               0 :         NS_ENSURE_TRUE(listParent && listOffset >= 0, NS_ERROR_FAILURE);
    4970                 :         // if we are a sublist, skip the br creation
    4971               0 :         if (!nsHTMLEditUtils::IsList(listParent))
    4972                 :         {
    4973                 :           // create a br before list
    4974               0 :           nsCOMPtr<nsIDOMNode> brNode;
    4975               0 :           res = mHTMLEditor->CreateBR(listParent, listOffset, address_of(brNode));
    4976               0 :           NS_ENSURE_SUCCESS(res, res);
    4977                 :           // adjust selection to be right before it
    4978               0 :           res = aSelection->Collapse(listParent, listOffset);
    4979               0 :           NS_ENSURE_SUCCESS(res, res);
    4980                 :         }
    4981                 :         // else just let selection perculate up.  We'll adjust it in AfterEdit()
    4982                 :       }
    4983                 :     }
    4984                 :     else
    4985                 :     {
    4986                 :       // adjust selection to be right after it
    4987               0 :       res = aSelection->Collapse(blockParent, offset+1);
    4988               0 :       NS_ENSURE_SUCCESS(res, res);
    4989                 :     }
    4990               0 :     res = mHTMLEditor->DeleteNode(emptyBlock);
    4991               0 :     *aHandled = true;
    4992                 :   }
    4993               0 :   return res;
    4994                 : }
    4995                 : 
    4996                 : nsresult
    4997               0 : nsHTMLEditRules::CheckForInvisibleBR(nsIDOMNode *aBlock, 
    4998                 :                                      BRLocation aWhere, 
    4999                 :                                      nsCOMPtr<nsIDOMNode> *outBRNode,
    5000                 :                                      PRInt32 aOffset)
    5001                 : {
    5002               0 :   NS_ENSURE_TRUE(aBlock && outBRNode, NS_ERROR_NULL_POINTER);
    5003               0 :   *outBRNode = nsnull;
    5004                 : 
    5005               0 :   nsCOMPtr<nsIDOMNode> testNode;
    5006               0 :   PRInt32 testOffset = 0;
    5007               0 :   bool runTest = false;
    5008                 : 
    5009               0 :   if (aWhere == kBlockEnd)
    5010                 :   {
    5011                 :     nsCOMPtr<nsIDOMNode> rightmostNode =
    5012               0 :       mHTMLEditor->GetRightmostChild(aBlock, true); // no block crossing
    5013                 : 
    5014               0 :     if (rightmostNode)
    5015                 :     {
    5016               0 :       nsCOMPtr<nsIDOMNode> nodeParent;
    5017                 :       PRInt32 nodeOffset;
    5018                 : 
    5019               0 :       if (NS_SUCCEEDED(nsEditor::GetNodeLocation(rightmostNode,
    5020                 :                                                  address_of(nodeParent), 
    5021                 :                                                  &nodeOffset)))
    5022                 :       {
    5023               0 :         runTest = true;
    5024               0 :         testNode = nodeParent;
    5025                 :         // use offset + 1, because we want the last node included in our evaluation
    5026               0 :         testOffset = nodeOffset + 1;
    5027                 :       }
    5028                 :     }
    5029                 :   }
    5030               0 :   else if (aOffset)
    5031                 :   {
    5032               0 :     runTest = true;
    5033               0 :     testNode = aBlock;
    5034                 :     // we'll check everything to the left of the input position
    5035               0 :     testOffset = aOffset;
    5036                 :   }
    5037                 : 
    5038               0 :   if (runTest)
    5039                 :   {
    5040               0 :     nsWSRunObject wsTester(mHTMLEditor, testNode, testOffset);
    5041               0 :     if (nsWSRunObject::eBreak == wsTester.mStartReason)
    5042                 :     {
    5043               0 :       *outBRNode = wsTester.mStartReasonNode;
    5044                 :     }
    5045                 :   }
    5046                 : 
    5047               0 :   return NS_OK;
    5048                 : }
    5049                 : 
    5050                 : 
    5051                 : ///////////////////////////////////////////////////////////////////////////
    5052                 : // GetInnerContent: aList and aTbl allow the caller to specify what kind 
    5053                 : //                  of content to "look inside".  If aTbl is true, look inside
    5054                 : //                  any table content, and insert the inner content into the
    5055                 : //                  supplied issupportsarray at offset aIndex.  
    5056                 : //                  Similarly with aList and list content.
    5057                 : //                  aIndex is updated to point past inserted elements.
    5058                 : //                  
    5059                 : nsresult
    5060               0 : nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsCOMArray<nsIDOMNode> &outArrayOfNodes, 
    5061                 :                                  PRInt32 *aIndex, bool aList, bool aTbl)
    5062                 : {
    5063               0 :   NS_ENSURE_TRUE(aNode && aIndex, NS_ERROR_NULL_POINTER);
    5064                 : 
    5065               0 :   nsCOMPtr<nsIDOMNode> node;
    5066                 :   
    5067               0 :   nsresult res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(node));
    5068               0 :   while (NS_SUCCEEDED(res) && node)
    5069                 :   {
    5070               0 :     if (  ( aList && (nsHTMLEditUtils::IsList(node)     || 
    5071               0 :                       nsHTMLEditUtils::IsListItem(node) ) )
    5072               0 :        || ( aTbl && nsHTMLEditUtils::IsTableElement(node) )  )
    5073                 :     {
    5074               0 :       res = GetInnerContent(node, outArrayOfNodes, aIndex, aList, aTbl);
    5075               0 :       NS_ENSURE_SUCCESS(res, res);
    5076                 :     }
    5077                 :     else
    5078                 :     {
    5079               0 :       outArrayOfNodes.InsertObjectAt(node, *aIndex);
    5080               0 :       (*aIndex)++;
    5081                 :     }
    5082               0 :     nsCOMPtr<nsIDOMNode> tmp;
    5083               0 :     res = node->GetNextSibling(getter_AddRefs(tmp));
    5084               0 :     node = tmp;
    5085                 :   }
    5086                 : 
    5087               0 :   return res;
    5088                 : }
    5089                 : 
    5090                 : ///////////////////////////////////////////////////////////////////////////
    5091                 : // ExpandSelectionForDeletion: this promotes our selection to include blocks
    5092                 : // that have all their children selected.
    5093                 : //                  
    5094                 : nsresult
    5095               0 : nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
    5096                 : {
    5097               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    5098                 :   
    5099                 :   // don't need to touch collapsed selections
    5100                 :   bool bCollapsed;
    5101               0 :   nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
    5102               0 :   NS_ENSURE_SUCCESS(res, res);
    5103               0 :   if (bCollapsed) return res;
    5104                 : 
    5105                 :   PRInt32 rangeCount;
    5106               0 :   res = aSelection->GetRangeCount(&rangeCount);
    5107               0 :   NS_ENSURE_SUCCESS(res, res);
    5108                 :   
    5109                 :   // we don't need to mess with cell selections, and we assume multirange selections are those.
    5110               0 :   if (rangeCount != 1) return NS_OK;
    5111                 :   
    5112                 :   // find current sel start and end
    5113               0 :   nsCOMPtr<nsIDOMRange> range;
    5114               0 :   res = aSelection->GetRangeAt(0, getter_AddRefs(range));
    5115               0 :   NS_ENSURE_SUCCESS(res, res);
    5116               0 :   NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
    5117               0 :   nsCOMPtr<nsIDOMNode> selStartNode, selEndNode, selCommon;
    5118                 :   PRInt32 selStartOffset, selEndOffset;
    5119                 :   
    5120               0 :   res = range->GetStartContainer(getter_AddRefs(selStartNode));
    5121               0 :   NS_ENSURE_SUCCESS(res, res);
    5122               0 :   res = range->GetStartOffset(&selStartOffset);
    5123               0 :   NS_ENSURE_SUCCESS(res, res);
    5124               0 :   res = range->GetEndContainer(getter_AddRefs(selEndNode));
    5125               0 :   NS_ENSURE_SUCCESS(res, res);
    5126               0 :   res = range->GetEndOffset(&selEndOffset);
    5127               0 :   NS_ENSURE_SUCCESS(res, res);
    5128                 : 
    5129                 :   // find current selection common block parent
    5130               0 :   res = range->GetCommonAncestorContainer(getter_AddRefs(selCommon));
    5131               0 :   NS_ENSURE_SUCCESS(res, res);
    5132               0 :   if (!IsBlockNode(selCommon))
    5133               0 :     selCommon = nsHTMLEditor::GetBlockNodeParent(selCommon);
    5134                 : 
    5135                 :   // set up for loops and cache our root element
    5136               0 :   bool stillLooking = true;
    5137               0 :   nsCOMPtr<nsIDOMNode> visNode, firstBRParent;
    5138               0 :   PRInt32 visOffset=0, firstBROffset=0;
    5139                 :   PRInt16 wsType;
    5140               0 :   nsCOMPtr<nsIContent> rootContent = mHTMLEditor->GetActiveEditingHost();
    5141               0 :   nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent);
    5142               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
    5143                 : 
    5144                 :   // find previous visible thingy before start of selection
    5145               0 :   if ((selStartNode!=selCommon) && (selStartNode!=rootElement))
    5146                 :   {
    5147               0 :     while (stillLooking)
    5148                 :     {
    5149               0 :       nsWSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset);
    5150               0 :       res = wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(visNode), &visOffset, &wsType);
    5151               0 :       NS_ENSURE_SUCCESS(res, res);
    5152               0 :       if (wsType == nsWSRunObject::eThisBlock)
    5153                 :       {
    5154                 :         // we want to keep looking up.  But stop if we are crossing table element
    5155                 :         // boundaries, or if we hit the root.
    5156               0 :         if ( nsHTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) ||
    5157               0 :             (selCommon == wsObj.mStartReasonNode)                    ||
    5158               0 :             (rootElement == wsObj.mStartReasonNode) )
    5159                 :         {
    5160               0 :           stillLooking = false;
    5161                 :         }
    5162                 :         else
    5163                 :         { 
    5164               0 :           nsEditor::GetNodeLocation(wsObj.mStartReasonNode, address_of(selStartNode), &selStartOffset);
    5165                 :         }
    5166                 :       }
    5167                 :       else
    5168                 :       {
    5169               0 :         stillLooking = false;
    5170                 :       }
    5171                 :     }
    5172                 :   }
    5173                 :   
    5174               0 :   stillLooking = true;
    5175                 :   // find next visible thingy after end of selection
    5176               0 :   if ((selEndNode!=selCommon) && (selEndNode!=rootElement))
    5177                 :   {
    5178               0 :     while (stillLooking)
    5179                 :     {
    5180               0 :       nsWSRunObject wsObj(mHTMLEditor, selEndNode, selEndOffset);
    5181               0 :       res = wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(visNode), &visOffset, &wsType);
    5182               0 :       NS_ENSURE_SUCCESS(res, res);
    5183               0 :       if (wsType == nsWSRunObject::eBreak)
    5184                 :       {
    5185               0 :         if (mHTMLEditor->IsVisBreak(wsObj.mEndReasonNode))
    5186                 :         {
    5187               0 :           stillLooking = false;
    5188                 :         }
    5189                 :         else
    5190                 :         { 
    5191               0 :           if (!firstBRParent)
    5192                 :           {
    5193               0 :             firstBRParent = selEndNode;
    5194               0 :             firstBROffset = selEndOffset;
    5195                 :           }
    5196               0 :           nsEditor::GetNodeLocation(wsObj.mEndReasonNode, address_of(selEndNode), &selEndOffset);
    5197               0 :           ++selEndOffset;
    5198                 :         }
    5199                 :       }
    5200               0 :       else if (wsType == nsWSRunObject::eThisBlock)
    5201                 :       {
    5202                 :         // we want to keep looking up.  But stop if we are crossing table element
    5203                 :         // boundaries, or if we hit the root.
    5204               0 :         if ( nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) ||
    5205               0 :             (selCommon == wsObj.mEndReasonNode)                    ||
    5206               0 :             (rootElement == wsObj.mEndReasonNode) )
    5207                 :         {
    5208               0 :           stillLooking = false;
    5209                 :         }
    5210                 :         else
    5211                 :         { 
    5212               0 :           nsEditor::GetNodeLocation(wsObj.mEndReasonNode, address_of(selEndNode), &selEndOffset);
    5213               0 :           ++selEndOffset;
    5214                 :         }
    5215                 :        }
    5216                 :       else
    5217                 :       {
    5218               0 :         stillLooking = false;
    5219                 :       }
    5220                 :     }
    5221                 :   }
    5222                 :   // now set the selection to the new range
    5223               0 :   aSelection->Collapse(selStartNode, selStartOffset);
    5224                 :   
    5225                 :   // expand selection endpoint only if we didnt pass a br,
    5226                 :   // or if we really needed to pass that br (ie, its block is now 
    5227                 :   // totally selected)
    5228               0 :   bool doEndExpansion = true;
    5229               0 :   if (firstBRParent)
    5230                 :   {
    5231                 :     // find block node containing br
    5232               0 :     nsCOMPtr<nsIDOMNode> brBlock = firstBRParent;
    5233               0 :     if (!IsBlockNode(brBlock))
    5234               0 :       brBlock = nsHTMLEditor::GetBlockNodeParent(brBlock);
    5235               0 :     bool nodeBefore=false, nodeAfter=false;
    5236                 :     
    5237                 :     // create a range that represents expanded selection
    5238               0 :     nsRefPtr<nsRange> range = new nsRange();
    5239               0 :     res = range->SetStart(selStartNode, selStartOffset);
    5240               0 :     NS_ENSURE_SUCCESS(res, res);
    5241               0 :     res = range->SetEnd(selEndNode, selEndOffset);
    5242               0 :     NS_ENSURE_SUCCESS(res, res);
    5243                 :     
    5244                 :     // check if block is entirely inside range
    5245               0 :     nsCOMPtr<nsIContent> brContentBlock = do_QueryInterface(brBlock);
    5246               0 :     res = nsRange::CompareNodeToRange(brContentBlock, range, &nodeBefore, &nodeAfter);
    5247                 :     
    5248                 :     // if block isn't contained, forgo grabbing the br in the expanded selection
    5249               0 :     if (nodeBefore || nodeAfter)
    5250               0 :       doEndExpansion = false;
    5251                 :   }
    5252               0 :   if (doEndExpansion)
    5253                 :   {
    5254               0 :     res = aSelection->Extend(selEndNode, selEndOffset);
    5255                 :   }
    5256                 :   else
    5257                 :   {
    5258                 :     // only expand to just before br
    5259               0 :     res = aSelection->Extend(firstBRParent, firstBROffset);
    5260                 :   }
    5261                 :   
    5262               0 :   return res;
    5263                 : }
    5264                 : 
    5265                 : #ifdef XXX_DEAD_CODE
    5266                 : ///////////////////////////////////////////////////////////////////////////
    5267                 : // AtStartOfBlock: is node/offset at the start of the editable material in this block?
    5268                 : //                  
    5269                 : bool
    5270                 : nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
    5271                 : {
    5272                 :   nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
    5273                 :   if (nodeAsText && aOffset) return false;  // there are chars in front of us
    5274                 :   
    5275                 :   nsCOMPtr<nsIDOMNode> priorNode;
    5276                 :   nsresult  res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(priorNode));
    5277                 :   NS_ENSURE_SUCCESS(res, true);
    5278                 :   NS_ENSURE_TRUE(priorNode, true);
    5279                 :   nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(priorNode);
    5280                 :   if (blockParent && (blockParent == aBlock)) return false;
    5281                 :   return true;
    5282                 : }
    5283                 : 
    5284                 : 
    5285                 : ///////////////////////////////////////////////////////////////////////////
    5286                 : // AtEndOfBlock: is node/offset at the end of the editable material in this block?
    5287                 : //                  
    5288                 : bool
    5289                 : nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
    5290                 : {
    5291                 :   nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
    5292                 :   if (nodeAsText)   
    5293                 :   {
    5294                 :     PRUint32 strLength;
    5295                 :     nodeAsText->GetLength(&strLength);
    5296                 :     if ((PRInt32)strLength > aOffset) return false;  // there are chars in after us
    5297                 :   }
    5298                 :   nsCOMPtr<nsIDOMNode> nextNode;
    5299                 :   nsresult  res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nextNode));
    5300                 :   NS_ENSURE_SUCCESS(res, true);
    5301                 :   NS_ENSURE_TRUE(nextNode, true);
    5302                 :   nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(nextNode);
    5303                 :   if (blockParent && (blockParent == aBlock)) return false;
    5304                 :   return true;
    5305                 : }
    5306                 : 
    5307                 : 
    5308                 : ///////////////////////////////////////////////////////////////////////////
    5309                 : // CreateMozDiv: makes a div with type = _moz
    5310                 : //                       
    5311                 : nsresult
    5312                 : nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outDiv)
    5313                 : {
    5314                 :   NS_ENSURE_TRUE(inParent && outDiv, NS_ERROR_NULL_POINTER);
    5315                 :   nsAutoString divType= "div";
    5316                 :   *outDiv = nsnull;
    5317                 :   nsresult res = mHTMLEditor->CreateNode(divType, inParent, inOffset, getter_AddRefs(*outDiv));
    5318                 :   NS_ENSURE_SUCCESS(res, res);
    5319                 :   // give it special moz attr
    5320                 :   nsCOMPtr<nsIDOMElement> mozDivElem = do_QueryInterface(*outDiv);
    5321                 :   res = mHTMLEditor->SetAttribute(mozDivElem, "type", "_moz");
    5322                 :   NS_ENSURE_SUCCESS(res, res);
    5323                 :   res = AddTrailerBR(*outDiv);
    5324                 :   return res;
    5325                 : }
    5326                 : #endif    
    5327                 : 
    5328                 : 
    5329                 : ///////////////////////////////////////////////////////////////////////////
    5330                 : // NormalizeSelection:  tweak non-collapsed selections to be more "natural".
    5331                 : //    Idea here is to adjust selection endpoint so that they do not cross
    5332                 : //    breaks or block boundaries unless something editable beyond that boundary
    5333                 : //    is also selected.  This adjustment makes it much easier for the various
    5334                 : //    block operations to determine what nodes to act on.
    5335                 : //                       
    5336                 : nsresult 
    5337               0 : nsHTMLEditRules::NormalizeSelection(nsISelection *inSelection)
    5338                 : {
    5339               0 :   NS_ENSURE_TRUE(inSelection, NS_ERROR_NULL_POINTER);
    5340                 : 
    5341                 :   // don't need to touch collapsed selections
    5342                 :   bool bCollapsed;
    5343               0 :   nsresult res = inSelection->GetIsCollapsed(&bCollapsed);
    5344               0 :   NS_ENSURE_SUCCESS(res, res);
    5345               0 :   if (bCollapsed) return res;
    5346                 : 
    5347                 :   PRInt32 rangeCount;
    5348               0 :   res = inSelection->GetRangeCount(&rangeCount);
    5349               0 :   NS_ENSURE_SUCCESS(res, res);
    5350                 :   
    5351                 :   // we don't need to mess with cell selections, and we assume multirange selections are those.
    5352               0 :   if (rangeCount != 1) return NS_OK;
    5353                 :   
    5354               0 :   nsCOMPtr<nsIDOMRange> range;
    5355               0 :   res = inSelection->GetRangeAt(0, getter_AddRefs(range));
    5356               0 :   NS_ENSURE_SUCCESS(res, res);
    5357               0 :   NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
    5358               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    5359                 :   PRInt32 startOffset, endOffset;
    5360               0 :   nsCOMPtr<nsIDOMNode> newStartNode, newEndNode;
    5361                 :   PRInt32 newStartOffset, newEndOffset;
    5362                 :   
    5363               0 :   res = range->GetStartContainer(getter_AddRefs(startNode));
    5364               0 :   NS_ENSURE_SUCCESS(res, res);
    5365               0 :   res = range->GetStartOffset(&startOffset);
    5366               0 :   NS_ENSURE_SUCCESS(res, res);
    5367               0 :   res = range->GetEndContainer(getter_AddRefs(endNode));
    5368               0 :   NS_ENSURE_SUCCESS(res, res);
    5369               0 :   res = range->GetEndOffset(&endOffset);
    5370               0 :   NS_ENSURE_SUCCESS(res, res);
    5371                 :   
    5372                 :   // adjusted values default to original values
    5373               0 :   newStartNode = startNode; 
    5374               0 :   newStartOffset = startOffset;
    5375               0 :   newEndNode = endNode; 
    5376               0 :   newEndOffset = endOffset;
    5377                 :   
    5378                 :   // some locals we need for whitespace code
    5379               0 :   nsCOMPtr<nsIDOMNode> someNode;
    5380                 :   PRInt32 offset;
    5381                 :   PRInt16 wsType;
    5382                 : 
    5383                 :   // let the whitespace code do the heavy lifting
    5384               0 :   nsWSRunObject wsEndObj(mHTMLEditor, endNode, endOffset);
    5385                 :   // is there any intervening visible whitespace?  if so we can't push selection past that,
    5386                 :   // it would visibly change maening of users selection
    5387               0 :   res = wsEndObj.PriorVisibleNode(endNode, endOffset, address_of(someNode), &offset, &wsType);
    5388               0 :   NS_ENSURE_SUCCESS(res, res);
    5389               0 :   if ((wsType != nsWSRunObject::eText) && (wsType != nsWSRunObject::eNormalWS))
    5390                 :   {
    5391                 :     // eThisBlock and eOtherBlock conveniently distinquish cases
    5392                 :     // of going "down" into a block and "up" out of a block.
    5393               0 :     if (wsEndObj.mStartReason == nsWSRunObject::eOtherBlock) 
    5394                 :     {
    5395                 :       // endpoint is just after the close of a block.
    5396               0 :       nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetRightmostChild(wsEndObj.mStartReasonNode, true);
    5397               0 :       if (child)
    5398                 :       {
    5399               0 :         res = nsEditor::GetNodeLocation(child, address_of(newEndNode), &newEndOffset);
    5400               0 :         NS_ENSURE_SUCCESS(res, res);
    5401               0 :         ++newEndOffset; // offset *after* child
    5402                 :       }
    5403                 :       // else block is empty - we can leave selection alone here, i think.
    5404                 :     }
    5405               0 :     else if (wsEndObj.mStartReason == nsWSRunObject::eThisBlock)
    5406                 :     {
    5407                 :       // endpoint is just after start of this block
    5408               0 :       nsCOMPtr<nsIDOMNode> child;
    5409               0 :       res = mHTMLEditor->GetPriorHTMLNode(endNode, endOffset, address_of(child));
    5410               0 :       if (child)
    5411                 :       {
    5412               0 :         res = nsEditor::GetNodeLocation(child, address_of(newEndNode), &newEndOffset);
    5413               0 :         NS_ENSURE_SUCCESS(res, res);
    5414               0 :         ++newEndOffset; // offset *after* child
    5415                 :       }
    5416                 :       // else block is empty - we can leave selection alone here, i think.
    5417                 :     }
    5418               0 :     else if (wsEndObj.mStartReason == nsWSRunObject::eBreak)
    5419                 :     {                                       
    5420                 :       // endpoint is just after break.  lets adjust it to before it.
    5421               0 :       res = nsEditor::GetNodeLocation(wsEndObj.mStartReasonNode, address_of(newEndNode), &newEndOffset);
    5422               0 :       NS_ENSURE_SUCCESS(res, res);
    5423                 :     }
    5424                 :   }
    5425                 :   
    5426                 :   
    5427                 :   // similar dealio for start of range
    5428               0 :   nsWSRunObject wsStartObj(mHTMLEditor, startNode, startOffset);
    5429                 :   // is there any intervening visible whitespace?  if so we can't push selection past that,
    5430                 :   // it would visibly change maening of users selection
    5431               0 :   res = wsStartObj.NextVisibleNode(startNode, startOffset, address_of(someNode), &offset, &wsType);
    5432               0 :   NS_ENSURE_SUCCESS(res, res);
    5433               0 :   if ((wsType != nsWSRunObject::eText) && (wsType != nsWSRunObject::eNormalWS))
    5434                 :   {
    5435                 :     // eThisBlock and eOtherBlock conveniently distinquish cases
    5436                 :     // of going "down" into a block and "up" out of a block.
    5437               0 :     if (wsStartObj.mEndReason == nsWSRunObject::eOtherBlock) 
    5438                 :     {
    5439                 :       // startpoint is just before the start of a block.
    5440               0 :       nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetLeftmostChild(wsStartObj.mEndReasonNode, true);
    5441               0 :       if (child)
    5442                 :       {
    5443               0 :         res = nsEditor::GetNodeLocation(child, address_of(newStartNode), &newStartOffset);
    5444               0 :         NS_ENSURE_SUCCESS(res, res);
    5445                 :       }
    5446                 :       // else block is empty - we can leave selection alone here, i think.
    5447                 :     }
    5448               0 :     else if (wsStartObj.mEndReason == nsWSRunObject::eThisBlock)
    5449                 :     {
    5450                 :       // startpoint is just before end of this block
    5451               0 :       nsCOMPtr<nsIDOMNode> child;
    5452               0 :       res = mHTMLEditor->GetNextHTMLNode(startNode, startOffset, address_of(child));
    5453               0 :       if (child)
    5454                 :       {
    5455               0 :         res = nsEditor::GetNodeLocation(child, address_of(newStartNode), &newStartOffset);
    5456               0 :         NS_ENSURE_SUCCESS(res, res);
    5457                 :       }
    5458                 :       // else block is empty - we can leave selection alone here, i think.
    5459                 :     }
    5460               0 :     else if (wsStartObj.mEndReason == nsWSRunObject::eBreak)
    5461                 :     {                                       
    5462                 :       // startpoint is just before a break.  lets adjust it to after it.
    5463               0 :       res = nsEditor::GetNodeLocation(wsStartObj.mEndReasonNode, address_of(newStartNode), &newStartOffset);
    5464               0 :       NS_ENSURE_SUCCESS(res, res);
    5465               0 :       ++newStartOffset; // offset *after* break
    5466                 :     }
    5467                 :   }
    5468                 :   
    5469                 :   // there is a demented possiblity we have to check for.  We might have a very strange selection
    5470                 :   // that is not collapsed and yet does not contain any editable content, and satisfies some of the
    5471                 :   // above conditions that cause tweaking.  In this case we don't want to tweak the selection into
    5472                 :   // a block it was never in, etc.  There are a variety of strategies one might use to try to
    5473                 :   // detect these cases, but I think the most straightforward is to see if the adjusted locations
    5474                 :   // "cross" the old values: ie, new end before old start, or new start after old end.  If so 
    5475                 :   // then just leave things alone.
    5476                 :   
    5477                 :   PRInt16 comp;
    5478                 :   comp = nsContentUtils::ComparePoints(startNode, startOffset,
    5479               0 :                                        newEndNode, newEndOffset);
    5480               0 :   if (comp == 1) return NS_OK;  // new end before old start
    5481                 :   comp = nsContentUtils::ComparePoints(newStartNode, newStartOffset,
    5482               0 :                                        endNode, endOffset);
    5483               0 :   if (comp == 1) return NS_OK;  // new start after old end
    5484                 :   
    5485                 :   // otherwise set selection to new values.  
    5486               0 :   inSelection->Collapse(newStartNode, newStartOffset);
    5487               0 :   inSelection->Extend(newEndNode, newEndOffset);
    5488               0 :   return NS_OK;
    5489                 : }
    5490                 : 
    5491                 : 
    5492                 : ///////////////////////////////////////////////////////////////////////////
    5493                 : // GetPromotedPoint: figure out where a start or end point for a block
    5494                 : //                   operation really is
    5495                 : nsresult
    5496               0 : nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset, 
    5497                 :                                   PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset)
    5498                 : {
    5499               0 :   nsresult res = NS_OK;
    5500               0 :   nsCOMPtr<nsIDOMNode> nearNode, node = aNode;
    5501               0 :   nsCOMPtr<nsIDOMNode> parent = aNode;
    5502               0 :   PRInt32 pOffset, offset = aOffset;
    5503                 :   
    5504                 :   // default values
    5505               0 :   *outNode = node;
    5506               0 :   *outOffset = offset;
    5507                 : 
    5508                 :   // we do one thing for text actions, something else entirely for other actions
    5509               0 :   if (actionID == nsEditor::kOpInsertText ||
    5510                 :       actionID == nsEditor::kOpInsertIMEText ||
    5511                 :       actionID == nsEditor::kOpInsertBreak ||
    5512                 :       actionID == nsEditor::kOpDeleteText)
    5513                 :   {
    5514                 :     bool isSpace, isNBSP;
    5515               0 :     nsCOMPtr<nsIDOMNode> temp;
    5516                 :     // for text actions, we want to look backwards (or forwards, as appropriate)
    5517                 :     // for additional whitespace or nbsp's.  We may have to act on these later even though
    5518                 :     // they are outside of the initial selection.  Even if they are in another node!
    5519               0 :     if (aWhere == kStart)
    5520                 :     {
    5521               0 :       do
    5522                 :       {
    5523                 :         PRInt32 prevOffset;
    5524               0 :         res = mHTMLEditor->IsPrevCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &prevOffset);
    5525               0 :         NS_ENSURE_SUCCESS(res, res);
    5526               0 :         if (isSpace || isNBSP) {
    5527               0 :           node = temp;
    5528               0 :           offset = prevOffset;
    5529                 :         } else {
    5530               0 :           break;
    5531                 :         }
    5532               0 :       } while (node);
    5533                 : 
    5534               0 :       *outNode = node;
    5535               0 :       *outOffset = offset;
    5536                 :     }
    5537               0 :     else if (aWhere == kEnd)
    5538                 :     {
    5539               0 :       do
    5540                 :       {
    5541                 :         PRInt32 nextOffset;
    5542               0 :         res = mHTMLEditor->IsNextCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &nextOffset);
    5543               0 :         NS_ENSURE_SUCCESS(res, res);
    5544               0 :         if (isSpace || isNBSP) {
    5545               0 :           node = temp;
    5546               0 :           offset = nextOffset;
    5547                 :         } else {
    5548               0 :           break;
    5549                 :         }
    5550               0 :       } while (node);
    5551                 : 
    5552               0 :       *outNode = node;
    5553               0 :       *outOffset = offset;
    5554                 :     }
    5555               0 :     return res;
    5556                 :   }
    5557                 : 
    5558                 :   // else not a text section.  In this case we want to see if we should
    5559                 :   // grab any adjacent inline nodes and/or parents and other ancestors
    5560               0 :   if (aWhere == kStart)
    5561                 :   {
    5562                 :     // some special casing for text nodes
    5563               0 :     if (nsEditor::IsTextNode(aNode))  
    5564                 :     {
    5565               0 :       res = nsEditor::GetNodeLocation(aNode, address_of(node), &offset);
    5566               0 :       NS_ENSURE_SUCCESS(res, res);
    5567                 :     }
    5568                 : 
    5569                 :     // look back through any further inline nodes that
    5570                 :     // aren't across a <br> from us, and that are enclosed in the same block.
    5571               0 :     nsCOMPtr<nsIDOMNode> priorNode;
    5572               0 :     res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(priorNode), true);
    5573                 :       
    5574               0 :     while (priorNode && NS_SUCCEEDED(res))
    5575                 :     {
    5576               0 :       if (mHTMLEditor->IsVisBreak(priorNode))
    5577               0 :         break;
    5578               0 :       if (IsBlockNode(priorNode))
    5579               0 :         break;
    5580               0 :       res = nsEditor::GetNodeLocation(priorNode, address_of(node), &offset);
    5581               0 :       NS_ENSURE_SUCCESS(res, res);
    5582               0 :       res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(priorNode), true);
    5583               0 :       NS_ENSURE_SUCCESS(res, res);
    5584                 :     }
    5585                 :     
    5586                 :         
    5587                 :     // finding the real start for this point.  look up the tree for as long as we are the 
    5588                 :     // first node in the container, and as long as we haven't hit the body node.
    5589               0 :     res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(nearNode), true);
    5590               0 :     NS_ENSURE_SUCCESS(res, res);
    5591               0 :     while (!nearNode && !nsTextEditUtils::IsBody(node))
    5592                 :     {
    5593                 :       // some cutoffs are here: we don't need to also include them in the aWhere == kEnd case.
    5594                 :       // as long as they are in one or the other it will work.
    5595                 :       // special case for outdent: don't keep looking up 
    5596                 :       // if we have found a blockquote element to act on
    5597               0 :       if ((actionID == nsHTMLEditor::kOpOutdent) && nsHTMLEditUtils::IsBlockquote(node))
    5598               0 :         break;
    5599                 : 
    5600               0 :       res = nsEditor::GetNodeLocation(node, address_of(parent), &pOffset);
    5601               0 :       NS_ENSURE_SUCCESS(res, res);
    5602                 : 
    5603                 :       // Don't walk past the editable section. Note that we need to check
    5604                 :       // before walking up to a parent because we need to return the parent
    5605                 :       // object, so the parent itself might not be in the editable area, but
    5606                 :       // it's OK if we're not performing a block-level action.
    5607                 :       bool blockLevelAction = (actionID == nsHTMLEditor::kOpIndent)
    5608                 :                              || (actionID == nsHTMLEditor::kOpOutdent)
    5609                 :                              || (actionID == nsHTMLEditor::kOpAlign)
    5610               0 :                              || (actionID == nsHTMLEditor::kOpMakeBasicBlock);
    5611               0 :       if (!mHTMLEditor->IsNodeInActiveEditor(parent) &&
    5612               0 :           (blockLevelAction || !mHTMLEditor->IsNodeInActiveEditor(node))) {
    5613               0 :         break;
    5614                 :       }
    5615                 : 
    5616               0 :       node = parent;
    5617               0 :       offset = pOffset;
    5618               0 :       res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(nearNode), true);
    5619               0 :       NS_ENSURE_SUCCESS(res, res);
    5620                 :     } 
    5621               0 :     *outNode = node;
    5622               0 :     *outOffset = offset;
    5623               0 :     return res;
    5624                 :   }
    5625                 :   
    5626               0 :   if (aWhere == kEnd)
    5627                 :   {
    5628                 :     // some special casing for text nodes
    5629               0 :     if (nsEditor::IsTextNode(aNode))  
    5630                 :     {
    5631               0 :       res = nsEditor::GetNodeLocation(aNode, address_of(node), &offset);
    5632               0 :       NS_ENSURE_SUCCESS(res, res);
    5633               0 :       offset++; // want to be after the text node
    5634                 :     }
    5635                 : 
    5636                 :     // look ahead through any further inline nodes that
    5637                 :     // aren't across a <br> from us, and that are enclosed in the same block.
    5638               0 :     nsCOMPtr<nsIDOMNode> nextNode;
    5639               0 :     res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nextNode), true);
    5640                 :       
    5641               0 :     while (nextNode && NS_SUCCEEDED(res))
    5642                 :     {
    5643               0 :       if (IsBlockNode(nextNode))
    5644               0 :         break;
    5645               0 :       res = nsEditor::GetNodeLocation(nextNode, address_of(node), &offset);
    5646               0 :       NS_ENSURE_SUCCESS(res, res);
    5647               0 :       offset++;
    5648               0 :       if (mHTMLEditor->IsVisBreak(nextNode))
    5649               0 :         break;
    5650               0 :       res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nextNode), true);
    5651               0 :       NS_ENSURE_SUCCESS(res, res);
    5652                 :     }
    5653                 :     
    5654                 :     // finding the real end for this point.  look up the tree for as long as we are the 
    5655                 :     // last node in the container, and as long as we haven't hit the body node.
    5656               0 :     res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nearNode), true);
    5657               0 :     NS_ENSURE_SUCCESS(res, res);
    5658               0 :     while (!nearNode && !nsTextEditUtils::IsBody(node))
    5659                 :     {
    5660               0 :       res = nsEditor::GetNodeLocation(node, address_of(parent), &pOffset);
    5661               0 :       NS_ENSURE_SUCCESS(res, res);
    5662                 : 
    5663                 :       // Don't walk past the editable section. Note that we need to check
    5664                 :       // before walking up to a parent because we need to return the parent
    5665                 :       // object, so the parent itself might not be in the editable area, but
    5666                 :       // it's OK.
    5667               0 :       if (!mHTMLEditor->IsNodeInActiveEditor(node) &&
    5668               0 :           !mHTMLEditor->IsNodeInActiveEditor(parent)) {
    5669               0 :         break;
    5670                 :       }
    5671                 : 
    5672               0 :       node = parent;
    5673               0 :       offset = pOffset+1;  // we want to be AFTER nearNode
    5674               0 :       res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nearNode), true);
    5675               0 :       NS_ENSURE_SUCCESS(res, res);
    5676                 :     } 
    5677               0 :     *outNode = node;
    5678               0 :     *outOffset = offset;
    5679               0 :     return res;
    5680                 :   }
    5681                 :   
    5682               0 :   return res;
    5683                 : }
    5684                 : 
    5685                 : 
    5686                 : ///////////////////////////////////////////////////////////////////////////
    5687                 : // GetPromotedRanges: run all the selection range endpoint through 
    5688                 : //                    GetPromotedPoint()
    5689                 : //                       
    5690                 : nsresult 
    5691               0 : nsHTMLEditRules::GetPromotedRanges(nsISelection *inSelection, 
    5692                 :                                    nsCOMArray<nsIDOMRange> &outArrayOfRanges, 
    5693                 :                                    PRInt32 inOperationType)
    5694                 : {
    5695               0 :   NS_ENSURE_TRUE(inSelection, NS_ERROR_NULL_POINTER);
    5696                 : 
    5697                 :   PRInt32 rangeCount;
    5698               0 :   nsresult res = inSelection->GetRangeCount(&rangeCount);
    5699               0 :   NS_ENSURE_SUCCESS(res, res);
    5700                 :   
    5701                 :   PRInt32 i;
    5702               0 :   nsCOMPtr<nsIDOMRange> selectionRange;
    5703               0 :   nsCOMPtr<nsIDOMRange> opRange;
    5704                 : 
    5705               0 :   for (i = 0; i < rangeCount; i++)
    5706                 :   {
    5707               0 :     res = inSelection->GetRangeAt(i, getter_AddRefs(selectionRange));
    5708               0 :     NS_ENSURE_SUCCESS(res, res);
    5709                 : 
    5710                 :     // clone range so we don't muck with actual selection ranges
    5711               0 :     res = selectionRange->CloneRange(getter_AddRefs(opRange));
    5712               0 :     NS_ENSURE_SUCCESS(res, res);
    5713                 : 
    5714                 :     // make a new adjusted range to represent the appropriate block content.
    5715                 :     // The basic idea is to push out the range endpoints
    5716                 :     // to truly enclose the blocks that we will affect.
    5717                 :     // This call alters opRange.
    5718               0 :     res = PromoteRange(opRange, inOperationType);
    5719               0 :     NS_ENSURE_SUCCESS(res, res);
    5720                 :       
    5721                 :     // stuff new opRange into array
    5722               0 :     outArrayOfRanges.AppendObject(opRange);
    5723                 :   }
    5724               0 :   return res;
    5725                 : }
    5726                 : 
    5727                 : 
    5728                 : ///////////////////////////////////////////////////////////////////////////
    5729                 : // PromoteRange: expand a range to include any parents for which all
    5730                 : //               editable children are already in range. 
    5731                 : //                       
    5732                 : nsresult 
    5733               0 : nsHTMLEditRules::PromoteRange(nsIDOMRange *inRange, 
    5734                 :                               PRInt32 inOperationType)
    5735                 : {
    5736               0 :   NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
    5737                 :   nsresult res;
    5738               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    5739                 :   PRInt32 startOffset, endOffset;
    5740                 :   
    5741               0 :   res = inRange->GetStartContainer(getter_AddRefs(startNode));
    5742               0 :   NS_ENSURE_SUCCESS(res, res);
    5743               0 :   res = inRange->GetStartOffset(&startOffset);
    5744               0 :   NS_ENSURE_SUCCESS(res, res);
    5745               0 :   res = inRange->GetEndContainer(getter_AddRefs(endNode));
    5746               0 :   NS_ENSURE_SUCCESS(res, res);
    5747               0 :   res = inRange->GetEndOffset(&endOffset);
    5748               0 :   NS_ENSURE_SUCCESS(res, res);
    5749                 :   
    5750                 :   // MOOSE major hack:
    5751                 :   // GetPromotedPoint doesn't really do the right thing for collapsed ranges
    5752                 :   // inside block elements that contain nothing but a solo <br>.  It's easier
    5753                 :   // to put a workaround here than to revamp GetPromotedPoint.  :-(
    5754               0 :   if ( (startNode == endNode) && (startOffset == endOffset))
    5755                 :   {
    5756               0 :     nsCOMPtr<nsIDOMNode> block;
    5757               0 :     if (IsBlockNode(startNode)) 
    5758               0 :       block = startNode;
    5759                 :     else
    5760               0 :       block = mHTMLEditor->GetBlockNodeParent(startNode);
    5761               0 :     if (block)
    5762                 :     {
    5763               0 :       bool bIsEmptyNode = false;
    5764                 :       // check for the editing host
    5765               0 :       nsIContent *rootContent = mHTMLEditor->GetActiveEditingHost();
    5766               0 :       nsCOMPtr<nsINode> rootNode = do_QueryInterface(rootContent);
    5767               0 :       nsCOMPtr<nsINode> blockNode = do_QueryInterface(block);
    5768               0 :       NS_ENSURE_TRUE(rootNode && blockNode, NS_ERROR_UNEXPECTED);
    5769                 :       // Make sure we don't go higher than our root element in the content tree
    5770               0 :       if (!nsContentUtils::ContentIsDescendantOf(rootNode, blockNode))
    5771                 :       {
    5772               0 :         res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
    5773                 :       }
    5774               0 :       if (bIsEmptyNode)
    5775                 :       {
    5776                 :         PRUint32 numChildren;
    5777               0 :         nsEditor::GetLengthOfDOMNode(block, numChildren); 
    5778               0 :         startNode = block;
    5779               0 :         endNode = block;
    5780               0 :         startOffset = 0;
    5781               0 :         endOffset = numChildren;
    5782                 :       }
    5783                 :     }
    5784                 :   }
    5785                 : 
    5786                 :   // make a new adjusted range to represent the appropriate block content.
    5787                 :   // this is tricky.  the basic idea is to push out the range endpoints
    5788                 :   // to truly enclose the blocks that we will affect
    5789                 :   
    5790               0 :   nsCOMPtr<nsIDOMNode> opStartNode;
    5791               0 :   nsCOMPtr<nsIDOMNode> opEndNode;
    5792                 :   PRInt32 opStartOffset, opEndOffset;
    5793               0 :   nsCOMPtr<nsIDOMRange> opRange;
    5794                 :   
    5795               0 :   res = GetPromotedPoint( kStart, startNode, startOffset, inOperationType, address_of(opStartNode), &opStartOffset);
    5796               0 :   NS_ENSURE_SUCCESS(res, res);
    5797               0 :   res = GetPromotedPoint( kEnd, endNode, endOffset, inOperationType, address_of(opEndNode), &opEndOffset);
    5798               0 :   NS_ENSURE_SUCCESS(res, res);
    5799                 : 
    5800                 :   // Make sure that the new range ends up to be in the editable section.
    5801               0 :   if (!mHTMLEditor->IsNodeInActiveEditor(nsEditor::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
    5802               0 :       !mHTMLEditor->IsNodeInActiveEditor(nsEditor::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) {
    5803               0 :     return NS_OK;
    5804                 :   }
    5805                 : 
    5806               0 :   res = inRange->SetStart(opStartNode, opStartOffset);
    5807               0 :   NS_ENSURE_SUCCESS(res, res);
    5808               0 :   res = inRange->SetEnd(opEndNode, opEndOffset);
    5809               0 :   return res;
    5810                 : } 
    5811                 : 
    5812                 : class nsUniqueFunctor : public nsBoolDomIterFunctor
    5813                 : {
    5814                 : public:
    5815               0 :   nsUniqueFunctor(nsCOMArray<nsIDOMNode> &aArray) : mArray(aArray)
    5816                 :   {
    5817               0 :   }
    5818               0 :   virtual bool operator()(nsIDOMNode* aNode)  // used to build list of all nodes iterator covers
    5819                 :   {
    5820               0 :     return mArray.IndexOf(aNode) < 0;
    5821                 :   }
    5822                 : 
    5823                 : private:
    5824                 :   nsCOMArray<nsIDOMNode> &mArray;
    5825                 : };
    5826                 : 
    5827                 : ///////////////////////////////////////////////////////////////////////////
    5828                 : // GetNodesForOperation: run through the ranges in the array and construct 
    5829                 : //                       a new array of nodes to be acted on.
    5830                 : //                       
    5831                 : nsresult 
    5832               0 : nsHTMLEditRules::GetNodesForOperation(nsCOMArray<nsIDOMRange>& inArrayOfRanges, 
    5833                 :                                       nsCOMArray<nsIDOMNode>& outArrayOfNodes, 
    5834                 :                                       PRInt32 inOperationType,
    5835                 :                                       bool aDontTouchContent)
    5836                 : {
    5837               0 :   PRInt32 rangeCount = inArrayOfRanges.Count();
    5838                 :   
    5839                 :   PRInt32 i;
    5840               0 :   nsCOMPtr<nsIDOMRange> opRange;
    5841                 : 
    5842               0 :   nsresult res = NS_OK;
    5843                 :   
    5844                 :   // bust up any inlines that cross our range endpoints,
    5845                 :   // but only if we are allowed to touch content.
    5846                 :   
    5847               0 :   if (!aDontTouchContent)
    5848                 :   {
    5849               0 :     nsAutoTArray<nsRangeStore, 16> rangeItemArray;
    5850               0 :     if (!rangeItemArray.AppendElements(rangeCount)) {
    5851               0 :       return NS_ERROR_OUT_OF_MEMORY;
    5852                 :     }
    5853                 : 
    5854               0 :     NS_ASSERTION(static_cast<PRUint32>(rangeCount) == rangeItemArray.Length(),
    5855                 :                  "How did that happen?");
    5856                 : 
    5857                 :     // first register ranges for special editor gravity
    5858               0 :     for (i = 0; i < rangeCount; i++)
    5859                 :     {
    5860               0 :       opRange = inArrayOfRanges[0];
    5861               0 :       nsRangeStore *item = rangeItemArray.Elements() + i;
    5862               0 :       item->StoreRange(opRange);
    5863               0 :       mHTMLEditor->mRangeUpdater.RegisterRangeItem(item);
    5864               0 :       inArrayOfRanges.RemoveObjectAt(0);
    5865                 :     }    
    5866                 :     // now bust up inlines.  Safe to start at rangeCount-1, since we
    5867                 :     // asserted we have enough items above.
    5868               0 :     for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--)
    5869                 :     {
    5870               0 :       res = BustUpInlinesAtRangeEndpoints(rangeItemArray[i]);
    5871                 :     } 
    5872                 :     // then unregister the ranges
    5873               0 :     for (i = 0; i < rangeCount; i++)
    5874                 :     {
    5875               0 :       nsRangeStore *item = rangeItemArray.Elements() + i;
    5876               0 :       mHTMLEditor->mRangeUpdater.DropRangeItem(item);
    5877               0 :       nsRefPtr<nsRange> range;
    5878               0 :       nsresult res2 = item->GetRange(getter_AddRefs(range));
    5879               0 :       opRange = range;
    5880               0 :       if (NS_FAILED(res2) && NS_SUCCEEDED(res)) {
    5881                 :         // Remember the failure, but keep going so we make sure to unregister
    5882                 :         // all our range items.
    5883               0 :         res = res2;
    5884                 :       }
    5885               0 :       inArrayOfRanges.AppendObject(opRange);
    5886                 :     }
    5887               0 :     NS_ENSURE_SUCCESS(res, res);
    5888                 :   }
    5889                 :   // gather up a list of all the nodes
    5890               0 :   for (i = 0; i < rangeCount; i++)
    5891                 :   {
    5892               0 :     opRange = inArrayOfRanges[i];
    5893                 :     
    5894               0 :     nsDOMSubtreeIterator iter;
    5895               0 :     res = iter.Init(opRange);
    5896               0 :     NS_ENSURE_SUCCESS(res, res);
    5897               0 :     if (outArrayOfNodes.Count() == 0) {
    5898               0 :       nsTrivialFunctor functor;
    5899               0 :       res = iter.AppendList(functor, outArrayOfNodes);
    5900               0 :       NS_ENSURE_SUCCESS(res, res);    
    5901                 :     }
    5902                 :     else {
    5903                 :       // We don't want duplicates in outArrayOfNodes, so we use an
    5904                 :       // iterator/functor that only return nodes that are not already in
    5905                 :       // outArrayOfNodes.
    5906               0 :       nsCOMArray<nsIDOMNode> nodes;
    5907               0 :       nsUniqueFunctor functor(outArrayOfNodes);
    5908               0 :       res = iter.AppendList(functor, nodes);
    5909               0 :       NS_ENSURE_SUCCESS(res, res);
    5910               0 :       if (!outArrayOfNodes.AppendObjects(nodes))
    5911               0 :         return NS_ERROR_OUT_OF_MEMORY;
    5912                 :     }
    5913                 :   }    
    5914                 : 
    5915                 :   // certain operations should not act on li's and td's, but rather inside 
    5916                 :   // them.  alter the list as needed
    5917               0 :   if (inOperationType == kMakeBasicBlock)
    5918                 :   {
    5919               0 :     PRInt32 listCount = outArrayOfNodes.Count();
    5920               0 :     for (i=listCount-1; i>=0; i--)
    5921                 :     {
    5922               0 :       nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
    5923               0 :       if (nsHTMLEditUtils::IsListItem(node))
    5924                 :       {
    5925               0 :         PRInt32 j=i;
    5926               0 :         outArrayOfNodes.RemoveObjectAt(i);
    5927               0 :         res = GetInnerContent(node, outArrayOfNodes, &j);
    5928               0 :         NS_ENSURE_SUCCESS(res, res);
    5929                 :       }
    5930                 :     }
    5931                 :   }
    5932                 :   // indent/outdent already do something special for list items, but
    5933                 :   // we still need to make sure we don't act on table elements
    5934               0 :   else if ( (inOperationType == kOutdent)  ||
    5935                 :             (inOperationType == kIndent)   ||
    5936                 :             (inOperationType == kSetAbsolutePosition))
    5937                 :   {
    5938               0 :     PRInt32 listCount = outArrayOfNodes.Count();
    5939               0 :     for (i=listCount-1; i>=0; i--)
    5940                 :     {
    5941               0 :       nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
    5942               0 :       if (nsHTMLEditUtils::IsTableElementButNotTable(node))
    5943                 :       {
    5944               0 :         PRInt32 j=i;
    5945               0 :         outArrayOfNodes.RemoveObjectAt(i);
    5946               0 :         res = GetInnerContent(node, outArrayOfNodes, &j);
    5947               0 :         NS_ENSURE_SUCCESS(res, res);
    5948                 :       }
    5949                 :     }
    5950                 :   }
    5951                 :   // outdent should look inside of divs.
    5952               0 :   if (inOperationType == kOutdent && !mHTMLEditor->IsCSSEnabled()) 
    5953                 :   {
    5954               0 :     PRInt32 listCount = outArrayOfNodes.Count();
    5955               0 :     for (i=listCount-1; i>=0; i--)
    5956                 :     {
    5957               0 :       nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
    5958               0 :       if (nsHTMLEditUtils::IsDiv(node))
    5959                 :       {
    5960               0 :         PRInt32 j=i;
    5961               0 :         outArrayOfNodes.RemoveObjectAt(i);
    5962               0 :         res = GetInnerContent(node, outArrayOfNodes, &j, false, false);
    5963               0 :         NS_ENSURE_SUCCESS(res, res);
    5964                 :       }
    5965                 :     }
    5966                 :   }
    5967                 : 
    5968                 : 
    5969                 :   // post process the list to break up inline containers that contain br's.
    5970                 :   // but only for operations that might care, like making lists or para's...
    5971               0 :   if ( (inOperationType == kMakeBasicBlock)   ||
    5972                 :        (inOperationType == kMakeList)         ||
    5973                 :        (inOperationType == kAlign)            ||
    5974                 :        (inOperationType == kSetAbsolutePosition) ||
    5975                 :        (inOperationType == kIndent)           ||
    5976                 :        (inOperationType == kOutdent) )
    5977                 :   {
    5978               0 :     PRInt32 listCount = outArrayOfNodes.Count();
    5979               0 :     for (i=listCount-1; i>=0; i--)
    5980                 :     {
    5981               0 :       nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
    5982               0 :       if (!aDontTouchContent && IsInlineNode(node) 
    5983               0 :            && mHTMLEditor->IsContainer(node) && !mHTMLEditor->IsTextNode(node))
    5984                 :       {
    5985               0 :         nsCOMArray<nsIDOMNode> arrayOfInlines;
    5986               0 :         res = BustUpInlinesAtBRs(node, arrayOfInlines);
    5987               0 :         NS_ENSURE_SUCCESS(res, res);
    5988                 :         // put these nodes in outArrayOfNodes, replacing the current node
    5989               0 :         outArrayOfNodes.RemoveObjectAt(i);
    5990               0 :         outArrayOfNodes.InsertObjectsAt(arrayOfInlines, i);
    5991                 :       }
    5992                 :     }
    5993                 :   }
    5994               0 :   return res;
    5995                 : }
    5996                 : 
    5997                 : 
    5998                 : 
    5999                 : ///////////////////////////////////////////////////////////////////////////
    6000                 : // GetChildNodesForOperation: 
    6001                 : //                       
    6002                 : nsresult 
    6003               0 : nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode, 
    6004                 :                                            nsCOMArray<nsIDOMNode>& outArrayOfNodes)
    6005                 : {
    6006               0 :   NS_ENSURE_TRUE(inNode, NS_ERROR_NULL_POINTER);
    6007                 :   
    6008               0 :   nsCOMPtr<nsIDOMNodeList> childNodes;
    6009               0 :   nsresult res = inNode->GetChildNodes(getter_AddRefs(childNodes));
    6010               0 :   NS_ENSURE_SUCCESS(res, res);
    6011               0 :   NS_ENSURE_TRUE(childNodes, NS_ERROR_NULL_POINTER);
    6012                 :   PRUint32 childCount;
    6013               0 :   res = childNodes->GetLength(&childCount);
    6014               0 :   NS_ENSURE_SUCCESS(res, res);
    6015                 :   
    6016                 :   PRUint32 i;
    6017               0 :   nsCOMPtr<nsIDOMNode> node;
    6018               0 :   for (i = 0; i < childCount; i++)
    6019                 :   {
    6020               0 :     res = childNodes->Item( i, getter_AddRefs(node));
    6021               0 :     NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    6022               0 :     if (!outArrayOfNodes.AppendObject(node))
    6023               0 :       return NS_ERROR_FAILURE;
    6024                 :   }
    6025               0 :   return res;
    6026                 : }
    6027                 : 
    6028                 : 
    6029                 : 
    6030                 : ///////////////////////////////////////////////////////////////////////////
    6031                 : // GetListActionNodes: 
    6032                 : //                       
    6033                 : nsresult 
    6034               0 : nsHTMLEditRules::GetListActionNodes(nsCOMArray<nsIDOMNode> &outArrayOfNodes, 
    6035                 :                                     bool aEntireList,
    6036                 :                                     bool aDontTouchContent)
    6037                 : {
    6038               0 :   nsresult res = NS_OK;
    6039                 :   
    6040               0 :   nsCOMPtr<nsISelection>selection;
    6041               0 :   res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    6042               0 :   NS_ENSURE_SUCCESS(res, res);
    6043               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    6044               0 :   NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE);
    6045                 :   // added this in so that ui code can ask to change an entire list, even if selection
    6046                 :   // is only in part of it.  used by list item dialog.
    6047               0 :   if (aEntireList)
    6048                 :   {       
    6049               0 :     nsCOMPtr<nsIEnumerator> enumerator;
    6050               0 :     res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    6051               0 :     NS_ENSURE_SUCCESS(res, res);
    6052               0 :     NS_ENSURE_TRUE(enumerator, NS_ERROR_UNEXPECTED);
    6053                 : 
    6054               0 :     for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
    6055                 :     {
    6056               0 :       nsCOMPtr<nsISupports> currentItem;
    6057               0 :       res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    6058               0 :       NS_ENSURE_SUCCESS(res, res);
    6059               0 :       NS_ENSURE_TRUE(currentItem, NS_ERROR_UNEXPECTED);
    6060                 : 
    6061               0 :       nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    6062               0 :       nsCOMPtr<nsIDOMNode> commonParent, parent, tmp;
    6063               0 :       range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
    6064               0 :       if (commonParent)
    6065                 :       {
    6066               0 :         parent = commonParent;
    6067               0 :         while (parent)
    6068                 :         {
    6069               0 :           if (nsHTMLEditUtils::IsList(parent))
    6070                 :           {
    6071               0 :             outArrayOfNodes.AppendObject(parent);
    6072               0 :             break;
    6073                 :           }
    6074               0 :           parent->GetParentNode(getter_AddRefs(tmp));
    6075               0 :           parent = tmp;
    6076                 :         }
    6077                 :       }
    6078                 :     }
    6079                 :     // if we didn't find any nodes this way, then try the normal way.  perhaps the
    6080                 :     // selection spans multiple lists but with no common list parent.
    6081               0 :     if (outArrayOfNodes.Count()) return NS_OK;
    6082                 :   }
    6083                 : 
    6084                 :   {
    6085                 :     // We don't like other people messing with our selection!
    6086               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    6087                 : 
    6088                 :     // contruct a list of nodes to act on.
    6089               0 :     res = GetNodesFromSelection(selection, kMakeList, outArrayOfNodes, aDontTouchContent);
    6090               0 :     NS_ENSURE_SUCCESS(res, res);
    6091                 :   }
    6092                 :                
    6093                 :   // pre process our list of nodes...                      
    6094               0 :   PRInt32 listCount = outArrayOfNodes.Count();
    6095                 :   PRInt32 i;
    6096               0 :   for (i=listCount-1; i>=0; i--)
    6097                 :   {
    6098               0 :     nsCOMPtr<nsIDOMNode> testNode = outArrayOfNodes[i];
    6099                 : 
    6100                 :     // Remove all non-editable nodes.  Leave them be.
    6101               0 :     if (!mHTMLEditor->IsEditable(testNode))
    6102                 :     {
    6103               0 :       outArrayOfNodes.RemoveObjectAt(i);
    6104                 :     }
    6105                 :     
    6106                 :     // scan for table elements and divs.  If we find table elements other than table,
    6107                 :     // replace it with a list of any editable non-table content.
    6108               0 :     if (nsHTMLEditUtils::IsTableElementButNotTable(testNode))
    6109                 :     {
    6110               0 :       PRInt32 j=i;
    6111               0 :       outArrayOfNodes.RemoveObjectAt(i);
    6112               0 :       res = GetInnerContent(testNode, outArrayOfNodes, &j, false);
    6113               0 :       NS_ENSURE_SUCCESS(res, res);
    6114                 :     }
    6115                 :   }
    6116                 : 
    6117                 :   // if there is only one node in the array, and it is a list, div, or blockquote,
    6118                 :   // then look inside of it until we find inner list or content.
    6119               0 :   res = LookInsideDivBQandList(outArrayOfNodes);
    6120               0 :   return res;
    6121                 : }
    6122                 : 
    6123                 : 
    6124                 : ///////////////////////////////////////////////////////////////////////////
    6125                 : // LookInsideDivBQandList: 
    6126                 : //                       
    6127                 : nsresult 
    6128               0 : nsHTMLEditRules::LookInsideDivBQandList(nsCOMArray<nsIDOMNode>& aNodeArray)
    6129                 : {
    6130                 :   // if there is only one node in the array, and it is a list, div, or blockquote,
    6131                 :   // then look inside of it until we find inner list or content.
    6132               0 :   nsresult res = NS_OK;
    6133               0 :   PRInt32 listCount = aNodeArray.Count();
    6134               0 :   if (listCount == 1)
    6135                 :   {
    6136               0 :     nsCOMPtr<nsIDOMNode> curNode = aNodeArray[0];
    6137                 :     
    6138               0 :     while (nsHTMLEditUtils::IsDiv(curNode)
    6139               0 :            || nsHTMLEditUtils::IsList(curNode)
    6140               0 :            || nsHTMLEditUtils::IsBlockquote(curNode))
    6141                 :     {
    6142                 :       // dive as long as there is only one child, and it is a list, div, blockquote
    6143                 :       PRUint32 numChildren;
    6144               0 :       res = mHTMLEditor->CountEditableChildren(curNode, numChildren);
    6145               0 :       NS_ENSURE_SUCCESS(res, res);
    6146                 :       
    6147               0 :       if (numChildren == 1)
    6148                 :       {
    6149                 :         // keep diving
    6150               0 :         nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
    6151               0 :         if (nsHTMLEditUtils::IsDiv(tmpNode)
    6152               0 :             || nsHTMLEditUtils::IsList(tmpNode)
    6153               0 :             || nsHTMLEditUtils::IsBlockquote(tmpNode))
    6154                 :         {
    6155                 :           // check editablility XXX floppy moose
    6156               0 :           curNode = tmpNode;
    6157                 :         }
    6158                 :         else break;
    6159                 :       }
    6160               0 :       else break;
    6161                 :     }
    6162                 :     // we've found innermost list/blockquote/div: 
    6163                 :     // replace the one node in the array with these nodes
    6164               0 :     aNodeArray.RemoveObjectAt(0);
    6165               0 :     if ((nsHTMLEditUtils::IsDiv(curNode) || nsHTMLEditUtils::IsBlockquote(curNode)))
    6166                 :     {
    6167               0 :       PRInt32 j=0;
    6168               0 :       res = GetInnerContent(curNode, aNodeArray, &j, false, false);
    6169                 :     }
    6170                 :     else
    6171                 :     {
    6172               0 :       aNodeArray.AppendObject(curNode);
    6173                 :     }
    6174                 :   }
    6175               0 :   return res;
    6176                 : }
    6177                 : 
    6178                 : 
    6179                 : ///////////////////////////////////////////////////////////////////////////
    6180                 : // GetDefinitionListItemTypes: 
    6181                 : //                       
    6182                 : nsresult 
    6183               0 : nsHTMLEditRules::GetDefinitionListItemTypes(nsIDOMNode *aNode, bool &aDT, bool &aDD)
    6184                 : {
    6185               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    6186               0 :   aDT = aDD = false;
    6187               0 :   nsresult res = NS_OK;
    6188               0 :   nsCOMPtr<nsIDOMNode> child, temp;
    6189               0 :   res = aNode->GetFirstChild(getter_AddRefs(child));
    6190               0 :   while (child && NS_SUCCEEDED(res))
    6191                 :   {
    6192               0 :     if (nsEditor::NodeIsType(child, nsEditProperty::dt)) aDT = true;
    6193               0 :     else if (nsEditor::NodeIsType(child, nsEditProperty::dd)) aDD = true;
    6194               0 :     res = child->GetNextSibling(getter_AddRefs(temp));
    6195               0 :     child = temp;
    6196                 :   }
    6197               0 :   return res;
    6198                 : }
    6199                 : 
    6200                 : ///////////////////////////////////////////////////////////////////////////
    6201                 : // GetParagraphFormatNodes: 
    6202                 : //                       
    6203                 : nsresult 
    6204               0 : nsHTMLEditRules::GetParagraphFormatNodes(nsCOMArray<nsIDOMNode>& outArrayOfNodes,
    6205                 :                                          bool aDontTouchContent)
    6206                 : {  
    6207               0 :   nsCOMPtr<nsISelection>selection;
    6208               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    6209               0 :   NS_ENSURE_SUCCESS(res, res);
    6210                 : 
    6211                 :   // contruct a list of nodes to act on.
    6212               0 :   res = GetNodesFromSelection(selection, kMakeBasicBlock, outArrayOfNodes, aDontTouchContent);
    6213               0 :   NS_ENSURE_SUCCESS(res, res);
    6214                 : 
    6215                 :   // pre process our list of nodes...                      
    6216               0 :   PRInt32 listCount = outArrayOfNodes.Count();
    6217                 :   PRInt32 i;
    6218               0 :   for (i=listCount-1; i>=0; i--)
    6219                 :   {
    6220               0 :     nsCOMPtr<nsIDOMNode> testNode = outArrayOfNodes[i];
    6221                 : 
    6222                 :     // Remove all non-editable nodes.  Leave them be.
    6223               0 :     if (!mHTMLEditor->IsEditable(testNode))
    6224                 :     {
    6225               0 :       outArrayOfNodes.RemoveObjectAt(i);
    6226                 :     }
    6227                 :     
    6228                 :     // scan for table elements.  If we find table elements other than table,
    6229                 :     // replace it with a list of any editable non-table content.  Ditto for list elements.
    6230               0 :     if (nsHTMLEditUtils::IsTableElement(testNode) ||
    6231               0 :         nsHTMLEditUtils::IsList(testNode) || 
    6232               0 :         nsHTMLEditUtils::IsListItem(testNode) )
    6233                 :     {
    6234               0 :       PRInt32 j=i;
    6235               0 :       outArrayOfNodes.RemoveObjectAt(i);
    6236               0 :       res = GetInnerContent(testNode, outArrayOfNodes, &j);
    6237               0 :       NS_ENSURE_SUCCESS(res, res);
    6238                 :     }
    6239                 :   }
    6240               0 :   return res;
    6241                 : }
    6242                 : 
    6243                 : 
    6244                 : ///////////////////////////////////////////////////////////////////////////
    6245                 : // BustUpInlinesAtRangeEndpoints: 
    6246                 : //                       
    6247                 : nsresult 
    6248               0 : nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item)
    6249                 : {
    6250               0 :   nsresult res = NS_OK;
    6251               0 :   bool isCollapsed = ((item.startNode == item.endNode) && (item.startOffset == item.endOffset));
    6252                 : 
    6253               0 :   nsCOMPtr<nsIDOMNode> endInline = GetHighestInlineParent(item.endNode);
    6254                 :   
    6255                 :   // if we have inline parents above range endpoints, split them
    6256               0 :   if (endInline && !isCollapsed)
    6257                 :   {
    6258               0 :     nsCOMPtr<nsIDOMNode> resultEndNode;
    6259                 :     PRInt32 resultEndOffset;
    6260               0 :     endInline->GetParentNode(getter_AddRefs(resultEndNode));
    6261                 :     res = mHTMLEditor->SplitNodeDeep(endInline, item.endNode, item.endOffset,
    6262               0 :                           &resultEndOffset, true);
    6263               0 :     NS_ENSURE_SUCCESS(res, res);
    6264                 :     // reset range
    6265               0 :     item.endNode = resultEndNode; item.endOffset = resultEndOffset;
    6266                 :   }
    6267                 : 
    6268               0 :   nsCOMPtr<nsIDOMNode> startInline = GetHighestInlineParent(item.startNode);
    6269                 : 
    6270               0 :   if (startInline)
    6271                 :   {
    6272               0 :     nsCOMPtr<nsIDOMNode> resultStartNode;
    6273                 :     PRInt32 resultStartOffset;
    6274               0 :     startInline->GetParentNode(getter_AddRefs(resultStartNode));
    6275                 :     res = mHTMLEditor->SplitNodeDeep(startInline, item.startNode, item.startOffset,
    6276               0 :                           &resultStartOffset, true);
    6277               0 :     NS_ENSURE_SUCCESS(res, res);
    6278                 :     // reset range
    6279               0 :     item.startNode = resultStartNode; item.startOffset = resultStartOffset;
    6280                 :   }
    6281                 :   
    6282               0 :   return res;
    6283                 : }
    6284                 : 
    6285                 : 
    6286                 : 
    6287                 : ///////////////////////////////////////////////////////////////////////////
    6288                 : // BustUpInlinesAtBRs: 
    6289                 : //                       
    6290                 : nsresult 
    6291               0 : nsHTMLEditRules::BustUpInlinesAtBRs(nsIDOMNode *inNode, 
    6292                 :                                     nsCOMArray<nsIDOMNode>& outArrayOfNodes)
    6293                 : {
    6294               0 :   NS_ENSURE_TRUE(inNode, NS_ERROR_NULL_POINTER);
    6295                 : 
    6296                 :   // first step is to build up a list of all the break nodes inside 
    6297                 :   // the inline container.
    6298               0 :   nsCOMArray<nsIDOMNode> arrayOfBreaks;
    6299               0 :   nsBRNodeFunctor functor;
    6300               0 :   nsDOMIterator iter;
    6301               0 :   nsresult res = iter.Init(inNode);
    6302               0 :   NS_ENSURE_SUCCESS(res, res);
    6303               0 :   res = iter.AppendList(functor, arrayOfBreaks);
    6304               0 :   NS_ENSURE_SUCCESS(res, res);
    6305                 :   
    6306                 :   // if there aren't any breaks, just put inNode itself in the array
    6307               0 :   PRInt32 listCount = arrayOfBreaks.Count();
    6308               0 :   if (!listCount)
    6309                 :   {
    6310               0 :     if (!outArrayOfNodes.AppendObject(inNode))
    6311               0 :       return NS_ERROR_FAILURE;
    6312                 :   }
    6313                 :   else
    6314                 :   {
    6315                 :     // else we need to bust up inNode along all the breaks
    6316               0 :     nsCOMPtr<nsIDOMNode> breakNode;
    6317               0 :     nsCOMPtr<nsIDOMNode> inlineParentNode;
    6318               0 :     nsCOMPtr<nsIDOMNode> leftNode;
    6319               0 :     nsCOMPtr<nsIDOMNode> rightNode;
    6320               0 :     nsCOMPtr<nsIDOMNode> splitDeepNode = inNode;
    6321               0 :     nsCOMPtr<nsIDOMNode> splitParentNode;
    6322                 :     PRInt32 splitOffset, resultOffset, i;
    6323               0 :     inNode->GetParentNode(getter_AddRefs(inlineParentNode));
    6324                 :     
    6325               0 :     for (i=0; i< listCount; i++)
    6326                 :     {
    6327               0 :       breakNode = arrayOfBreaks[i];
    6328               0 :       NS_ENSURE_TRUE(breakNode, NS_ERROR_NULL_POINTER);
    6329               0 :       NS_ENSURE_TRUE(splitDeepNode, NS_ERROR_NULL_POINTER);
    6330               0 :       res = nsEditor::GetNodeLocation(breakNode, address_of(splitParentNode), &splitOffset);
    6331               0 :       NS_ENSURE_SUCCESS(res, res);
    6332                 :       res = mHTMLEditor->SplitNodeDeep(splitDeepNode, splitParentNode, splitOffset,
    6333               0 :                           &resultOffset, false, address_of(leftNode), address_of(rightNode));
    6334               0 :       NS_ENSURE_SUCCESS(res, res);
    6335                 :       // put left node in node list
    6336               0 :       if (leftNode)
    6337                 :       {
    6338                 :         // might not be a left node.  a break might have been at the very
    6339                 :         // beginning of inline container, in which case splitnodedeep
    6340                 :         // would not actually split anything
    6341               0 :         if (!outArrayOfNodes.AppendObject(leftNode))
    6342               0 :           return NS_ERROR_FAILURE;
    6343                 :       }
    6344                 :       // move break outside of container and also put in node list
    6345               0 :       res = mHTMLEditor->MoveNode(breakNode, inlineParentNode, resultOffset);
    6346               0 :       NS_ENSURE_SUCCESS(res, res);
    6347               0 :       if (!outArrayOfNodes.AppendObject(breakNode))
    6348               0 :         return  NS_ERROR_FAILURE;
    6349                 :       // now rightNode becomes the new node to split
    6350               0 :       splitDeepNode = rightNode;
    6351                 :     }
    6352                 :     // now tack on remaining rightNode, if any, to the list
    6353               0 :     if (rightNode)
    6354                 :     {
    6355               0 :       if (!outArrayOfNodes.AppendObject(rightNode))
    6356               0 :         return NS_ERROR_FAILURE;
    6357                 :     }
    6358                 :   }
    6359               0 :   return res;
    6360                 : }
    6361                 : 
    6362                 : 
    6363                 : nsCOMPtr<nsIDOMNode> 
    6364               0 : nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode)
    6365                 : {
    6366               0 :   NS_ENSURE_TRUE(aNode, nsnull);
    6367               0 :   if (IsBlockNode(aNode)) return nsnull;
    6368               0 :   nsCOMPtr<nsIDOMNode> inlineNode, node=aNode;
    6369                 : 
    6370               0 :   while (node && IsInlineNode(node))
    6371                 :   {
    6372               0 :     inlineNode = node;
    6373               0 :     inlineNode->GetParentNode(getter_AddRefs(node));
    6374                 :   }
    6375               0 :   return inlineNode;
    6376                 : }
    6377                 : 
    6378                 : 
    6379                 : ///////////////////////////////////////////////////////////////////////////
    6380                 : // GetNodesFromPoint: given a particular operation, construct a list  
    6381                 : //                     of nodes from a point that will be operated on. 
    6382                 : //                       
    6383                 : nsresult 
    6384               0 : nsHTMLEditRules::GetNodesFromPoint(DOMPoint point,
    6385                 :                                    PRInt32 operation,
    6386                 :                                    nsCOMArray<nsIDOMNode> &arrayOfNodes,
    6387                 :                                    bool dontTouchContent)
    6388                 : {
    6389                 :   nsresult res;
    6390                 : 
    6391                 :   // get our point
    6392               0 :   nsCOMPtr<nsIDOMNode> node;
    6393                 :   PRInt32 offset;
    6394               0 :   point.GetPoint(node, offset);
    6395                 :   
    6396                 :   // use it to make a range
    6397               0 :   nsRefPtr<nsRange> range = new nsRange();
    6398               0 :   res = range->SetStart(node, offset);
    6399               0 :   NS_ENSURE_SUCCESS(res, res);
    6400                 :   /* SetStart() will also set the end for this new range
    6401                 :   res = range->SetEnd(node, offset);
    6402                 :   NS_ENSURE_SUCCESS(res, res); */
    6403                 :   
    6404                 :   // expand the range to include adjacent inlines
    6405               0 :   res = PromoteRange(range, operation);
    6406               0 :   NS_ENSURE_SUCCESS(res, res);
    6407                 :       
    6408                 :   // make array of ranges
    6409               0 :   nsCOMArray<nsIDOMRange> arrayOfRanges;
    6410                 :   
    6411                 :   // stuff new opRange into array
    6412               0 :   arrayOfRanges.AppendObject(range);
    6413                 :   
    6414                 :   // use these ranges to contruct a list of nodes to act on.
    6415               0 :   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); 
    6416               0 :   return res;
    6417                 : }
    6418                 : 
    6419                 : 
    6420                 : ///////////////////////////////////////////////////////////////////////////
    6421                 : // GetNodesFromSelection: given a particular operation, construct a list  
    6422                 : //                     of nodes from the selection that will be operated on. 
    6423                 : //                       
    6424                 : nsresult 
    6425               0 : nsHTMLEditRules::GetNodesFromSelection(nsISelection *selection,
    6426                 :                                        PRInt32 operation,
    6427                 :                                        nsCOMArray<nsIDOMNode>& arrayOfNodes,
    6428                 :                                        bool dontTouchContent)
    6429                 : {
    6430               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    6431                 :   nsresult res;
    6432                 :   
    6433                 :   // promote selection ranges
    6434               0 :   nsCOMArray<nsIDOMRange> arrayOfRanges;
    6435               0 :   res = GetPromotedRanges(selection, arrayOfRanges, operation);
    6436               0 :   NS_ENSURE_SUCCESS(res, res);
    6437                 :   
    6438                 :   // use these ranges to contruct a list of nodes to act on.
    6439               0 :   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); 
    6440               0 :   return res;
    6441                 : }
    6442                 : 
    6443                 : 
    6444                 : ///////////////////////////////////////////////////////////////////////////
    6445                 : // MakeTransitionList: detect all the transitions in the array, where a 
    6446                 : //                     transition means that adjacent nodes in the array 
    6447                 : //                     don't have the same parent.
    6448                 : //                       
    6449                 : nsresult 
    6450               0 : nsHTMLEditRules::MakeTransitionList(nsCOMArray<nsIDOMNode>& inArrayOfNodes, 
    6451                 :                                     nsTArray<bool> &inTransitionArray)
    6452                 : {
    6453               0 :   PRUint32 listCount = inArrayOfNodes.Count();
    6454               0 :   inTransitionArray.EnsureLengthAtLeast(listCount);
    6455                 :   PRUint32 i;
    6456               0 :   nsCOMPtr<nsIDOMNode> prevElementParent;
    6457               0 :   nsCOMPtr<nsIDOMNode> curElementParent;
    6458                 :   
    6459               0 :   for (i=0; i<listCount; i++)
    6460                 :   {
    6461               0 :     nsIDOMNode* transNode = inArrayOfNodes[i];
    6462               0 :     transNode->GetParentNode(getter_AddRefs(curElementParent));
    6463               0 :     if (curElementParent != prevElementParent)
    6464                 :     {
    6465                 :       // different parents, or separated by <br>: transition point
    6466               0 :       inTransitionArray[i] = true;
    6467                 :     }
    6468                 :     else
    6469                 :     {
    6470                 :       // same parents: these nodes grew up together
    6471               0 :       inTransitionArray[i] = false;
    6472                 :     }
    6473               0 :     prevElementParent = curElementParent;
    6474                 :   }
    6475               0 :   return NS_OK;
    6476                 : }
    6477                 : 
    6478                 : 
    6479                 : 
    6480                 : /********************************************************
    6481                 :  *  main implementation methods 
    6482                 :  ********************************************************/
    6483                 :  
    6484                 : ///////////////////////////////////////////////////////////////////////////
    6485                 : // IsInListItem: if aNode is the descendant of a listitem, return that li.
    6486                 : //               But table element boundaries are stoppers on the search.
    6487                 : //               Also stops on the active editor host (contenteditable).
    6488                 : //               Also test if aNode is an li itself.
    6489                 : //                       
    6490                 : already_AddRefed<nsIDOMNode>
    6491               0 : nsHTMLEditRules::IsInListItem(nsIDOMNode* aNode)
    6492                 : {
    6493               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    6494               0 :   nsCOMPtr<nsIDOMNode> retval = do_QueryInterface(IsInListItem(node));
    6495               0 :   return retval.forget();
    6496                 : }
    6497                 : 
    6498                 : nsINode*
    6499               0 : nsHTMLEditRules::IsInListItem(nsINode* aNode)
    6500                 : {
    6501               0 :   NS_ENSURE_TRUE(aNode, nsnull);
    6502               0 :   if (aNode->IsElement() && nsHTMLEditUtils::IsListItem(aNode->AsElement())) {
    6503               0 :     return aNode;
    6504                 :   }
    6505                 : 
    6506               0 :   nsINode* parent = aNode->GetNodeParent();
    6507               0 :   while (parent && mHTMLEditor->IsNodeInActiveEditor(parent) &&
    6508               0 :          !(parent->IsElement() &&
    6509               0 :            nsHTMLEditUtils::IsTableElement(parent->AsElement()))) {
    6510               0 :     if (nsHTMLEditUtils::IsListItem(parent->AsElement())) {
    6511               0 :       return parent;
    6512                 :     }
    6513               0 :     parent = parent->GetNodeParent();
    6514                 :   }
    6515               0 :   return nsnull;
    6516                 : }
    6517                 : 
    6518                 : 
    6519                 : ///////////////////////////////////////////////////////////////////////////
    6520                 : // ReturnInHeader: do the right thing for returns pressed in headers
    6521                 : //                       
    6522                 : nsresult 
    6523               0 : nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection, 
    6524                 :                                 nsIDOMNode *aHeader, 
    6525                 :                                 nsIDOMNode *aNode, 
    6526                 :                                 PRInt32 aOffset)
    6527                 : {
    6528               0 :   NS_ENSURE_TRUE(aSelection && aHeader && aNode, NS_ERROR_NULL_POINTER);  
    6529                 :   
    6530                 :   // remeber where the header is
    6531               0 :   nsCOMPtr<nsIDOMNode> headerParent;
    6532                 :   PRInt32 offset;
    6533               0 :   nsresult res = nsEditor::GetNodeLocation(aHeader, address_of(headerParent), &offset);
    6534               0 :   NS_ENSURE_SUCCESS(res, res);
    6535                 : 
    6536                 :   // get ws code to adjust any ws
    6537               0 :   nsCOMPtr<nsIDOMNode> selNode = aNode;
    6538               0 :   res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset);
    6539               0 :   NS_ENSURE_SUCCESS(res, res);
    6540                 : 
    6541                 :   // split the header
    6542                 :   PRInt32 newOffset;
    6543               0 :   res = mHTMLEditor->SplitNodeDeep( aHeader, selNode, aOffset, &newOffset);
    6544               0 :   NS_ENSURE_SUCCESS(res, res);
    6545                 : 
    6546                 :   // if the leftand heading is empty, put a mozbr in it
    6547               0 :   nsCOMPtr<nsIDOMNode> prevItem;
    6548               0 :   mHTMLEditor->GetPriorHTMLSibling(aHeader, address_of(prevItem));
    6549               0 :   if (prevItem && nsHTMLEditUtils::IsHeader(prevItem))
    6550                 :   {
    6551                 :     bool bIsEmptyNode;
    6552               0 :     res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode);
    6553               0 :     NS_ENSURE_SUCCESS(res, res);
    6554               0 :     if (bIsEmptyNode)
    6555                 :     {
    6556               0 :       nsCOMPtr<nsIDOMNode> brNode;
    6557               0 :       res = CreateMozBR(prevItem, 0, address_of(brNode));
    6558               0 :       NS_ENSURE_SUCCESS(res, res);
    6559                 :     }
    6560                 :   }
    6561                 :   
    6562                 :   // if the new (righthand) header node is empty, delete it
    6563                 :   bool isEmpty;
    6564               0 :   res = IsEmptyBlock(aHeader, &isEmpty, true);
    6565               0 :   NS_ENSURE_SUCCESS(res, res);
    6566               0 :   if (isEmpty)
    6567                 :   {
    6568               0 :     res = mHTMLEditor->DeleteNode(aHeader);
    6569               0 :     NS_ENSURE_SUCCESS(res, res);
    6570                 :     // layout tells the caret to blink in a weird place
    6571                 :     // if we don't place a break after the header.
    6572               0 :     nsCOMPtr<nsIDOMNode> sibling;
    6573               0 :     res = mHTMLEditor->GetNextHTMLSibling(headerParent, offset+1, address_of(sibling));
    6574               0 :     NS_ENSURE_SUCCESS(res, res);
    6575               0 :     if (!sibling || !nsTextEditUtils::IsBreak(sibling))
    6576                 :     {
    6577                 :       // create a paragraph
    6578               0 :       NS_NAMED_LITERAL_STRING(pType, "p");
    6579               0 :       nsCOMPtr<nsIDOMNode> pNode;
    6580               0 :       res = mHTMLEditor->CreateNode(pType, headerParent, offset+1, getter_AddRefs(pNode));
    6581               0 :       NS_ENSURE_SUCCESS(res, res);
    6582                 : 
    6583                 :       // append a <br> to it
    6584               0 :       nsCOMPtr<nsIDOMNode> brNode;
    6585               0 :       res = mHTMLEditor->CreateBR(pNode, 0, address_of(brNode));
    6586               0 :       NS_ENSURE_SUCCESS(res, res);
    6587                 : 
    6588                 :       // set selection to before the break
    6589               0 :       res = aSelection->Collapse(pNode, 0);
    6590                 :     }
    6591                 :     else
    6592                 :     {
    6593               0 :       res = nsEditor::GetNodeLocation(sibling, address_of(headerParent), &offset);
    6594               0 :       NS_ENSURE_SUCCESS(res, res);
    6595                 :       // put selection after break
    6596               0 :       res = aSelection->Collapse(headerParent,offset+1);
    6597                 :     }
    6598                 :   }
    6599                 :   else
    6600                 :   {
    6601                 :     // put selection at front of righthand heading
    6602               0 :     res = aSelection->Collapse(aHeader,0);
    6603                 :   }
    6604               0 :   return res;
    6605                 : }
    6606                 : 
    6607                 : ///////////////////////////////////////////////////////////////////////////
    6608                 : // ReturnInParagraph: do the right thing for returns pressed in paragraphs
    6609                 : //                       
    6610                 : nsresult 
    6611               0 : nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, 
    6612                 :                                    nsIDOMNode *aPara, 
    6613                 :                                    nsIDOMNode *aNode, 
    6614                 :                                    PRInt32 aOffset,
    6615                 :                                    bool *aCancel,
    6616                 :                                    bool *aHandled)
    6617                 : {
    6618               0 :   if (!aSelection || !aPara || !aNode || !aCancel || !aHandled) 
    6619               0 :     { return NS_ERROR_NULL_POINTER; }
    6620               0 :   *aCancel = false;
    6621               0 :   *aHandled = false;
    6622                 : 
    6623               0 :   nsCOMPtr<nsIDOMNode> parent;
    6624                 :   PRInt32 offset;
    6625               0 :   nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
    6626               0 :   NS_ENSURE_SUCCESS(res, res);
    6627                 : 
    6628                 :   bool    doesCRCreateNewP;
    6629               0 :   res = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(&doesCRCreateNewP);
    6630               0 :   NS_ENSURE_SUCCESS(res, res);
    6631                 : 
    6632               0 :   bool newBRneeded = false;
    6633               0 :   nsCOMPtr<nsIDOMNode> sibling;
    6634                 : 
    6635               0 :   if (aNode == aPara && doesCRCreateNewP) {
    6636                 :     // we are at the edges of the block, newBRneeded not needed!
    6637               0 :     sibling = aNode;
    6638                 :   }
    6639               0 :   else if (mHTMLEditor->IsTextNode(aNode))
    6640                 :   {
    6641               0 :     nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aNode);
    6642                 :     PRUint32 strLength;
    6643               0 :     res = textNode->GetLength(&strLength);
    6644               0 :     NS_ENSURE_SUCCESS(res, res);
    6645                 :     
    6646                 :     // at beginning of text node?
    6647               0 :     if (!aOffset)
    6648                 :     {
    6649                 :       // is there a BR prior to it?
    6650               0 :       mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling));
    6651               0 :       if (!sibling ||
    6652               0 :           !mHTMLEditor->IsVisBreak(sibling) || nsTextEditUtils::HasMozAttr(sibling))
    6653                 :       {
    6654               0 :         newBRneeded = true;
    6655                 :       }
    6656                 :     }
    6657               0 :     else if (aOffset == (PRInt32)strLength)
    6658                 :     {
    6659                 :       // we're at the end of text node...
    6660                 :       // is there a BR after to it?
    6661               0 :       res = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling));
    6662               0 :       if (!sibling ||
    6663               0 :           !mHTMLEditor->IsVisBreak(sibling) || nsTextEditUtils::HasMozAttr(sibling)) 
    6664                 :       {
    6665               0 :         newBRneeded = true;
    6666               0 :         offset++;
    6667                 :       }
    6668                 :     }
    6669                 :     else
    6670                 :     {
    6671               0 :       if (doesCRCreateNewP)
    6672                 :       {
    6673               0 :         nsCOMPtr<nsIDOMNode> tmp;
    6674               0 :         res = mEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp));
    6675               0 :         NS_ENSURE_SUCCESS(res, res);
    6676               0 :         aNode = tmp;
    6677                 :       }
    6678                 : 
    6679               0 :       newBRneeded = true;
    6680               0 :       offset++;
    6681                 :     }
    6682                 :   }
    6683                 :   else
    6684                 :   {
    6685                 :     // not in a text node.  
    6686                 :     // is there a BR prior to it?
    6687               0 :     nsCOMPtr<nsIDOMNode> nearNode, selNode = aNode;
    6688               0 :     res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode));
    6689               0 :     NS_ENSURE_SUCCESS(res, res);
    6690               0 :     if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) 
    6691                 :     {
    6692                 :       // is there a BR after it?
    6693               0 :       res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode));
    6694               0 :       NS_ENSURE_SUCCESS(res, res);
    6695               0 :       if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) 
    6696                 :       {
    6697               0 :         newBRneeded = true;
    6698                 :       }
    6699                 :     }
    6700               0 :     if (!newBRneeded)
    6701               0 :       sibling = nearNode;
    6702                 :   }
    6703               0 :   if (newBRneeded)
    6704                 :   {
    6705                 :     // if CR does not create a new P, default to BR creation
    6706               0 :     NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK);
    6707                 : 
    6708               0 :     nsCOMPtr<nsIDOMNode> brNode;
    6709               0 :     res =  mHTMLEditor->CreateBR(parent, offset, address_of(brNode));
    6710               0 :     sibling = brNode;
    6711                 :   }
    6712               0 :   nsCOMPtr<nsIDOMNode> selNode = aNode;
    6713               0 :   *aHandled = true;
    6714               0 :   return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &aOffset);
    6715                 : }
    6716                 : 
    6717                 : ///////////////////////////////////////////////////////////////////////////
    6718                 : // SplitParagraph: split a paragraph at selection point, possibly deleting a br
    6719                 : //                       
    6720                 : nsresult 
    6721               0 : nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
    6722                 :                                 nsIDOMNode *aBRNode, 
    6723                 :                                 nsISelection *aSelection,
    6724                 :                                 nsCOMPtr<nsIDOMNode> *aSelNode, 
    6725                 :                                 PRInt32 *aOffset)
    6726                 : {
    6727               0 :   NS_ENSURE_TRUE(aPara && aBRNode && aSelNode && *aSelNode && aOffset && aSelection, NS_ERROR_NULL_POINTER);
    6728               0 :   nsresult res = NS_OK;
    6729                 :   
    6730                 :   // split para
    6731                 :   PRInt32 newOffset;
    6732                 :   // get ws code to adjust any ws
    6733               0 :   nsCOMPtr<nsIDOMNode> leftPara, rightPara;
    6734               0 :   res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, aSelNode, aOffset);
    6735               0 :   NS_ENSURE_SUCCESS(res, res);
    6736                 :   // split the paragraph
    6737                 :   res = mHTMLEditor->SplitNodeDeep(aPara, *aSelNode, *aOffset, &newOffset, false,
    6738               0 :                                    address_of(leftPara), address_of(rightPara));
    6739               0 :   NS_ENSURE_SUCCESS(res, res);
    6740                 :   // get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
    6741               0 :   if (mHTMLEditor->IsVisBreak(aBRNode))
    6742                 :   {
    6743               0 :     res = mHTMLEditor->DeleteNode(aBRNode);  
    6744               0 :     NS_ENSURE_SUCCESS(res, res);
    6745                 :   }
    6746                 : 
    6747                 :   // remove ID attribute on the paragraph we just created
    6748               0 :   nsCOMPtr<nsIDOMElement> rightElt = do_QueryInterface(rightPara);
    6749               0 :   res = mHTMLEditor->RemoveAttribute(rightElt, NS_LITERAL_STRING("id"));
    6750               0 :   NS_ENSURE_SUCCESS(res, res);
    6751                 : 
    6752                 :   // check both halves of para to see if we need mozBR
    6753               0 :   res = InsertMozBRIfNeeded(leftPara);
    6754               0 :   NS_ENSURE_SUCCESS(res, res);
    6755               0 :   res = InsertMozBRIfNeeded(rightPara);
    6756               0 :   NS_ENSURE_SUCCESS(res, res);
    6757                 : 
    6758                 :   // selection to beginning of right hand para;
    6759                 :   // look inside any containers that are up front.
    6760               0 :   nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetLeftmostChild(rightPara, true);
    6761               0 :   if (mHTMLEditor->IsTextNode(child) || mHTMLEditor->IsContainer(child))
    6762                 :   {
    6763               0 :     aSelection->Collapse(child,0);
    6764                 :   }
    6765                 :   else
    6766                 :   {
    6767               0 :     nsCOMPtr<nsIDOMNode> parent;
    6768                 :     PRInt32 offset;
    6769               0 :     res = nsEditor::GetNodeLocation(child, address_of(parent), &offset);
    6770               0 :     aSelection->Collapse(parent,offset);
    6771                 :   }
    6772               0 :   return res;
    6773                 : }
    6774                 : 
    6775                 : 
    6776                 : ///////////////////////////////////////////////////////////////////////////
    6777                 : // ReturnInListItem: do the right thing for returns pressed in list items
    6778                 : //                       
    6779                 : nsresult 
    6780               0 : nsHTMLEditRules::ReturnInListItem(nsISelection *aSelection, 
    6781                 :                                   nsIDOMNode *aListItem, 
    6782                 :                                   nsIDOMNode *aNode, 
    6783                 :                                   PRInt32 aOffset)
    6784                 : {
    6785               0 :   NS_ENSURE_TRUE(aSelection && aListItem && aNode, NS_ERROR_NULL_POINTER);
    6786               0 :   nsCOMPtr<nsISelection> selection(aSelection);
    6787               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    6788               0 :   nsresult res = NS_OK;
    6789                 :   
    6790               0 :   nsCOMPtr<nsIDOMNode> listitem;
    6791                 :   
    6792                 :   // sanity check
    6793               0 :   NS_PRECONDITION(true == nsHTMLEditUtils::IsListItem(aListItem),
    6794                 :                   "expected a list item and didn't get one");
    6795                 :   
    6796                 :   // get the listitem parent and the active editing host.
    6797               0 :   nsIContent* rootContent = mHTMLEditor->GetActiveEditingHost();
    6798               0 :   nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootContent);
    6799               0 :   nsCOMPtr<nsIDOMNode> list;
    6800                 :   PRInt32 itemOffset;
    6801               0 :   res = nsEditor::GetNodeLocation(aListItem, address_of(list), &itemOffset);
    6802               0 :   NS_ENSURE_SUCCESS(res, res);
    6803                 : 
    6804                 :   // if we are in an empty listitem, then we want to pop up out of the list
    6805                 :   // but only if prefs says it's ok and if the parent isn't the active editing host.
    6806                 :   bool isEmpty;
    6807               0 :   res = IsEmptyBlock(aListItem, &isEmpty, true, false);
    6808               0 :   NS_ENSURE_SUCCESS(res, res);
    6809               0 :   if (isEmpty && (rootNode != list) && mReturnInEmptyLIKillsList)
    6810                 :   {
    6811                 :     // get the list offset now -- before we might eventually split the list
    6812               0 :     nsCOMPtr<nsIDOMNode> listparent;
    6813                 :     PRInt32 offset;
    6814               0 :     res = nsEditor::GetNodeLocation(list, address_of(listparent), &offset);
    6815               0 :     NS_ENSURE_SUCCESS(res, res);
    6816                 : 
    6817                 :     // are we the last list item in the list?
    6818                 :     bool bIsLast;
    6819               0 :     res = mHTMLEditor->IsLastEditableChild(aListItem, &bIsLast);
    6820               0 :     NS_ENSURE_SUCCESS(res, res);
    6821               0 :     if (!bIsLast)
    6822                 :     {
    6823                 :       // we need to split the list!
    6824               0 :       nsCOMPtr<nsIDOMNode> tempNode;
    6825               0 :       res = mHTMLEditor->SplitNode(list, itemOffset, getter_AddRefs(tempNode));
    6826               0 :       NS_ENSURE_SUCCESS(res, res);
    6827                 :     }
    6828                 : 
    6829                 :     // are we in a sublist?
    6830               0 :     if (nsHTMLEditUtils::IsList(listparent))  //in a sublist
    6831                 :     {
    6832                 :       // if so, move this list item out of this list and into the grandparent list
    6833               0 :       res = mHTMLEditor->MoveNode(aListItem,listparent,offset+1);
    6834               0 :       NS_ENSURE_SUCCESS(res, res);
    6835               0 :       res = aSelection->Collapse(aListItem,0);
    6836                 :     }
    6837                 :     else
    6838                 :     {
    6839                 :       // otherwise kill this listitem
    6840               0 :       res = mHTMLEditor->DeleteNode(aListItem);
    6841               0 :       NS_ENSURE_SUCCESS(res, res);
    6842                 :       
    6843                 :       // time to insert a paragraph
    6844               0 :       NS_NAMED_LITERAL_STRING(pType, "p");
    6845               0 :       nsCOMPtr<nsIDOMNode> pNode;
    6846               0 :       res = mHTMLEditor->CreateNode(pType, listparent, offset+1, getter_AddRefs(pNode));
    6847               0 :       NS_ENSURE_SUCCESS(res, res);
    6848                 : 
    6849                 :       // append a <br> to it
    6850               0 :       nsCOMPtr<nsIDOMNode> brNode;
    6851               0 :       res = mHTMLEditor->CreateBR(pNode, 0, address_of(brNode));
    6852               0 :       NS_ENSURE_SUCCESS(res, res);
    6853                 : 
    6854                 :       // set selection to before the break
    6855               0 :       res = aSelection->Collapse(pNode, 0);
    6856                 :     }
    6857               0 :     return res;
    6858                 :   }
    6859                 :   
    6860                 :   // else we want a new list item at the same list level.
    6861                 :   // get ws code to adjust any ws
    6862               0 :   nsCOMPtr<nsIDOMNode> selNode = aNode;
    6863               0 :   res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset);
    6864               0 :   NS_ENSURE_SUCCESS(res, res);
    6865                 :   // now split list item
    6866                 :   PRInt32 newOffset;
    6867               0 :   res = mHTMLEditor->SplitNodeDeep( aListItem, selNode, aOffset, &newOffset, false);
    6868               0 :   NS_ENSURE_SUCCESS(res, res);
    6869                 :   // hack: until I can change the damaged doc range code back to being
    6870                 :   // extra inclusive, I have to manually detect certain list items that
    6871                 :   // may be left empty.
    6872               0 :   nsCOMPtr<nsIDOMNode> prevItem;
    6873               0 :   mHTMLEditor->GetPriorHTMLSibling(aListItem, address_of(prevItem));
    6874                 : 
    6875               0 :   if (prevItem && nsHTMLEditUtils::IsListItem(prevItem))
    6876                 :   {
    6877                 :     bool bIsEmptyNode;
    6878               0 :     res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode);
    6879               0 :     NS_ENSURE_SUCCESS(res, res);
    6880               0 :     if (bIsEmptyNode)
    6881                 :     {
    6882               0 :       nsCOMPtr<nsIDOMNode> brNode;
    6883               0 :       res = CreateMozBR(prevItem, 0, address_of(brNode));
    6884               0 :       NS_ENSURE_SUCCESS(res, res);
    6885                 :     }
    6886                 :     else 
    6887                 :     {
    6888               0 :       res = mHTMLEditor->IsEmptyNode(aListItem, &bIsEmptyNode, true);
    6889               0 :       NS_ENSURE_SUCCESS(res, res);
    6890               0 :       if (bIsEmptyNode) 
    6891                 :       {
    6892               0 :         nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(aListItem);
    6893               0 :         if (nodeAtom == nsEditProperty::dd || nodeAtom == nsEditProperty::dt)
    6894                 :         {
    6895               0 :           nsCOMPtr<nsIDOMNode> list;
    6896                 :           PRInt32 itemOffset;
    6897               0 :           res = nsEditor::GetNodeLocation(aListItem, address_of(list), &itemOffset);
    6898               0 :           NS_ENSURE_SUCCESS(res, res);
    6899                 : 
    6900               0 :           nsAutoString listTag((nodeAtom == nsEditProperty::dt) ? NS_LITERAL_STRING("dd") : NS_LITERAL_STRING("dt"));
    6901               0 :           nsCOMPtr<nsIDOMNode> newListItem;
    6902               0 :           res = mHTMLEditor->CreateNode(listTag, list, itemOffset+1, getter_AddRefs(newListItem));
    6903               0 :           NS_ENSURE_SUCCESS(res, res);
    6904               0 :           res = mEditor->DeleteNode(aListItem);
    6905               0 :           NS_ENSURE_SUCCESS(res, res);
    6906               0 :           return aSelection->Collapse(newListItem, 0);
    6907                 :         }
    6908                 : 
    6909               0 :         nsCOMPtr<nsIDOMNode> brNode;
    6910               0 :         res = mHTMLEditor->CopyLastEditableChildStyles(prevItem, aListItem, getter_AddRefs(brNode));
    6911               0 :         NS_ENSURE_SUCCESS(res, res);
    6912               0 :         if (brNode) 
    6913                 :         {
    6914               0 :           nsCOMPtr<nsIDOMNode> brParent;
    6915                 :           PRInt32 offset;
    6916               0 :           res = nsEditor::GetNodeLocation(brNode, address_of(brParent), &offset);
    6917               0 :           return aSelection->Collapse(brParent, offset);
    6918                 :         }
    6919                 :       }
    6920                 :       else
    6921                 :       {
    6922               0 :         nsWSRunObject wsObj(mHTMLEditor, aListItem, 0);
    6923               0 :         nsCOMPtr<nsIDOMNode> visNode;
    6924               0 :         PRInt32 visOffset = 0;
    6925                 :         PRInt16 wsType;
    6926               0 :         res = wsObj.NextVisibleNode(aListItem, 0, address_of(visNode), &visOffset, &wsType);
    6927               0 :         NS_ENSURE_SUCCESS(res, res);
    6928               0 :         if ( (wsType==nsWSRunObject::eSpecial)  || 
    6929                 :              (wsType==nsWSRunObject::eBreak)    ||
    6930               0 :              nsHTMLEditUtils::IsHR(visNode) ) 
    6931                 :         {
    6932               0 :           nsCOMPtr<nsIDOMNode> parent;
    6933                 :           PRInt32 offset;
    6934               0 :           res = nsEditor::GetNodeLocation(visNode, address_of(parent), &offset);
    6935               0 :           NS_ENSURE_SUCCESS(res, res);
    6936               0 :           return aSelection->Collapse(parent, offset);
    6937                 :         }
    6938                 :         else
    6939                 :         {
    6940               0 :           return aSelection->Collapse(visNode, visOffset);
    6941                 :         }
    6942                 :       }
    6943                 :     }
    6944                 :   }
    6945               0 :   res = aSelection->Collapse(aListItem,0);
    6946               0 :   return res;
    6947                 : }
    6948                 : 
    6949                 : 
    6950                 : ///////////////////////////////////////////////////////////////////////////
    6951                 : // MakeBlockquote:  put the list of nodes into one or more blockquotes.  
    6952                 : //                       
    6953                 : nsresult 
    6954               0 : nsHTMLEditRules::MakeBlockquote(nsCOMArray<nsIDOMNode>& arrayOfNodes)
    6955                 : {
    6956                 :   // the idea here is to put the nodes into a minimal number of 
    6957                 :   // blockquotes.  When the user blockquotes something, they expect
    6958                 :   // one blockquote.  That may not be possible (for instance, if they
    6959                 :   // have two table cells selected, you need two blockquotes inside the cells).
    6960                 :   
    6961               0 :   nsresult res = NS_OK;
    6962                 :   
    6963               0 :   nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
    6964                 :   PRInt32 offset;
    6965               0 :   PRInt32 listCount = arrayOfNodes.Count();
    6966                 :   
    6967               0 :   nsCOMPtr<nsIDOMNode> prevParent;
    6968                 :   
    6969                 :   PRInt32 i;
    6970               0 :   for (i=0; i<listCount; i++)
    6971                 :   {
    6972                 :     // get the node to act on, and its location
    6973               0 :     curNode = arrayOfNodes[i];
    6974               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    6975               0 :     NS_ENSURE_SUCCESS(res, res);
    6976                 : 
    6977                 :     // if the node is a table element or list item, dive inside
    6978               0 :     if (nsHTMLEditUtils::IsTableElementButNotTable(curNode) || 
    6979               0 :         nsHTMLEditUtils::IsListItem(curNode))
    6980                 :     {
    6981               0 :       curBlock = 0;  // forget any previous block
    6982                 :       // recursion time
    6983               0 :       nsCOMArray<nsIDOMNode> childArray;
    6984               0 :       res = GetChildNodesForOperation(curNode, childArray);
    6985               0 :       NS_ENSURE_SUCCESS(res, res);
    6986               0 :       res = MakeBlockquote(childArray);
    6987               0 :       NS_ENSURE_SUCCESS(res, res);
    6988                 :     }
    6989                 :     
    6990                 :     // if the node has different parent than previous node,
    6991                 :     // further nodes in a new parent
    6992               0 :     if (prevParent)
    6993                 :     {
    6994               0 :       nsCOMPtr<nsIDOMNode> temp;
    6995               0 :       curNode->GetParentNode(getter_AddRefs(temp));
    6996               0 :       if (temp != prevParent)
    6997                 :       {
    6998               0 :         curBlock = 0;  // forget any previous blockquote node we were using
    6999               0 :         prevParent = temp;
    7000                 :       }
    7001                 :     }
    7002                 :     else     
    7003                 : 
    7004                 :     {
    7005               0 :       curNode->GetParentNode(getter_AddRefs(prevParent));
    7006                 :     }
    7007                 :     
    7008                 :     // if no curBlock, make one
    7009               0 :     if (!curBlock)
    7010                 :     {
    7011               0 :       NS_NAMED_LITERAL_STRING(quoteType, "blockquote");
    7012               0 :       res = SplitAsNeeded(&quoteType, address_of(curParent), &offset);
    7013               0 :       NS_ENSURE_SUCCESS(res, res);
    7014               0 :       res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curBlock));
    7015               0 :       NS_ENSURE_SUCCESS(res, res);
    7016                 :       // remember our new block for postprocessing
    7017               0 :       mNewBlock = curBlock;
    7018                 :       // note: doesn't matter if we set mNewBlock multiple times.
    7019                 :     }
    7020                 :       
    7021               0 :     res = mHTMLEditor->MoveNode(curNode, curBlock, -1);
    7022               0 :     NS_ENSURE_SUCCESS(res, res);
    7023                 :   }
    7024               0 :   return res;
    7025                 : }
    7026                 : 
    7027                 : 
    7028                 : 
    7029                 : ///////////////////////////////////////////////////////////////////////////
    7030                 : // RemoveBlockStyle:  make the nodes have no special block type.  
    7031                 : //                       
    7032                 : nsresult 
    7033               0 : nsHTMLEditRules::RemoveBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes)
    7034                 : {
    7035                 :   // intent of this routine is to be used for converting to/from
    7036                 :   // headers, paragraphs, pre, and address.  Those blocks
    7037                 :   // that pretty much just contain inline things...
    7038                 :   
    7039               0 :   nsresult res = NS_OK;
    7040                 :   
    7041               0 :   nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, firstNode, lastNode;
    7042                 :   PRInt32 offset;
    7043               0 :   PRInt32 listCount = arrayOfNodes.Count();
    7044                 :     
    7045                 :   PRInt32 i;
    7046               0 :   for (i=0; i<listCount; i++)
    7047                 :   {
    7048                 :     // get the node to act on, and its location
    7049               0 :     curNode = arrayOfNodes[i];
    7050               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    7051               0 :     NS_ENSURE_SUCCESS(res, res);
    7052               0 :     nsAutoString curNodeTag, curBlockTag;
    7053               0 :     nsEditor::GetTagString(curNode, curNodeTag);
    7054               0 :     ToLowerCase(curNodeTag);
    7055                 :  
    7056                 :     // if curNode is a address, p, header, address, or pre, remove it 
    7057               0 :     if (nsHTMLEditUtils::IsFormatNode(curNode))
    7058                 :     {
    7059                 :       // process any partial progress saved
    7060               0 :       if (curBlock)
    7061                 :       {
    7062               0 :         res = RemovePartOfBlock(curBlock, firstNode, lastNode);
    7063               0 :         NS_ENSURE_SUCCESS(res, res);
    7064               0 :         curBlock = 0;  firstNode = 0;  lastNode = 0;
    7065                 :       }
    7066                 :       // remove curent block
    7067               0 :       res = mHTMLEditor->RemoveBlockContainer(curNode); 
    7068               0 :       NS_ENSURE_SUCCESS(res, res);
    7069                 :     }
    7070               0 :     else if (nsHTMLEditUtils::IsTable(curNode)                    || 
    7071               0 :              nsHTMLEditUtils::IsTableRow(curNode)                 ||
    7072               0 :              (curNodeTag.EqualsLiteral("tbody"))      ||
    7073               0 :              (curNodeTag.EqualsLiteral("td"))         ||
    7074               0 :              nsHTMLEditUtils::IsList(curNode)                     ||
    7075               0 :              (curNodeTag.EqualsLiteral("li"))         ||
    7076               0 :              nsHTMLEditUtils::IsBlockquote(curNode)               ||
    7077               0 :              nsHTMLEditUtils::IsDiv(curNode))
    7078                 :     {
    7079                 :       // process any partial progress saved
    7080               0 :       if (curBlock)
    7081                 :       {
    7082               0 :         res = RemovePartOfBlock(curBlock, firstNode, lastNode);
    7083               0 :         NS_ENSURE_SUCCESS(res, res);
    7084               0 :         curBlock = 0;  firstNode = 0;  lastNode = 0;
    7085                 :       }
    7086                 :       // recursion time
    7087               0 :       nsCOMArray<nsIDOMNode> childArray;
    7088               0 :       res = GetChildNodesForOperation(curNode, childArray);
    7089               0 :       NS_ENSURE_SUCCESS(res, res);
    7090               0 :       res = RemoveBlockStyle(childArray);
    7091               0 :       NS_ENSURE_SUCCESS(res, res);
    7092                 :     }
    7093               0 :     else if (IsInlineNode(curNode))
    7094                 :     {
    7095               0 :       if (curBlock)
    7096                 :       {
    7097                 :         // if so, is this node a descendant?
    7098               0 :         if (nsEditorUtils::IsDescendantOf(curNode, curBlock))
    7099                 :         {
    7100               0 :           lastNode = curNode;
    7101               0 :           continue;  // then we don't need to do anything different for this node
    7102                 :         }
    7103                 :         else
    7104                 :         {
    7105                 :           // otherwise, we have progressed beyond end of curBlock,
    7106                 :           // so lets handle it now.  We need to remove the portion of 
    7107                 :           // curBlock that contains [firstNode - lastNode].
    7108               0 :           res = RemovePartOfBlock(curBlock, firstNode, lastNode);
    7109               0 :           NS_ENSURE_SUCCESS(res, res);
    7110               0 :           curBlock = 0;  firstNode = 0;  lastNode = 0;
    7111                 :           // fall out and handle curNode
    7112                 :         }
    7113                 :       }
    7114               0 :       curBlock = mHTMLEditor->GetBlockNodeParent(curNode);
    7115               0 :       if (nsHTMLEditUtils::IsFormatNode(curBlock))
    7116                 :       {
    7117               0 :         firstNode = curNode;  
    7118               0 :         lastNode = curNode;
    7119                 :       }
    7120                 :       else
    7121               0 :         curBlock = 0;  // not a block kind that we care about.
    7122                 :     }
    7123                 :     else
    7124                 :     { // some node that is already sans block style.  skip over it and
    7125                 :       // process any partial progress saved
    7126               0 :       if (curBlock)
    7127                 :       {
    7128               0 :         res = RemovePartOfBlock(curBlock, firstNode, lastNode);
    7129               0 :         NS_ENSURE_SUCCESS(res, res);
    7130               0 :         curBlock = 0;  firstNode = 0;  lastNode = 0;
    7131                 :       }
    7132                 :     }
    7133                 :   }
    7134                 :   // process any partial progress saved
    7135               0 :   if (curBlock)
    7136                 :   {
    7137               0 :     res = RemovePartOfBlock(curBlock, firstNode, lastNode);
    7138               0 :     NS_ENSURE_SUCCESS(res, res);
    7139               0 :     curBlock = 0;  firstNode = 0;  lastNode = 0;
    7140                 :   }
    7141               0 :   return res;
    7142                 : }
    7143                 : 
    7144                 : 
    7145                 : ///////////////////////////////////////////////////////////////////////////
    7146                 : // ApplyBlockStyle:  do whatever it takes to make the list of nodes into 
    7147                 : //                   one or more blocks of type blockTag.  
    7148                 : //                       
    7149                 : nsresult 
    7150               0 : nsHTMLEditRules::ApplyBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes, const nsAString *aBlockTag)
    7151                 : {
    7152                 :   // intent of this routine is to be used for converting to/from
    7153                 :   // headers, paragraphs, pre, and address.  Those blocks
    7154                 :   // that pretty much just contain inline things...
    7155                 :   
    7156               0 :   NS_ENSURE_TRUE(aBlockTag, NS_ERROR_NULL_POINTER);
    7157               0 :   nsresult res = NS_OK;
    7158                 :   
    7159               0 :   nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
    7160                 :   PRInt32 offset;
    7161               0 :   PRInt32 listCount = arrayOfNodes.Count();
    7162               0 :   nsString tString(*aBlockTag);////MJUDGE SCC NEED HELP
    7163                 : 
    7164                 :   // Remove all non-editable nodes.  Leave them be.
    7165                 :   PRInt32 j;
    7166               0 :   for (j=listCount-1; j>=0; j--)
    7167                 :   {
    7168               0 :     if (!mHTMLEditor->IsEditable(arrayOfNodes[j]))
    7169                 :     {
    7170               0 :       arrayOfNodes.RemoveObjectAt(j);
    7171                 :     }
    7172                 :   }
    7173                 :   
    7174                 :   // reset list count
    7175               0 :   listCount = arrayOfNodes.Count();
    7176                 :   
    7177                 :   PRInt32 i;
    7178               0 :   for (i=0; i<listCount; i++)
    7179                 :   {
    7180                 :     // get the node to act on, and its location
    7181               0 :     curNode = arrayOfNodes[i];
    7182               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    7183               0 :     NS_ENSURE_SUCCESS(res, res);
    7184               0 :     nsAutoString curNodeTag;
    7185               0 :     nsEditor::GetTagString(curNode, curNodeTag);
    7186               0 :     ToLowerCase(curNodeTag);
    7187                 :  
    7188                 :     // is it already the right kind of block?
    7189               0 :     if (curNodeTag == *aBlockTag)
    7190                 :     {
    7191               0 :       curBlock = 0;  // forget any previous block used for previous inline nodes
    7192               0 :       continue;  // do nothing to this block
    7193                 :     }
    7194                 :         
    7195                 :     // if curNode is a address, p, header, address, or pre, replace 
    7196                 :     // it with a new block of correct type.
    7197                 :     // xxx floppy moose: pre can't hold everything the others can
    7198               0 :     if (nsHTMLEditUtils::IsMozDiv(curNode)     ||
    7199               0 :         nsHTMLEditUtils::IsFormatNode(curNode))
    7200                 :     {
    7201               0 :       curBlock = 0;  // forget any previous block used for previous inline nodes
    7202                 :       res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag,
    7203               0 :                                           nsnull, nsnull, true);
    7204               0 :       NS_ENSURE_SUCCESS(res, res);
    7205                 :     }
    7206               0 :     else if (nsHTMLEditUtils::IsTable(curNode)                    || 
    7207               0 :              (curNodeTag.EqualsLiteral("tbody"))      ||
    7208               0 :              (curNodeTag.EqualsLiteral("tr"))         ||
    7209               0 :              (curNodeTag.EqualsLiteral("td"))         ||
    7210               0 :              nsHTMLEditUtils::IsList(curNode)                     ||
    7211               0 :              (curNodeTag.EqualsLiteral("li"))         ||
    7212               0 :              nsHTMLEditUtils::IsBlockquote(curNode)               ||
    7213               0 :              nsHTMLEditUtils::IsDiv(curNode))
    7214                 :     {
    7215               0 :       curBlock = 0;  // forget any previous block used for previous inline nodes
    7216                 :       // recursion time
    7217               0 :       nsCOMArray<nsIDOMNode> childArray;
    7218               0 :       res = GetChildNodesForOperation(curNode, childArray);
    7219               0 :       NS_ENSURE_SUCCESS(res, res);
    7220               0 :       PRInt32 childCount = childArray.Count();
    7221               0 :       if (childCount)
    7222                 :       {
    7223               0 :         res = ApplyBlockStyle(childArray, aBlockTag);
    7224               0 :         NS_ENSURE_SUCCESS(res, res);
    7225                 :       }
    7226                 :       else
    7227                 :       {
    7228                 :         // make sure we can put a block here
    7229               0 :         res = SplitAsNeeded(aBlockTag, address_of(curParent), &offset);
    7230               0 :         NS_ENSURE_SUCCESS(res, res);
    7231               0 :         nsCOMPtr<nsIDOMNode> theBlock;
    7232               0 :         res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(theBlock));
    7233               0 :         NS_ENSURE_SUCCESS(res, res);
    7234                 :         // remember our new block for postprocessing
    7235               0 :         mNewBlock = theBlock;
    7236                 :       }
    7237                 :     }
    7238                 :     
    7239                 :     // if the node is a break, we honor it by putting further nodes in a new parent
    7240               0 :     else if (curNodeTag.EqualsLiteral("br"))
    7241                 :     {
    7242               0 :       if (curBlock)
    7243                 :       {
    7244               0 :         curBlock = 0;  // forget any previous block used for previous inline nodes
    7245               0 :         res = mHTMLEditor->DeleteNode(curNode);
    7246               0 :         NS_ENSURE_SUCCESS(res, res);
    7247                 :       }
    7248                 :       else
    7249                 :       {
    7250                 :         // the break is the first (or even only) node we encountered.  Create a
    7251                 :         // block for it.
    7252               0 :         res = SplitAsNeeded(aBlockTag, address_of(curParent), &offset);
    7253               0 :         NS_ENSURE_SUCCESS(res, res);
    7254               0 :         res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
    7255               0 :         NS_ENSURE_SUCCESS(res, res);
    7256                 :         // remember our new block for postprocessing
    7257               0 :         mNewBlock = curBlock;
    7258                 :         // note: doesn't matter if we set mNewBlock multiple times.
    7259               0 :         res = mHTMLEditor->MoveNode(curNode, curBlock, -1);
    7260               0 :         NS_ENSURE_SUCCESS(res, res);
    7261                 :       }
    7262                 :     }
    7263                 :         
    7264                 :     
    7265                 :     // if curNode is inline, pull it into curBlock
    7266                 :     // note: it's assumed that consecutive inline nodes in the 
    7267                 :     // arrayOfNodes are actually members of the same block parent.
    7268                 :     // this happens to be true now as a side effect of how
    7269                 :     // arrayOfNodes is contructed, but some additional logic should
    7270                 :     // be added here if that should change
    7271                 :     
    7272               0 :     else if (IsInlineNode(curNode))
    7273                 :     {
    7274                 :       // if curNode is a non editable, drop it if we are going to <pre>
    7275               0 :       if (tString.LowerCaseEqualsLiteral("pre") 
    7276               0 :         && (!mHTMLEditor->IsEditable(curNode)))
    7277               0 :         continue; // do nothing to this block
    7278                 :       
    7279                 :       // if no curBlock, make one
    7280               0 :       if (!curBlock)
    7281                 :       {
    7282               0 :         res = SplitAsNeeded(aBlockTag, address_of(curParent), &offset);
    7283               0 :         NS_ENSURE_SUCCESS(res, res);
    7284               0 :         res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
    7285               0 :         NS_ENSURE_SUCCESS(res, res);
    7286                 :         // remember our new block for postprocessing
    7287               0 :         mNewBlock = curBlock;
    7288                 :         // note: doesn't matter if we set mNewBlock multiple times.
    7289                 :       }
    7290                 :       
    7291                 :       // if curNode is a Break, replace it with a return if we are going to <pre>
    7292                 :       // xxx floppy moose
    7293                 :  
    7294                 :       // this is a continuation of some inline nodes that belong together in
    7295                 :       // the same block item.  use curBlock
    7296               0 :       res = mHTMLEditor->MoveNode(curNode, curBlock, -1);
    7297               0 :       NS_ENSURE_SUCCESS(res, res);
    7298                 :     }
    7299                 :   }
    7300               0 :   return res;
    7301                 : }
    7302                 : 
    7303                 : 
    7304                 : ///////////////////////////////////////////////////////////////////////////
    7305                 : // SplitAsNeeded:  given a tag name, split inOutParent up to the point   
    7306                 : //                 where we can insert the tag.  Adjust inOutParent and
    7307                 : //                 inOutOffset to pint to new location for tag.
    7308                 : nsresult 
    7309               0 : nsHTMLEditRules::SplitAsNeeded(const nsAString *aTag, 
    7310                 :                                nsCOMPtr<nsIDOMNode> *inOutParent,
    7311                 :                                PRInt32 *inOutOffset)
    7312                 : {
    7313               0 :   NS_ENSURE_TRUE(aTag && inOutParent && inOutOffset, NS_ERROR_NULL_POINTER);
    7314               0 :   NS_ENSURE_TRUE(*inOutParent, NS_ERROR_NULL_POINTER);
    7315               0 :   nsCOMPtr<nsIDOMNode> tagParent, temp, splitNode, parent = *inOutParent;
    7316               0 :   nsresult res = NS_OK;
    7317                 :    
    7318                 :   // check that we have a place that can legally contain the tag
    7319               0 :   while (!tagParent)
    7320                 :   {
    7321                 :     // sniffing up the parent tree until we find 
    7322                 :     // a legal place for the block
    7323               0 :     if (!parent) break;
    7324                 :     // Don't leave the active editing host
    7325               0 :     if (!mHTMLEditor->IsNodeInActiveEditor(parent)) {
    7326               0 :       nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
    7327               0 :       if (parentContent != mHTMLEditor->GetActiveEditingHost()) {
    7328                 :         break;
    7329                 :       }
    7330                 :     }
    7331               0 :     if (mHTMLEditor->CanContainTag(parent, *aTag))
    7332                 :     {
    7333               0 :       tagParent = parent;
    7334               0 :       break;
    7335                 :     }
    7336               0 :     splitNode = parent;
    7337               0 :     parent->GetParentNode(getter_AddRefs(temp));
    7338               0 :     parent = temp;
    7339                 :   }
    7340               0 :   if (!tagParent)
    7341                 :   {
    7342                 :     // could not find a place to build tag!
    7343               0 :     return NS_ERROR_FAILURE;
    7344                 :   }
    7345               0 :   if (splitNode)
    7346                 :   {
    7347                 :     // we found a place for block, but above inOutParent.  We need to split nodes.
    7348               0 :     res = mHTMLEditor->SplitNodeDeep(splitNode, *inOutParent, *inOutOffset, inOutOffset);
    7349               0 :     NS_ENSURE_SUCCESS(res, res);
    7350               0 :     *inOutParent = tagParent;
    7351                 :   }
    7352               0 :   return res;
    7353                 : }      
    7354                 : 
    7355                 : ///////////////////////////////////////////////////////////////////////////
    7356                 : // JoinNodesSmart:  join two nodes, doing whatever makes sense for their  
    7357                 : //                  children (which often means joining them, too).
    7358                 : //                  aNodeLeft & aNodeRight must be same type of node.
    7359                 : nsresult 
    7360               0 : nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft, 
    7361                 :                                  nsIDOMNode *aNodeRight, 
    7362                 :                                  nsCOMPtr<nsIDOMNode> *aOutMergeParent, 
    7363                 :                                  PRInt32 *aOutMergeOffset)
    7364                 : {
    7365                 :   // check parms
    7366               0 :   NS_ENSURE_TRUE(aNodeLeft &&  
    7367                 :       aNodeRight && 
    7368                 :       aOutMergeParent &&
    7369                 :       aOutMergeOffset, NS_ERROR_NULL_POINTER);
    7370                 :   
    7371               0 :   nsresult res = NS_OK;
    7372                 :   // caller responsible for:
    7373                 :   //   left & right node are same type
    7374                 :   PRInt32 parOffset;
    7375               0 :   nsCOMPtr<nsIDOMNode> parent, rightParent;
    7376               0 :   res = nsEditor::GetNodeLocation(aNodeLeft, address_of(parent), &parOffset);
    7377               0 :   NS_ENSURE_SUCCESS(res, res);
    7378               0 :   aNodeRight->GetParentNode(getter_AddRefs(rightParent));
    7379                 : 
    7380                 :   // if they don't have the same parent, first move the 'right' node 
    7381                 :   // to after the 'left' one
    7382               0 :   if (parent != rightParent)
    7383                 :   {
    7384               0 :     res = mHTMLEditor->MoveNode(aNodeRight, parent, parOffset);
    7385               0 :     NS_ENSURE_SUCCESS(res, res);
    7386                 :   }
    7387                 :   
    7388                 :   // defaults for outParams
    7389               0 :   *aOutMergeParent = aNodeRight;
    7390               0 :   res = mHTMLEditor->GetLengthOfDOMNode(aNodeLeft, *((PRUint32*)aOutMergeOffset));
    7391               0 :   NS_ENSURE_SUCCESS(res, res);
    7392                 : 
    7393                 :   // separate join rules for differing blocks
    7394               0 :   if (nsHTMLEditUtils::IsList(aNodeLeft) ||
    7395               0 :       mHTMLEditor->IsTextNode(aNodeLeft))
    7396                 :   {
    7397                 :     // for list's, merge shallow (wouldn't want to combine list items)
    7398               0 :     res = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight, parent);
    7399               0 :     NS_ENSURE_SUCCESS(res, res);
    7400               0 :     return res;
    7401                 :   }
    7402                 :   else
    7403                 :   {
    7404                 :     // remember the last left child, and firt right child
    7405               0 :     nsCOMPtr<nsIDOMNode> lastLeft, firstRight;
    7406               0 :     res = mHTMLEditor->GetLastEditableChild(aNodeLeft, address_of(lastLeft));
    7407               0 :     NS_ENSURE_SUCCESS(res, res);
    7408               0 :     res = mHTMLEditor->GetFirstEditableChild(aNodeRight, address_of(firstRight));
    7409               0 :     NS_ENSURE_SUCCESS(res, res);
    7410                 : 
    7411                 :     // for list items, divs, etc, merge smart
    7412               0 :     res = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight, parent);
    7413               0 :     NS_ENSURE_SUCCESS(res, res);
    7414                 : 
    7415               0 :     if (lastLeft && firstRight &&
    7416               0 :         mHTMLEditor->NodesSameType(lastLeft, firstRight) &&
    7417               0 :         (nsEditor::IsTextNode(lastLeft) ||
    7418               0 :          mHTMLEditor->mHTMLCSSUtils->ElementsSameStyle(lastLeft, firstRight)))
    7419               0 :       return JoinNodesSmart(lastLeft, firstRight, aOutMergeParent, aOutMergeOffset);
    7420                 :   }
    7421               0 :   return res;
    7422                 : }
    7423                 : 
    7424                 : 
    7425                 : nsresult 
    7426               0 : nsHTMLEditRules::GetTopEnclosingMailCite(nsIDOMNode *aNode, 
    7427                 :                                          nsCOMPtr<nsIDOMNode> *aOutCiteNode,
    7428                 :                                          bool aPlainText)
    7429                 : {
    7430                 :   // check parms
    7431               0 :   NS_ENSURE_TRUE(aNode && aOutCiteNode, NS_ERROR_NULL_POINTER);
    7432                 :   
    7433               0 :   nsresult res = NS_OK;
    7434               0 :   nsCOMPtr<nsIDOMNode> node, parentNode;
    7435               0 :   node = do_QueryInterface(aNode);
    7436                 :   
    7437               0 :   while (node)
    7438                 :   {
    7439               0 :     if ( (aPlainText && nsHTMLEditUtils::IsPre(node)) ||
    7440               0 :          nsHTMLEditUtils::IsMailCite(node) )
    7441               0 :       *aOutCiteNode = node;
    7442               0 :     if (nsTextEditUtils::IsBody(node)) break;
    7443                 :     
    7444               0 :     res = node->GetParentNode(getter_AddRefs(parentNode));
    7445               0 :     NS_ENSURE_SUCCESS(res, res);
    7446               0 :     node = parentNode;
    7447                 :   }
    7448                 : 
    7449               0 :   return res;
    7450                 : }
    7451                 : 
    7452                 : 
    7453                 : nsresult 
    7454               0 : nsHTMLEditRules::CacheInlineStyles(nsIDOMNode *aNode)
    7455                 : {
    7456               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    7457                 : 
    7458               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    7459                 : 
    7460               0 :   for (PRInt32 j = 0; j < SIZE_STYLE_TABLE; ++j)
    7461                 :   {
    7462               0 :     bool isSet = false;
    7463               0 :     nsAutoString outValue;
    7464               0 :     nsCOMPtr<nsIDOMNode> resultNode;
    7465               0 :     if (!useCSS)
    7466                 :     {
    7467                 :       mHTMLEditor->IsTextPropertySetByContent(aNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr), nsnull,
    7468               0 :                                isSet, getter_AddRefs(resultNode), &outValue);
    7469                 :     }
    7470                 :     else
    7471                 :     {
    7472                 :       mHTMLEditor->mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr),
    7473               0 :                                                     isSet, outValue, COMPUTED_STYLE_TYPE);
    7474                 :     }
    7475               0 :     if (isSet)
    7476                 :     {
    7477               0 :       mCachedStyles[j].mPresent = true;
    7478               0 :       mCachedStyles[j].value.Assign(outValue);
    7479                 :     }
    7480                 :   }
    7481               0 :   return NS_OK;
    7482                 : }
    7483                 : 
    7484                 : 
    7485                 : nsresult 
    7486               0 : nsHTMLEditRules::ReapplyCachedStyles()
    7487                 : {
    7488                 :   // The idea here is to examine our cached list of styles
    7489                 :   // and see if any have been removed.  If so, add typeinstate
    7490                 :   // for them, so that they will be reinserted when new 
    7491                 :   // content is added.
    7492                 :   
    7493                 :   // When we apply cached styles to TypeInState, we always want
    7494                 :   // to blow away prior TypeInState:
    7495               0 :   mHTMLEditor->mTypeInState->Reset();
    7496                 : 
    7497                 :   // remember if we are in css mode
    7498               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    7499                 : 
    7500                 :   // get selection point
    7501               0 :   nsCOMPtr<nsISelection>selection;
    7502               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    7503               0 :   NS_ENSURE_SUCCESS(res, res);
    7504               0 :   nsCOMPtr<nsIDOMNode> selNode;
    7505                 :   PRInt32 selOffset;
    7506               0 :   res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
    7507               0 :   NS_ENSURE_SUCCESS(res, res);
    7508                 : 
    7509               0 :   for (PRInt32 j = 0; j < SIZE_STYLE_TABLE; ++j)
    7510                 :   {
    7511               0 :     if (mCachedStyles[j].mPresent)
    7512                 :     {
    7513                 :       bool bFirst, bAny, bAll;
    7514               0 :       bFirst = bAny = bAll = false;
    7515                 :       
    7516               0 :       nsAutoString curValue;
    7517               0 :       if (useCSS) // check computed style first in css case
    7518                 :       {
    7519                 :         mHTMLEditor->mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(selNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr),
    7520               0 :                                                     bAny, curValue, COMPUTED_STYLE_TYPE);
    7521                 :       }
    7522               0 :       if (!bAny) // then check typeinstate and html style
    7523                 :       {
    7524                 :         res = mHTMLEditor->GetInlinePropertyBase(mCachedStyles[j].tag, &(mCachedStyles[j].attr), &(mCachedStyles[j].value), 
    7525               0 :                                                         &bFirst, &bAny, &bAll, &curValue, false);
    7526               0 :         NS_ENSURE_SUCCESS(res, res);
    7527                 :       }
    7528                 :       // this style has disappeared through deletion.  Add it onto our typeinstate:
    7529               0 :       if (!bAny) 
    7530                 :       {
    7531               0 :         mHTMLEditor->mTypeInState->SetProp(mCachedStyles[j].tag, mCachedStyles[j].attr, mCachedStyles[j].value);
    7532                 :       }
    7533                 :     }
    7534                 :   }
    7535               0 :   return NS_OK;
    7536                 : }
    7537                 : 
    7538                 : 
    7539                 : nsresult
    7540               0 : nsHTMLEditRules::ClearCachedStyles()
    7541                 : {
    7542                 :   // clear the mPresent bits in mCachedStyles array
    7543                 :   
    7544                 :   PRInt32 j;
    7545               0 :   for (j=0; j<SIZE_STYLE_TABLE; j++)
    7546                 :   {
    7547               0 :     mCachedStyles[j].mPresent = false;
    7548               0 :     mCachedStyles[j].value.Truncate(0);
    7549                 :   }
    7550               0 :   return NS_OK;
    7551                 : }
    7552                 : 
    7553                 : 
    7554                 : nsresult 
    7555               0 : nsHTMLEditRules::AdjustSpecialBreaks(bool aSafeToAskFrames)
    7556                 : {
    7557               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    7558               0 :   nsCOMPtr<nsISupports> isupports;
    7559                 :   PRInt32 nodeCount,j;
    7560                 :   
    7561                 :   // gather list of empty nodes
    7562               0 :   nsEmptyEditableFunctor functor(mHTMLEditor);
    7563               0 :   nsDOMIterator iter;
    7564               0 :   nsresult res = iter.Init(mDocChangeRange);
    7565               0 :   NS_ENSURE_SUCCESS(res, res);
    7566               0 :   res = iter.AppendList(functor, arrayOfNodes);
    7567               0 :   NS_ENSURE_SUCCESS(res, res);
    7568                 : 
    7569                 :   // put moz-br's into these empty li's and td's
    7570               0 :   nodeCount = arrayOfNodes.Count();
    7571               0 :   for (j = 0; j < nodeCount; j++)
    7572                 :   {
    7573                 :     // need to put br at END of node.  It may have
    7574                 :     // empty containers in it and still pass the "IsEmptynode" test,
    7575                 :     // and we want the br's to be after them.  Also, we want the br
    7576                 :     // to be after the selection if the selection is in this node.
    7577                 :     PRUint32 len;
    7578               0 :     nsCOMPtr<nsIDOMNode> brNode, theNode = arrayOfNodes[0];
    7579               0 :     arrayOfNodes.RemoveObjectAt(0);
    7580               0 :     res = nsEditor::GetLengthOfDOMNode(theNode, len);
    7581               0 :     NS_ENSURE_SUCCESS(res, res);
    7582               0 :     res = CreateMozBR(theNode, (PRInt32)len, address_of(brNode));
    7583               0 :     NS_ENSURE_SUCCESS(res, res);
    7584                 :   }
    7585                 :   
    7586               0 :   return res;
    7587                 : }
    7588                 : 
    7589                 : nsresult 
    7590               0 : nsHTMLEditRules::AdjustWhitespace(nsISelection *aSelection)
    7591                 : {
    7592                 :   // get selection point
    7593               0 :   nsCOMPtr<nsIDOMNode> selNode;
    7594                 :   PRInt32 selOffset;
    7595               0 :   nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    7596               0 :   NS_ENSURE_SUCCESS(res, res);
    7597                 :   
    7598                 :   // ask whitespace object to tweak nbsp's
    7599               0 :   return nsWSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace();
    7600                 : }
    7601                 : 
    7602                 : nsresult 
    7603               0 : nsHTMLEditRules::PinSelectionToNewBlock(nsISelection *aSelection)
    7604                 : {
    7605               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    7606                 :   bool bCollapsed;
    7607               0 :   nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
    7608               0 :   NS_ENSURE_SUCCESS(res, res);
    7609               0 :   if (!bCollapsed) {
    7610               0 :     return NS_OK;
    7611                 :   }
    7612                 : 
    7613                 :   // get the (collapsed) selection location
    7614               0 :   nsCOMPtr<nsIDOMNode> selNode, temp;
    7615                 :   PRInt32 selOffset;
    7616               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    7617               0 :   NS_ENSURE_SUCCESS(res, res);
    7618               0 :   temp = selNode;
    7619                 :   
    7620                 :   // use ranges and sRangeHelper to compare sel point to new block
    7621               0 :   nsRefPtr<nsRange> range = new nsRange();
    7622               0 :   res = range->SetStart(selNode, selOffset);
    7623               0 :   NS_ENSURE_SUCCESS(res, res);
    7624               0 :   res = range->SetEnd(selNode, selOffset);
    7625               0 :   NS_ENSURE_SUCCESS(res, res);
    7626               0 :   nsCOMPtr<nsIContent> block (do_QueryInterface(mNewBlock));
    7627               0 :   NS_ENSURE_TRUE(block, NS_ERROR_NO_INTERFACE);
    7628                 :   bool nodeBefore, nodeAfter;
    7629               0 :   res = nsRange::CompareNodeToRange(block, range, &nodeBefore, &nodeAfter);
    7630               0 :   NS_ENSURE_SUCCESS(res, res);
    7631                 :   
    7632               0 :   if (nodeBefore && nodeAfter)
    7633               0 :     return NS_OK;  // selection is inside block
    7634               0 :   else if (nodeBefore)
    7635                 :   {
    7636                 :     // selection is after block.  put at end of block.
    7637               0 :     nsCOMPtr<nsIDOMNode> tmp = mNewBlock;
    7638               0 :     mHTMLEditor->GetLastEditableChild(mNewBlock, address_of(tmp));
    7639                 :     PRUint32 endPoint;
    7640               0 :     if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp))
    7641                 :     {
    7642               0 :       res = nsEditor::GetLengthOfDOMNode(tmp, endPoint);
    7643               0 :       NS_ENSURE_SUCCESS(res, res);
    7644                 :     }
    7645                 :     else
    7646                 :     {
    7647               0 :       nsCOMPtr<nsIDOMNode> tmp2;
    7648               0 :       res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), (PRInt32*)&endPoint);
    7649               0 :       NS_ENSURE_SUCCESS(res, res);
    7650               0 :       tmp = tmp2;
    7651               0 :       endPoint++;  // want to be after this node
    7652                 :     }
    7653               0 :     return aSelection->Collapse(tmp, (PRInt32)endPoint);
    7654                 :   }
    7655                 :   else
    7656                 :   {
    7657                 :     // selection is before block.  put at start of block.
    7658               0 :     nsCOMPtr<nsIDOMNode> tmp = mNewBlock;
    7659               0 :     mHTMLEditor->GetFirstEditableChild(mNewBlock, address_of(tmp));
    7660                 :     PRInt32 offset;
    7661               0 :     if (!(mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)))
    7662                 :     {
    7663               0 :       nsCOMPtr<nsIDOMNode> tmp2;
    7664               0 :       res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), &offset);
    7665               0 :       NS_ENSURE_SUCCESS(res, res);
    7666               0 :       tmp = tmp2;
    7667                 :     }
    7668               0 :     return aSelection->Collapse(tmp, 0);
    7669                 :   }
    7670                 : }
    7671                 : 
    7672                 : nsresult 
    7673               0 : nsHTMLEditRules::CheckInterlinePosition(nsISelection *aSelection)
    7674                 : {
    7675               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    7676               0 :   nsCOMPtr<nsISelection> selection(aSelection);
    7677               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    7678                 : 
    7679                 :   // if the selection isn't collapsed, do nothing.
    7680                 :   bool bCollapsed;
    7681               0 :   nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
    7682               0 :   NS_ENSURE_SUCCESS(res, res);
    7683               0 :   if (!bCollapsed) {
    7684               0 :     return NS_OK;
    7685                 :   }
    7686                 : 
    7687                 :   // get the (collapsed) selection location
    7688               0 :   nsCOMPtr<nsIDOMNode> selNode, node;
    7689                 :   PRInt32 selOffset;
    7690               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    7691               0 :   NS_ENSURE_SUCCESS(res, res);
    7692                 :   
    7693                 :   // are we after a block?  If so try set caret to following content
    7694               0 :   mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(node));
    7695               0 :   if (node && IsBlockNode(node))
    7696                 :   {
    7697               0 :     selPriv->SetInterlinePosition(true);
    7698               0 :     return NS_OK;
    7699                 :   }
    7700                 : 
    7701                 :   // are we before a block?  If so try set caret to prior content
    7702               0 :   mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(node));
    7703               0 :   if (node && IsBlockNode(node))
    7704                 :   {
    7705               0 :     selPriv->SetInterlinePosition(false);
    7706               0 :     return NS_OK;
    7707                 :   }
    7708                 :   
    7709                 :   // are we after a <br>?  If so we want to stick to whatever is after <br>.
    7710               0 :   mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(node), true);
    7711               0 :   if (node && nsTextEditUtils::IsBreak(node))
    7712               0 :       selPriv->SetInterlinePosition(true);
    7713               0 :   return NS_OK;
    7714                 : }
    7715                 : 
    7716                 : nsresult 
    7717               0 : nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction)
    7718                 : {
    7719               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
    7720               0 :   nsCOMPtr<nsISelection> selection(aSelection);
    7721               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    7722                 :  
    7723                 :   // if the selection isn't collapsed, do nothing.
    7724                 :   // moose: one thing to do instead is check for the case of
    7725                 :   // only a single break selected, and collapse it.  Good thing?  Beats me.
    7726                 :   bool bCollapsed;
    7727               0 :   nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
    7728               0 :   NS_ENSURE_SUCCESS(res, res);
    7729               0 :   if (!bCollapsed) {
    7730               0 :     return NS_OK;
    7731                 :   }
    7732                 : 
    7733                 :   // get the (collapsed) selection location
    7734               0 :   nsCOMPtr<nsIDOMNode> selNode, temp;
    7735                 :   PRInt32 selOffset;
    7736               0 :   res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    7737               0 :   NS_ENSURE_SUCCESS(res, res);
    7738               0 :   temp = selNode;
    7739                 :   
    7740                 :   // are we in an editable node?
    7741               0 :   while (!mHTMLEditor->IsEditable(selNode))
    7742                 :   {
    7743                 :     // scan up the tree until we find an editable place to be
    7744               0 :     res = nsEditor::GetNodeLocation(temp, address_of(selNode), &selOffset);
    7745               0 :     NS_ENSURE_SUCCESS(res, res);
    7746               0 :     NS_ENSURE_TRUE(selNode, NS_ERROR_FAILURE);
    7747               0 :     temp = selNode;
    7748                 :   }
    7749                 :   
    7750                 :   // make sure we aren't in an empty block - user will see no cursor.  If this
    7751                 :   // is happening, put a <br> in the block if allowed.
    7752               0 :   nsCOMPtr<nsIDOMNode> theblock;
    7753               0 :   if (IsBlockNode(selNode)) theblock = selNode;
    7754               0 :   else theblock = mHTMLEditor->GetBlockNodeParent(selNode);
    7755               0 :   if (theblock && mHTMLEditor->IsEditable(theblock)) {
    7756                 :     bool bIsEmptyNode;
    7757               0 :     res = mHTMLEditor->IsEmptyNode(theblock, &bIsEmptyNode, false, false);
    7758               0 :     NS_ENSURE_SUCCESS(res, res);
    7759                 :     // check if br can go into the destination node
    7760               0 :     if (bIsEmptyNode && mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("br")))
    7761                 :     {
    7762               0 :       nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(mHTMLEditor->GetRoot());
    7763               0 :       NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
    7764               0 :       if (selNode == rootNode)
    7765                 :       {
    7766                 :         // Our root node is completely empty. Don't add a <br> here.
    7767                 :         // AfterEditInner() will add one for us when it calls
    7768                 :         // CreateBogusNodeIfNeeded()!
    7769               0 :         return NS_OK;
    7770                 :       }
    7771                 : 
    7772               0 :       nsCOMPtr<nsIDOMNode> brNode;
    7773                 :       // we know we can skip the rest of this routine given the cirumstance
    7774               0 :       return CreateMozBR(selNode, selOffset, address_of(brNode));
    7775                 :     }
    7776                 :   }
    7777                 :   
    7778                 :   // are we in a text node? 
    7779               0 :   nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
    7780               0 :   if (textNode)
    7781               0 :     return NS_OK; // we LIKE it when we are in a text node.  that RULZ
    7782                 :   
    7783                 :   // do we need to insert a special mozBR?  We do if we are:
    7784                 :   // 1) prior node is in same block where selection is AND
    7785                 :   // 2) prior node is a br AND
    7786                 :   // 3) that br is not visible
    7787                 : 
    7788               0 :   nsCOMPtr<nsIDOMNode> nearNode;
    7789               0 :   res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
    7790               0 :   NS_ENSURE_SUCCESS(res, res);
    7791               0 :   if (nearNode) 
    7792                 :   {
    7793                 :     // is nearNode also a descendant of same block?
    7794               0 :     nsCOMPtr<nsIDOMNode> block, nearBlock;
    7795               0 :     if (IsBlockNode(selNode)) block = selNode;
    7796               0 :     else block = mHTMLEditor->GetBlockNodeParent(selNode);
    7797               0 :     nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
    7798               0 :     if (block == nearBlock)
    7799                 :     {
    7800               0 :       if (nearNode && nsTextEditUtils::IsBreak(nearNode) )
    7801                 :       {   
    7802               0 :         if (!mHTMLEditor->IsVisBreak(nearNode))
    7803                 :         {
    7804                 :           // need to insert special moz BR. Why?  Because if we don't
    7805                 :           // the user will see no new line for the break.  Also, things
    7806                 :           // like table cells won't grow in height.
    7807               0 :           nsCOMPtr<nsIDOMNode> brNode;
    7808               0 :           res = CreateMozBR(selNode, selOffset, address_of(brNode));
    7809               0 :           NS_ENSURE_SUCCESS(res, res);
    7810               0 :           res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
    7811               0 :           NS_ENSURE_SUCCESS(res, res);
    7812                 :           // selection stays *before* moz-br, sticking to it
    7813               0 :           selPriv->SetInterlinePosition(true);
    7814               0 :           res = aSelection->Collapse(selNode,selOffset);
    7815               0 :           NS_ENSURE_SUCCESS(res, res);
    7816                 :         }
    7817                 :         else
    7818                 :         {
    7819               0 :           nsCOMPtr<nsIDOMNode> nextNode;
    7820               0 :           mHTMLEditor->GetNextHTMLNode(nearNode, address_of(nextNode), true);
    7821               0 :           if (nextNode && nsTextEditUtils::IsMozBR(nextNode))
    7822                 :           {
    7823                 :             // selection between br and mozbr.  make it stick to mozbr
    7824                 :             // so that it will be on blank line.   
    7825               0 :             selPriv->SetInterlinePosition(true);
    7826                 :           }
    7827                 :         }
    7828                 :       }
    7829                 :     }
    7830                 :   }
    7831                 : 
    7832                 :   // we aren't in a textnode: are we adjacent to text or a break or an image?
    7833               0 :   res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode), true);
    7834               0 :   NS_ENSURE_SUCCESS(res, res);
    7835               0 :   if (nearNode && (nsTextEditUtils::IsBreak(nearNode)
    7836               0 :                    || nsEditor::IsTextNode(nearNode)
    7837               0 :                    || nsHTMLEditUtils::IsImage(nearNode)
    7838               0 :                    || nsHTMLEditUtils::IsHR(nearNode)))
    7839               0 :     return NS_OK; // this is a good place for the caret to be
    7840               0 :   res = mHTMLEditor->GetNextHTMLNode(selNode, selOffset, address_of(nearNode), true);
    7841               0 :   NS_ENSURE_SUCCESS(res, res);
    7842               0 :   if (nearNode && (nsTextEditUtils::IsBreak(nearNode)
    7843               0 :                    || nsEditor::IsTextNode(nearNode)
    7844               0 :                    || nsHTMLEditUtils::IsImage(nearNode)
    7845               0 :                    || nsHTMLEditUtils::IsHR(nearNode)))
    7846               0 :     return NS_OK; // this is a good place for the caret to be
    7847                 : 
    7848                 :   // look for a nearby text node.
    7849                 :   // prefer the correct direction.
    7850               0 :   res = FindNearSelectableNode(selNode, selOffset, aAction, address_of(nearNode));
    7851               0 :   NS_ENSURE_SUCCESS(res, res);
    7852                 : 
    7853               0 :   if (nearNode)
    7854                 :   {
    7855                 :     // is the nearnode a text node?
    7856               0 :     textNode = do_QueryInterface(nearNode);
    7857               0 :     if (textNode)
    7858                 :     {
    7859               0 :       PRInt32 offset = 0;
    7860                 :       // put selection in right place:
    7861               0 :       if (aAction == nsIEditor::ePrevious)
    7862               0 :         textNode->GetLength((PRUint32*)&offset);
    7863               0 :       res = aSelection->Collapse(nearNode,offset);
    7864                 :     }
    7865                 :     else  // must be break or image
    7866                 :     {
    7867               0 :       res = nsEditor::GetNodeLocation(nearNode, address_of(selNode), &selOffset);
    7868               0 :       NS_ENSURE_SUCCESS(res, res);
    7869               0 :       if (aAction == nsIEditor::ePrevious) selOffset++;  // want to be beyond it if we backed up to it
    7870               0 :       res = aSelection->Collapse(selNode, selOffset);
    7871                 :     }
    7872                 :   }
    7873               0 :   return res;
    7874                 : }
    7875                 : 
    7876                 : 
    7877                 : nsresult
    7878               0 : nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode, 
    7879                 :                                         PRInt32 aSelOffset, 
    7880                 :                                         nsIEditor::EDirection &aDirection,
    7881                 :                                         nsCOMPtr<nsIDOMNode> *outSelectableNode)
    7882                 : {
    7883               0 :   NS_ENSURE_TRUE(aSelNode && outSelectableNode, NS_ERROR_NULL_POINTER);
    7884               0 :   *outSelectableNode = nsnull;
    7885               0 :   nsresult res = NS_OK;
    7886                 :   
    7887               0 :   nsCOMPtr<nsIDOMNode> nearNode, curNode;
    7888               0 :   if (aDirection == nsIEditor::ePrevious)
    7889               0 :     res = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
    7890                 :   else
    7891               0 :     res = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
    7892               0 :   NS_ENSURE_SUCCESS(res, res);
    7893                 :   
    7894               0 :   if (!nearNode) // try the other direction then
    7895                 :   {
    7896               0 :     if (aDirection == nsIEditor::ePrevious)
    7897               0 :       aDirection = nsIEditor::eNext;
    7898                 :     else
    7899               0 :       aDirection = nsIEditor::ePrevious;
    7900                 :     
    7901               0 :     if (aDirection == nsIEditor::ePrevious)
    7902               0 :       res = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
    7903                 :     else
    7904               0 :       res = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
    7905               0 :     NS_ENSURE_SUCCESS(res, res);
    7906                 :   }
    7907                 :   
    7908                 :   // scan in the right direction until we find an eligible text node,
    7909                 :   // but don't cross any breaks, images, or table elements.
    7910               0 :   while (nearNode && !(mHTMLEditor->IsTextNode(nearNode)
    7911               0 :                        || nsTextEditUtils::IsBreak(nearNode)
    7912               0 :                        || nsHTMLEditUtils::IsImage(nearNode)))
    7913                 :   {
    7914               0 :     curNode = nearNode;
    7915               0 :     if (aDirection == nsIEditor::ePrevious)
    7916               0 :       res = mHTMLEditor->GetPriorHTMLNode(curNode, address_of(nearNode));
    7917                 :     else
    7918               0 :       res = mHTMLEditor->GetNextHTMLNode(curNode, address_of(nearNode));
    7919               0 :     NS_ENSURE_SUCCESS(res, res);
    7920                 :   }
    7921                 :   
    7922               0 :   if (nearNode)
    7923                 :   {
    7924                 :     // don't cross any table elements
    7925                 :     bool bInDifTblElems;
    7926               0 :     res = InDifferentTableElements(nearNode, aSelNode, &bInDifTblElems);
    7927               0 :     NS_ENSURE_SUCCESS(res, res);
    7928               0 :     if (bInDifTblElems) return NS_OK;  
    7929                 :     
    7930                 :     // otherwise, ok, we have found a good spot to put the selection
    7931               0 :     *outSelectableNode = do_QueryInterface(nearNode);
    7932                 :   }
    7933               0 :   return res;
    7934                 : }
    7935                 : 
    7936                 : 
    7937                 : nsresult
    7938               0 : nsHTMLEditRules::InDifferentTableElements(nsIDOMNode *aNode1, nsIDOMNode *aNode2, bool *aResult)
    7939                 : {
    7940               0 :   NS_ASSERTION(aNode1 && aNode2 && aResult, "null args");
    7941               0 :   NS_ENSURE_TRUE(aNode1 && aNode2 && aResult, NS_ERROR_NULL_POINTER);
    7942                 : 
    7943               0 :   nsCOMPtr<nsIDOMNode> tn1, tn2, node = aNode1, temp;
    7944               0 :   *aResult = false;
    7945                 :   
    7946               0 :   while (node && !nsHTMLEditUtils::IsTableElement(node))
    7947                 :   {
    7948               0 :     node->GetParentNode(getter_AddRefs(temp));
    7949               0 :     node = temp;
    7950                 :   }
    7951               0 :   tn1 = node;
    7952                 :   
    7953               0 :   node = aNode2;
    7954               0 :   while (node && !nsHTMLEditUtils::IsTableElement(node))
    7955                 :   {
    7956               0 :     node->GetParentNode(getter_AddRefs(temp));
    7957               0 :     node = temp;
    7958                 :   }
    7959               0 :   tn2 = node;
    7960                 :   
    7961               0 :   *aResult = (tn1 != tn2);
    7962                 :   
    7963               0 :   return NS_OK;
    7964                 : }
    7965                 : 
    7966                 : 
    7967                 : nsresult 
    7968               0 : nsHTMLEditRules::RemoveEmptyNodes()
    7969                 : {
    7970               0 :   nsCOMArray<nsIDOMNode> arrayOfEmptyNodes, arrayOfEmptyCites;
    7971               0 :   nsCOMPtr<nsISupports> isupports;
    7972                 :   PRInt32 nodeCount,j;
    7973                 :   
    7974                 :   // some general notes on the algorithm used here: the goal is to examine all the
    7975                 :   // nodes in mDocChangeRange, and remove the empty ones.  We do this by using a
    7976                 :   // content iterator to traverse all the nodes in the range, and placing the empty
    7977                 :   // nodes into an array.  After finishing the iteration, we delete the empty nodes
    7978                 :   // in the array.  (they cannot be deleted as we find them becasue that would 
    7979                 :   // invalidate the iterator.)  
    7980                 :   // Since checking to see if a node is empty can be costly for nodes with many
    7981                 :   // descendants, there are some optimizations made.  I rely on the fact that the
    7982                 :   // iterator is post-order: it will visit children of a node before visiting the 
    7983                 :   // parent node.  So if I find that a child node is not empty, I know that its
    7984                 :   // parent is not empty without even checking.  So I put the parent on a "skipList"
    7985                 :   // which is just a voidArray of nodes I can skip the empty check on.  If I 
    7986                 :   // encounter a node on the skiplist, i skip the processing for that node and replace
    7987                 :   // its slot in the skiplist with that node's parent.
    7988                 :   // An interseting idea is to go ahead and regard parent nodes that are NOT on the
    7989                 :   // skiplist as being empty (without even doing the IsEmptyNode check) on the theory
    7990                 :   // that if they weren't empty, we would have encountered a non-empty child earlier
    7991                 :   // and thus put this parent node on the skiplist.
    7992                 :   // Unfortunately I can't use that strategy here, because the range may include 
    7993                 :   // some children of a node while excluding others.  Thus I could find all the 
    7994                 :   // _examined_ children empty, but still not have an empty parent.
    7995                 :   
    7996                 :   // need an iterator
    7997                 :   nsCOMPtr<nsIContentIterator> iter =
    7998               0 :                   do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
    7999               0 :   NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
    8000                 :   
    8001               0 :   nsresult res = iter->Init(mDocChangeRange);
    8002               0 :   NS_ENSURE_SUCCESS(res, res);
    8003                 :   
    8004               0 :   nsTArray<nsIDOMNode*> skipList;
    8005                 : 
    8006                 :   // check for empty nodes
    8007               0 :   while (!iter->IsDone())
    8008                 :   {
    8009               0 :     nsCOMPtr<nsIDOMNode> node, parent;
    8010                 : 
    8011               0 :     node = do_QueryInterface(iter->GetCurrentNode());
    8012               0 :     NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    8013                 : 
    8014               0 :     node->GetParentNode(getter_AddRefs(parent));
    8015                 :     
    8016               0 :     PRUint32 idx = skipList.IndexOf(node);
    8017               0 :     if (idx != skipList.NoIndex)
    8018                 :     {
    8019                 :       // this node is on our skip list.  Skip processing for this node, 
    8020                 :       // and replace its value in the skip list with the value of its parent
    8021               0 :       skipList[idx] = parent;
    8022                 :     }
    8023                 :     else
    8024                 :     {
    8025               0 :       bool bIsCandidate = false;
    8026               0 :       bool bIsEmptyNode = false;
    8027               0 :       bool bIsMailCite = false;
    8028                 : 
    8029                 :       // don't delete the body
    8030               0 :       if (!nsTextEditUtils::IsBody(node))
    8031                 :       {
    8032                 :         // only consider certain nodes to be empty for purposes of removal
    8033               0 :         if (  (bIsMailCite = nsHTMLEditUtils::IsMailCite(node))  ||
    8034               0 :               nsEditor::NodeIsType(node, nsEditProperty::a)      ||
    8035               0 :               nsHTMLEditUtils::IsInlineStyle(node)               ||
    8036               0 :               nsHTMLEditUtils::IsList(node)                      ||
    8037               0 :               nsHTMLEditUtils::IsDiv(node)  )
    8038                 :         {
    8039               0 :           bIsCandidate = true;
    8040                 :         }
    8041                 :         // these node types are candidates if selection is not in them
    8042               0 :         else if (nsHTMLEditUtils::IsFormatNode(node) ||
    8043               0 :             nsHTMLEditUtils::IsListItem(node)  ||
    8044               0 :             nsHTMLEditUtils::IsBlockquote(node) )
    8045                 :         {
    8046                 :           // if it is one of these, don't delete if selection inside.
    8047                 :           // this is so we can create empty headings, etc, for the
    8048                 :           // user to type into.
    8049                 :           bool bIsSelInNode;
    8050               0 :           res = SelectionEndpointInNode(node, &bIsSelInNode);
    8051               0 :           NS_ENSURE_SUCCESS(res, res);
    8052               0 :           if (!bIsSelInNode)
    8053                 :           {
    8054               0 :             bIsCandidate = true;
    8055                 :           }
    8056                 :         }
    8057                 :       }
    8058                 :       
    8059               0 :       if (bIsCandidate)
    8060                 :       {
    8061               0 :         if (bIsMailCite)  // we delete mailcites even if they have a solo br in them
    8062               0 :           res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, true, true);  
    8063                 :         else  // other nodes we require to be empty
    8064               0 :           res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, false, true);
    8065               0 :         NS_ENSURE_SUCCESS(res, res);
    8066               0 :         if (bIsEmptyNode)
    8067                 :         {
    8068               0 :           if (bIsMailCite)  // mailcites go on a separate list from other empty nodes
    8069                 :           {
    8070               0 :             arrayOfEmptyCites.AppendObject(node);
    8071                 :           }
    8072                 :           else
    8073                 :           {
    8074               0 :             arrayOfEmptyNodes.AppendObject(node);
    8075                 :           }
    8076                 :         }
    8077                 :       }
    8078                 :       
    8079               0 :       if (!bIsEmptyNode)
    8080                 :       {
    8081                 :         // put parent on skip list
    8082               0 :         skipList.AppendElement(parent);
    8083                 :       }
    8084                 :     }
    8085                 : 
    8086               0 :     iter->Next();
    8087                 :   }
    8088                 :   
    8089                 :   // now delete the empty nodes
    8090               0 :   nodeCount = arrayOfEmptyNodes.Count();
    8091               0 :   for (j = 0; j < nodeCount; j++)
    8092                 :   {
    8093               0 :     nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyNodes[0];
    8094               0 :     arrayOfEmptyNodes.RemoveObjectAt(0);
    8095               0 :     if (mHTMLEditor->IsModifiableNode(delNode)) {
    8096               0 :       res = mHTMLEditor->DeleteNode(delNode);
    8097               0 :       NS_ENSURE_SUCCESS(res, res);
    8098                 :     }
    8099                 :   }
    8100                 :   
    8101                 :   // now delete the empty mailcites
    8102                 :   // this is a separate step because we want to pull out any br's and preserve them.
    8103               0 :   nodeCount = arrayOfEmptyCites.Count();
    8104               0 :   for (j = 0; j < nodeCount; j++)
    8105                 :   {
    8106               0 :     nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyCites[0];
    8107               0 :     arrayOfEmptyCites.RemoveObjectAt(0);
    8108                 :     bool bIsEmptyNode;
    8109               0 :     res = mHTMLEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
    8110               0 :     NS_ENSURE_SUCCESS(res, res);
    8111               0 :     if (!bIsEmptyNode)
    8112                 :     {
    8113                 :       // we are deleting a cite that has just a br.  We want to delete cite, 
    8114                 :       // but preserve br.
    8115               0 :       nsCOMPtr<nsIDOMNode> parent, brNode;
    8116                 :       PRInt32 offset;
    8117               0 :       res = nsEditor::GetNodeLocation(delNode, address_of(parent), &offset);
    8118               0 :       NS_ENSURE_SUCCESS(res, res);
    8119               0 :       res = mHTMLEditor->CreateBR(parent, offset, address_of(brNode));
    8120               0 :       NS_ENSURE_SUCCESS(res, res);
    8121                 :     }
    8122               0 :     res = mHTMLEditor->DeleteNode(delNode);
    8123               0 :     NS_ENSURE_SUCCESS(res, res);
    8124                 :   }
    8125                 :   
    8126               0 :   return res;
    8127                 : }
    8128                 : 
    8129                 : nsresult
    8130               0 : nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, bool *aResult)
    8131                 : {
    8132               0 :   NS_ENSURE_TRUE(aNode && aResult, NS_ERROR_NULL_POINTER);
    8133                 :   
    8134               0 :   *aResult = false;
    8135                 :   
    8136               0 :   nsCOMPtr<nsISelection>selection;
    8137               0 :   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    8138               0 :   NS_ENSURE_SUCCESS(res, res);
    8139               0 :   nsCOMPtr<nsISelectionPrivate>selPriv(do_QueryInterface(selection));
    8140                 :   
    8141               0 :   nsCOMPtr<nsIEnumerator> enumerator;
    8142               0 :   res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    8143               0 :   NS_ENSURE_SUCCESS(res, res);
    8144               0 :   NS_ENSURE_TRUE(enumerator, NS_ERROR_UNEXPECTED);
    8145                 : 
    8146               0 :   for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
    8147                 :   {
    8148               0 :     nsCOMPtr<nsISupports> currentItem;
    8149               0 :     res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    8150               0 :     NS_ENSURE_SUCCESS(res, res);
    8151               0 :     NS_ENSURE_TRUE(currentItem, NS_ERROR_UNEXPECTED);
    8152                 : 
    8153               0 :     nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    8154               0 :     nsCOMPtr<nsIDOMNode> startParent, endParent;
    8155               0 :     range->GetStartContainer(getter_AddRefs(startParent));
    8156               0 :     if (startParent)
    8157                 :     {
    8158               0 :       if (aNode == startParent)
    8159                 :       {
    8160               0 :         *aResult = true;
    8161               0 :         return NS_OK;
    8162                 :       }
    8163               0 :       if (nsEditorUtils::IsDescendantOf(startParent, aNode)) 
    8164                 :       {
    8165               0 :         *aResult = true;
    8166               0 :         return NS_OK;
    8167                 :       }
    8168                 :     }
    8169               0 :     range->GetEndContainer(getter_AddRefs(endParent));
    8170               0 :     if (startParent == endParent) continue;
    8171               0 :     if (endParent)
    8172                 :     {
    8173               0 :       if (aNode == endParent) 
    8174                 :       {
    8175               0 :         *aResult = true;
    8176               0 :         return NS_OK;
    8177                 :       }
    8178               0 :       if (nsEditorUtils::IsDescendantOf(endParent, aNode))
    8179                 :       {
    8180               0 :         *aResult = true;
    8181               0 :         return NS_OK;
    8182                 :       }
    8183                 :     }
    8184                 :   }
    8185               0 :   return res;
    8186                 : }
    8187                 : 
    8188                 : ///////////////////////////////////////////////////////////////////////////
    8189                 : // IsEmptyInline:  return true if aNode is an empty inline container
    8190                 : //                
    8191                 : //                  
    8192                 : bool 
    8193               0 : nsHTMLEditRules::IsEmptyInline(nsIDOMNode *aNode)
    8194                 : {
    8195               0 :   if (aNode && IsInlineNode(aNode) && mHTMLEditor->IsContainer(aNode)) 
    8196                 :   {
    8197                 :     bool bEmpty;
    8198               0 :     mHTMLEditor->IsEmptyNode(aNode, &bEmpty);
    8199               0 :     return bEmpty;
    8200                 :   }
    8201               0 :   return false;
    8202                 : }
    8203                 : 
    8204                 : 
    8205                 : bool 
    8206               0 : nsHTMLEditRules::ListIsEmptyLine(nsCOMArray<nsIDOMNode> &arrayOfNodes)
    8207                 : {
    8208                 :   // we have a list of nodes which we are candidates for being moved
    8209                 :   // into a new block.  Determine if it's anything more than a blank line.
    8210                 :   // Look for editable content above and beyond one single BR.
    8211               0 :   PRInt32 listCount = arrayOfNodes.Count();
    8212               0 :   NS_ENSURE_TRUE(listCount, true);
    8213               0 :   nsCOMPtr<nsIDOMNode> somenode;
    8214               0 :   PRInt32 j, brCount=0;
    8215               0 :   for (j = 0; j < listCount; j++)
    8216                 :   {
    8217               0 :     somenode = arrayOfNodes[j];
    8218               0 :     if (somenode && mHTMLEditor->IsEditable(somenode))
    8219                 :     {
    8220               0 :       if (nsTextEditUtils::IsBreak(somenode))
    8221                 :       {
    8222                 :         // first break doesn't count
    8223               0 :         if (brCount) return false;
    8224               0 :         brCount++;
    8225                 :       }
    8226               0 :       else if (IsEmptyInline(somenode)) 
    8227                 :       {
    8228                 :         // empty inline, keep looking
    8229                 :       }
    8230               0 :       else return false;
    8231                 :     }
    8232                 :   }
    8233               0 :   return true;
    8234                 : }
    8235                 : 
    8236                 : 
    8237                 : nsresult 
    8238               0 : nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, bool *aOutOfList)
    8239                 : {
    8240                 :   // check parms
    8241               0 :   NS_ENSURE_TRUE(aListItem && aOutOfList, NS_ERROR_NULL_POINTER);
    8242                 :   
    8243                 :   // init out params
    8244               0 :   *aOutOfList = false;
    8245                 :   
    8246               0 :   nsCOMPtr<nsIDOMNode> curParent;
    8247               0 :   nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(aListItem));
    8248                 :   PRInt32 offset;
    8249               0 :   nsresult res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    8250               0 :   NS_ENSURE_SUCCESS(res, res);
    8251                 :     
    8252               0 :   if (!nsHTMLEditUtils::IsListItem(curNode))
    8253               0 :     return NS_ERROR_FAILURE;
    8254                 :     
    8255                 :   // if it's first or last list item, don't need to split the list
    8256                 :   // otherwise we do.
    8257               0 :   nsCOMPtr<nsIDOMNode> curParPar;
    8258                 :   PRInt32 parOffset;
    8259               0 :   res = nsEditor::GetNodeLocation(curParent, address_of(curParPar), &parOffset);
    8260               0 :   NS_ENSURE_SUCCESS(res, res);
    8261                 :   
    8262                 :   bool bIsFirstListItem;
    8263               0 :   res = mHTMLEditor->IsFirstEditableChild(curNode, &bIsFirstListItem);
    8264               0 :   NS_ENSURE_SUCCESS(res, res);
    8265                 : 
    8266                 :   bool bIsLastListItem;
    8267               0 :   res = mHTMLEditor->IsLastEditableChild(curNode, &bIsLastListItem);
    8268               0 :   NS_ENSURE_SUCCESS(res, res);
    8269                 :     
    8270               0 :   if (!bIsFirstListItem && !bIsLastListItem)
    8271                 :   {
    8272                 :     // split the list
    8273               0 :     nsCOMPtr<nsIDOMNode> newBlock;
    8274               0 :     res = mHTMLEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
    8275               0 :     NS_ENSURE_SUCCESS(res, res);
    8276                 :   }
    8277                 :   
    8278               0 :   if (!bIsFirstListItem) parOffset++;
    8279                 :   
    8280               0 :   res = mHTMLEditor->MoveNode(curNode, curParPar, parOffset);
    8281               0 :   NS_ENSURE_SUCCESS(res, res);
    8282                 :     
    8283                 :   // unwrap list item contents if they are no longer in a list
    8284               0 :   if (!nsHTMLEditUtils::IsList(curParPar)
    8285               0 :       && nsHTMLEditUtils::IsListItem(curNode)) 
    8286                 :   {
    8287               0 :     res = mHTMLEditor->RemoveBlockContainer(curNode);
    8288               0 :     NS_ENSURE_SUCCESS(res, res);
    8289               0 :     *aOutOfList = true;
    8290                 :   }
    8291               0 :   return res;
    8292                 : }
    8293                 : 
    8294                 : nsresult
    8295               0 : nsHTMLEditRules::RemoveListStructure(nsIDOMNode *aList)
    8296                 : {
    8297               0 :   NS_ENSURE_ARG_POINTER(aList);
    8298                 : 
    8299                 :   nsresult res;
    8300                 : 
    8301               0 :   nsCOMPtr<nsIDOMNode> child;
    8302               0 :   aList->GetFirstChild(getter_AddRefs(child));
    8303                 : 
    8304               0 :   while (child)
    8305                 :   {
    8306               0 :     if (nsHTMLEditUtils::IsListItem(child))
    8307                 :     {
    8308                 :       bool bOutOfList;
    8309               0 :       do
    8310                 :       {
    8311               0 :         res = PopListItem(child, &bOutOfList);
    8312               0 :         NS_ENSURE_SUCCESS(res, res);
    8313               0 :       } while (!bOutOfList);   // keep popping it out until it's not in a list anymore
    8314                 :     }
    8315               0 :     else if (nsHTMLEditUtils::IsList(child))
    8316                 :     {
    8317               0 :       res = RemoveListStructure(child);
    8318               0 :       NS_ENSURE_SUCCESS(res, res);
    8319                 :     }
    8320                 :     else
    8321                 :     {
    8322                 :       // delete any non- list items for now
    8323               0 :       res = mHTMLEditor->DeleteNode(child);
    8324               0 :       NS_ENSURE_SUCCESS(res, res);
    8325                 :     }
    8326               0 :     aList->GetFirstChild(getter_AddRefs(child));
    8327                 :   }
    8328                 :   // delete the now-empty list
    8329               0 :   res = mHTMLEditor->RemoveBlockContainer(aList);
    8330               0 :   NS_ENSURE_SUCCESS(res, res);
    8331                 : 
    8332               0 :   return res;
    8333                 : }
    8334                 : 
    8335                 : 
    8336                 : nsresult 
    8337               0 : nsHTMLEditRules::ConfirmSelectionInBody()
    8338                 : {
    8339               0 :   nsresult res = NS_OK;
    8340                 : 
    8341                 :   // get the body  
    8342               0 :   nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(mHTMLEditor->GetRoot());
    8343               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
    8344                 : 
    8345                 :   // get the selection
    8346               0 :   nsCOMPtr<nsISelection>selection;
    8347               0 :   res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    8348               0 :   NS_ENSURE_SUCCESS(res, res);
    8349                 :   
    8350                 :   // get the selection start location
    8351               0 :   nsCOMPtr<nsIDOMNode> selNode, temp, parent;
    8352                 :   PRInt32 selOffset;
    8353               0 :   res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
    8354               0 :   NS_ENSURE_SUCCESS(res, res);
    8355               0 :   temp = selNode;
    8356                 :   
    8357                 :   // check that selNode is inside body
    8358               0 :   while (temp && !nsTextEditUtils::IsBody(temp))
    8359                 :   {
    8360               0 :     res = temp->GetParentNode(getter_AddRefs(parent));
    8361               0 :     temp = parent;
    8362                 :   }
    8363                 :   
    8364                 :   // if we aren't in the body, force the issue
    8365               0 :   if (!temp) 
    8366                 :   {
    8367                 : //    uncomment this to see when we get bad selections
    8368                 : //    NS_NOTREACHED("selection not in body");
    8369               0 :     selection->Collapse(rootElement, 0);
    8370                 :   }
    8371                 :   
    8372                 :   // get the selection end location
    8373               0 :   res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
    8374               0 :   NS_ENSURE_SUCCESS(res, res);
    8375               0 :   temp = selNode;
    8376                 :   
    8377                 :   // check that selNode is inside body
    8378               0 :   while (temp && !nsTextEditUtils::IsBody(temp))
    8379                 :   {
    8380               0 :     res = temp->GetParentNode(getter_AddRefs(parent));
    8381               0 :     temp = parent;
    8382                 :   }
    8383                 :   
    8384                 :   // if we aren't in the body, force the issue
    8385               0 :   if (!temp) 
    8386                 :   {
    8387                 : //    uncomment this to see when we get bad selections
    8388                 : //    NS_NOTREACHED("selection not in body");
    8389               0 :     selection->Collapse(rootElement, 0);
    8390                 :   }
    8391                 :   
    8392               0 :   return res;
    8393                 : }
    8394                 : 
    8395                 : 
    8396                 : nsresult 
    8397               0 : nsHTMLEditRules::UpdateDocChangeRange(nsIDOMRange *aRange)
    8398                 : {
    8399               0 :   nsresult res = NS_OK;
    8400                 : 
    8401                 :   // first make sure aRange is in the document.  It might not be if
    8402                 :   // portions of our editting action involved manipulating nodes
    8403                 :   // prior to placing them in the document (e.g., populating a list item
    8404                 :   // before placing it in its list)
    8405               0 :   nsCOMPtr<nsIDOMNode> startNode;
    8406               0 :   res = aRange->GetStartContainer(getter_AddRefs(startNode));
    8407               0 :   NS_ENSURE_SUCCESS(res, res);
    8408               0 :   if (!mHTMLEditor->IsDescendantOfBody(startNode))
    8409                 :   {
    8410                 :     // just return - we don't need to adjust mDocChangeRange in this case
    8411               0 :     return NS_OK;
    8412                 :   }
    8413                 :   
    8414               0 :   if (!mDocChangeRange)
    8415                 :   {
    8416                 :     // clone aRange.
    8417               0 :     nsCOMPtr<nsIDOMRange> range;
    8418               0 :     res = aRange->CloneRange(getter_AddRefs(range));
    8419               0 :     mDocChangeRange = static_cast<nsRange*>(range.get());
    8420                 :   }
    8421                 :   else
    8422                 :   {
    8423                 :     PRInt16 result;
    8424                 :     
    8425                 :     // compare starts of ranges
    8426               0 :     res = mDocChangeRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, aRange, &result);
    8427               0 :     if (res == NS_ERROR_NOT_INITIALIZED) {
    8428                 :       // This will happen is mDocChangeRange is non-null, but the range is
    8429                 :       // uninitialized. In this case we'll set the start to aRange start.
    8430                 :       // The same test won't be needed further down since after we've set
    8431                 :       // the start the range will be collapsed to that point.
    8432               0 :       result = 1;
    8433               0 :       res = NS_OK;
    8434                 :     }
    8435               0 :     NS_ENSURE_SUCCESS(res, res);
    8436               0 :     if (result > 0)  // positive result means mDocChangeRange start is after aRange start
    8437                 :     {
    8438                 :       PRInt32 startOffset;
    8439               0 :       res = aRange->GetStartOffset(&startOffset);
    8440               0 :       NS_ENSURE_SUCCESS(res, res);
    8441               0 :       res = mDocChangeRange->SetStart(startNode, startOffset);
    8442               0 :       NS_ENSURE_SUCCESS(res, res);
    8443                 :     }
    8444                 :     
    8445                 :     // compare ends of ranges
    8446               0 :     res = mDocChangeRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, aRange, &result);
    8447               0 :     NS_ENSURE_SUCCESS(res, res);
    8448               0 :     if (result < 0)  // negative result means mDocChangeRange end is before aRange end
    8449                 :     {
    8450               0 :       nsCOMPtr<nsIDOMNode> endNode;
    8451                 :       PRInt32 endOffset;
    8452               0 :       res = aRange->GetEndContainer(getter_AddRefs(endNode));
    8453               0 :       NS_ENSURE_SUCCESS(res, res);
    8454               0 :       res = aRange->GetEndOffset(&endOffset);
    8455               0 :       NS_ENSURE_SUCCESS(res, res);
    8456               0 :       res = mDocChangeRange->SetEnd(endNode, endOffset);
    8457               0 :       NS_ENSURE_SUCCESS(res, res);
    8458                 :     }
    8459                 :   }
    8460               0 :   return res;
    8461                 : }
    8462                 : 
    8463                 : nsresult 
    8464               0 : nsHTMLEditRules::InsertMozBRIfNeeded(nsIDOMNode *aNode)
    8465                 : {
    8466               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    8467               0 :   if (!IsBlockNode(aNode)) return NS_OK;
    8468                 :   
    8469                 :   bool isEmpty;
    8470               0 :   nsCOMPtr<nsIDOMNode> brNode;
    8471               0 :   nsresult res = mHTMLEditor->IsEmptyNode(aNode, &isEmpty);
    8472               0 :   NS_ENSURE_SUCCESS(res, res);
    8473               0 :   if (isEmpty)
    8474                 :   {
    8475               0 :     res = CreateMozBR(aNode, 0, address_of(brNode));
    8476                 :   }
    8477               0 :   return res;
    8478                 : }
    8479                 : 
    8480                 : NS_IMETHODIMP 
    8481               0 : nsHTMLEditRules::WillCreateNode(const nsAString& aTag, nsIDOMNode *aParent, PRInt32 aPosition)
    8482                 : {
    8483               0 :   return NS_OK;  
    8484                 : }
    8485                 : 
    8486                 : NS_IMETHODIMP 
    8487               0 : nsHTMLEditRules::DidCreateNode(const nsAString& aTag, 
    8488                 :                                nsIDOMNode *aNode, 
    8489                 :                                nsIDOMNode *aParent, 
    8490                 :                                PRInt32 aPosition, 
    8491                 :                                nsresult aResult)
    8492                 : {
    8493               0 :   if (!mListenerEnabled) {
    8494               0 :     return NS_OK;
    8495                 :   }
    8496                 :   // assumption that Join keeps the righthand node
    8497               0 :   nsresult res = mUtilRange->SelectNode(aNode);
    8498               0 :   NS_ENSURE_SUCCESS(res, res);
    8499               0 :   res = UpdateDocChangeRange(mUtilRange);
    8500               0 :   return res;  
    8501                 : }
    8502                 : 
    8503                 : 
    8504                 : NS_IMETHODIMP 
    8505               0 : nsHTMLEditRules::WillInsertNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aPosition)
    8506                 : {
    8507               0 :   return NS_OK;  
    8508                 : }
    8509                 : 
    8510                 : 
    8511                 : NS_IMETHODIMP 
    8512               0 : nsHTMLEditRules::DidInsertNode(nsIDOMNode *aNode, 
    8513                 :                                nsIDOMNode *aParent, 
    8514                 :                                PRInt32 aPosition, 
    8515                 :                                nsresult aResult)
    8516                 : {
    8517               0 :   if (!mListenerEnabled) {
    8518               0 :     return NS_OK;
    8519                 :   }
    8520               0 :   nsresult res = mUtilRange->SelectNode(aNode);
    8521               0 :   NS_ENSURE_SUCCESS(res, res);
    8522               0 :   res = UpdateDocChangeRange(mUtilRange);
    8523               0 :   return res;  
    8524                 : }
    8525                 : 
    8526                 : 
    8527                 : NS_IMETHODIMP 
    8528               0 : nsHTMLEditRules::WillDeleteNode(nsIDOMNode *aChild)
    8529                 : {
    8530               0 :   if (!mListenerEnabled) {
    8531               0 :     return NS_OK;
    8532                 :   }
    8533               0 :   nsresult res = mUtilRange->SelectNode(aChild);
    8534               0 :   NS_ENSURE_SUCCESS(res, res);
    8535               0 :   res = UpdateDocChangeRange(mUtilRange);
    8536               0 :   return res;  
    8537                 : }
    8538                 : 
    8539                 : 
    8540                 : NS_IMETHODIMP 
    8541               0 : nsHTMLEditRules::DidDeleteNode(nsIDOMNode *aChild, nsresult aResult)
    8542                 : {
    8543               0 :   return NS_OK;  
    8544                 : }
    8545                 : 
    8546                 : 
    8547                 : NS_IMETHODIMP 
    8548               0 : nsHTMLEditRules::WillSplitNode(nsIDOMNode *aExistingRightNode, PRInt32 aOffset)
    8549                 : {
    8550               0 :   return NS_OK;  
    8551                 : }
    8552                 : 
    8553                 : 
    8554                 : NS_IMETHODIMP 
    8555               0 : nsHTMLEditRules::DidSplitNode(nsIDOMNode *aExistingRightNode, 
    8556                 :                               PRInt32 aOffset, 
    8557                 :                               nsIDOMNode *aNewLeftNode, 
    8558                 :                               nsresult aResult)
    8559                 : {
    8560               0 :   if (!mListenerEnabled) {
    8561               0 :     return NS_OK;
    8562                 :   }
    8563               0 :   nsresult res = mUtilRange->SetStart(aNewLeftNode, 0);
    8564               0 :   NS_ENSURE_SUCCESS(res, res);
    8565               0 :   res = mUtilRange->SetEnd(aExistingRightNode, 0);
    8566               0 :   NS_ENSURE_SUCCESS(res, res);
    8567               0 :   res = UpdateDocChangeRange(mUtilRange);
    8568               0 :   return res;  
    8569                 : }
    8570                 : 
    8571                 : 
    8572                 : NS_IMETHODIMP 
    8573               0 : nsHTMLEditRules::WillJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsIDOMNode *aParent)
    8574                 : {
    8575               0 :   if (!mListenerEnabled) {
    8576               0 :     return NS_OK;
    8577                 :   }
    8578                 :   // remember split point
    8579               0 :   nsresult res = nsEditor::GetLengthOfDOMNode(aLeftNode, mJoinOffset);
    8580               0 :   return res;  
    8581                 : }
    8582                 : 
    8583                 : 
    8584                 : NS_IMETHODIMP 
    8585               0 : nsHTMLEditRules::DidJoinNodes(nsIDOMNode  *aLeftNode, 
    8586                 :                               nsIDOMNode *aRightNode, 
    8587                 :                               nsIDOMNode *aParent, 
    8588                 :                               nsresult aResult)
    8589                 : {
    8590               0 :   if (!mListenerEnabled) {
    8591               0 :     return NS_OK;
    8592                 :   }
    8593                 :   // assumption that Join keeps the righthand node
    8594               0 :   nsresult res = mUtilRange->SetStart(aRightNode, mJoinOffset);
    8595               0 :   NS_ENSURE_SUCCESS(res, res);
    8596               0 :   res = mUtilRange->SetEnd(aRightNode, mJoinOffset);
    8597               0 :   NS_ENSURE_SUCCESS(res, res);
    8598               0 :   res = UpdateDocChangeRange(mUtilRange);
    8599               0 :   return res;  
    8600                 : }
    8601                 : 
    8602                 : 
    8603                 : NS_IMETHODIMP 
    8604               0 : nsHTMLEditRules::WillInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsAString &aString)
    8605                 : {
    8606               0 :   return NS_OK;  
    8607                 : }
    8608                 : 
    8609                 : 
    8610                 : NS_IMETHODIMP 
    8611               0 : nsHTMLEditRules::DidInsertText(nsIDOMCharacterData *aTextNode, 
    8612                 :                                   PRInt32 aOffset, 
    8613                 :                                   const nsAString &aString, 
    8614                 :                                   nsresult aResult)
    8615                 : {
    8616               0 :   if (!mListenerEnabled) {
    8617               0 :     return NS_OK;
    8618                 :   }
    8619               0 :   PRInt32 length = aString.Length();
    8620               0 :   nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
    8621               0 :   nsresult res = mUtilRange->SetStart(theNode, aOffset);
    8622               0 :   NS_ENSURE_SUCCESS(res, res);
    8623               0 :   res = mUtilRange->SetEnd(theNode, aOffset+length);
    8624               0 :   NS_ENSURE_SUCCESS(res, res);
    8625               0 :   res = UpdateDocChangeRange(mUtilRange);
    8626               0 :   return res;  
    8627                 : }
    8628                 : 
    8629                 : 
    8630                 : NS_IMETHODIMP 
    8631               0 : nsHTMLEditRules::WillDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
    8632                 : {
    8633               0 :   return NS_OK;  
    8634                 : }
    8635                 : 
    8636                 : 
    8637                 : NS_IMETHODIMP 
    8638               0 : nsHTMLEditRules::DidDeleteText(nsIDOMCharacterData *aTextNode, 
    8639                 :                                   PRInt32 aOffset, 
    8640                 :                                   PRInt32 aLength, 
    8641                 :                                   nsresult aResult)
    8642                 : {
    8643               0 :   if (!mListenerEnabled) {
    8644               0 :     return NS_OK;
    8645                 :   }
    8646               0 :   nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
    8647               0 :   nsresult res = mUtilRange->SetStart(theNode, aOffset);
    8648               0 :   NS_ENSURE_SUCCESS(res, res);
    8649               0 :   res = mUtilRange->SetEnd(theNode, aOffset);
    8650               0 :   NS_ENSURE_SUCCESS(res, res);
    8651               0 :   res = UpdateDocChangeRange(mUtilRange);
    8652               0 :   return res;  
    8653                 : }
    8654                 : 
    8655                 : NS_IMETHODIMP
    8656               0 : nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection)
    8657                 : {
    8658               0 :   if (!mListenerEnabled) {
    8659               0 :     return NS_OK;
    8660                 :   }
    8661                 :   // get the (collapsed) selection location
    8662               0 :   nsCOMPtr<nsIDOMNode> selNode;
    8663                 :   PRInt32 selOffset;
    8664                 : 
    8665               0 :   nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    8666               0 :   NS_ENSURE_SUCCESS(res, res);
    8667               0 :   res = mUtilRange->SetStart(selNode, selOffset);
    8668               0 :   NS_ENSURE_SUCCESS(res, res);
    8669               0 :   res = mHTMLEditor->GetEndNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    8670               0 :   NS_ENSURE_SUCCESS(res, res);
    8671               0 :   res = mUtilRange->SetEnd(selNode, selOffset);
    8672               0 :   NS_ENSURE_SUCCESS(res, res);
    8673               0 :   res = UpdateDocChangeRange(mUtilRange);
    8674               0 :   return res;  
    8675                 : }
    8676                 : 
    8677                 : NS_IMETHODIMP
    8678               0 : nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
    8679                 : {
    8680               0 :   return NS_OK;
    8681                 : }
    8682                 : 
    8683                 : // Let's remove all alignment hints in the children of aNode; it can
    8684                 : // be an ALIGN attribute (in case we just remove it) or a CENTER
    8685                 : // element (here we have to remove the container and keep its
    8686                 : // children). We break on tables and don't look at their children.
    8687                 : nsresult
    8688               0 : nsHTMLEditRules::RemoveAlignment(nsIDOMNode * aNode, const nsAString & aAlignType, bool aChildrenOnly)
    8689                 : {
    8690               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    8691                 : 
    8692               0 :   if (mHTMLEditor->IsTextNode(aNode) || nsHTMLEditUtils::IsTable(aNode)) return NS_OK;
    8693               0 :   nsresult res = NS_OK;
    8694                 : 
    8695               0 :   nsCOMPtr<nsIDOMNode> child = aNode,tmp;
    8696               0 :   if (aChildrenOnly)
    8697                 :   {
    8698               0 :     aNode->GetFirstChild(getter_AddRefs(child));
    8699                 :   }
    8700               0 :   bool useCSS = mHTMLEditor->IsCSSEnabled();
    8701                 : 
    8702               0 :   while (child)
    8703                 :   {
    8704               0 :     if (aChildrenOnly) {
    8705                 :       // get the next sibling right now because we could have to remove child
    8706               0 :       child->GetNextSibling(getter_AddRefs(tmp));
    8707                 :     }
    8708                 :     else
    8709                 :     {
    8710               0 :       tmp = nsnull;
    8711                 :     }
    8712                 :     bool isBlock;
    8713               0 :     res = mHTMLEditor->NodeIsBlockStatic(child, &isBlock);
    8714               0 :     NS_ENSURE_SUCCESS(res, res);
    8715                 : 
    8716               0 :     if (nsEditor::NodeIsType(child, nsEditProperty::center))
    8717                 :     {
    8718                 :       // the current node is a CENTER element
    8719                 :       // first remove children's alignment
    8720               0 :       res = RemoveAlignment(child, aAlignType, true);
    8721               0 :       NS_ENSURE_SUCCESS(res, res);
    8722                 : 
    8723                 :       // we may have to insert BRs in first and last position of element's children
    8724                 :       // if the nodes before/after are not blocks and not BRs
    8725               0 :       res = MakeSureElemStartsOrEndsOnCR(child);
    8726               0 :       NS_ENSURE_SUCCESS(res, res);
    8727                 : 
    8728                 :       // now remove the CENTER container
    8729               0 :       res = mHTMLEditor->RemoveContainer(child);
    8730               0 :       NS_ENSURE_SUCCESS(res, res);
    8731                 :     }
    8732               0 :     else if (isBlock || nsHTMLEditUtils::IsHR(child))
    8733                 :     {
    8734                 :       // the current node is a block element
    8735               0 :       nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(child);
    8736               0 :       if (nsHTMLEditUtils::SupportsAlignAttr(child))
    8737                 :       {
    8738                 :         // remove the ALIGN attribute if this element can have it
    8739               0 :         res = mHTMLEditor->RemoveAttribute(curElem, NS_LITERAL_STRING("align"));
    8740               0 :         NS_ENSURE_SUCCESS(res, res);
    8741                 :       }
    8742               0 :       if (useCSS)
    8743                 :       {
    8744               0 :         if (nsHTMLEditUtils::IsTable(child) || nsHTMLEditUtils::IsHR(child))
    8745                 :         {
    8746               0 :           res = mHTMLEditor->SetAttributeOrEquivalent(curElem, NS_LITERAL_STRING("align"), aAlignType, false); 
    8747                 :         }
    8748                 :         else
    8749                 :         {
    8750               0 :           nsAutoString dummyCssValue;
    8751               0 :           res = mHTMLEditor->mHTMLCSSUtils->RemoveCSSInlineStyle(child, nsEditProperty::cssTextAlign, dummyCssValue);
    8752                 :         }
    8753               0 :         NS_ENSURE_SUCCESS(res, res);
    8754                 :       }
    8755               0 :       if (!nsHTMLEditUtils::IsTable(child))
    8756                 :       {
    8757                 :         // unless this is a table, look at children
    8758               0 :         res = RemoveAlignment(child, aAlignType, true);
    8759               0 :         NS_ENSURE_SUCCESS(res, res);
    8760                 :       }
    8761                 :     }
    8762               0 :     child = tmp;
    8763                 :   }
    8764               0 :   return NS_OK;
    8765                 : }
    8766                 : 
    8767                 : // Let's insert a BR as first (resp. last) child of aNode if its
    8768                 : // first (resp. last) child is not a block nor a BR, and if the
    8769                 : // previous (resp. next) sibling is not a block nor a BR
    8770                 : nsresult
    8771               0 : nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, bool aStarts)
    8772                 : {
    8773               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    8774                 : 
    8775               0 :   nsCOMPtr<nsIDOMNode> child;
    8776                 :   nsresult res;
    8777               0 :   if (aStarts)
    8778                 :   {
    8779               0 :     res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(child));
    8780                 :   }
    8781                 :   else
    8782                 :   {
    8783               0 :     res = mHTMLEditor->GetLastEditableChild(aNode, address_of(child));
    8784                 :   }
    8785               0 :   NS_ENSURE_SUCCESS(res, res);
    8786               0 :   NS_ENSURE_TRUE(child, NS_OK);
    8787                 :   bool isChildBlock;
    8788               0 :   res = mHTMLEditor->NodeIsBlockStatic(child, &isChildBlock);
    8789               0 :   NS_ENSURE_SUCCESS(res, res);
    8790               0 :   bool foundCR = false;
    8791               0 :   if (isChildBlock || nsTextEditUtils::IsBreak(child))
    8792                 :   {
    8793               0 :     foundCR = true;
    8794                 :   }
    8795                 :   else
    8796                 :   {
    8797               0 :     nsCOMPtr<nsIDOMNode> sibling;
    8798               0 :     if (aStarts)
    8799                 :     {
    8800               0 :       res = mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling));
    8801                 :     }
    8802                 :     else
    8803                 :     {
    8804               0 :       res = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling));
    8805                 :     }
    8806               0 :     NS_ENSURE_SUCCESS(res, res);
    8807               0 :     if (sibling)
    8808                 :     {
    8809                 :       bool isBlock;
    8810               0 :       res = mHTMLEditor->NodeIsBlockStatic(sibling, &isBlock);
    8811               0 :       NS_ENSURE_SUCCESS(res, res);
    8812               0 :       if (isBlock || nsTextEditUtils::IsBreak(sibling))
    8813                 :       {
    8814               0 :         foundCR = true;
    8815                 :       }
    8816                 :     }
    8817                 :     else
    8818                 :     {
    8819               0 :       foundCR = true;
    8820                 :     }
    8821                 :   }
    8822               0 :   if (!foundCR)
    8823                 :   {
    8824               0 :     nsCOMPtr<nsIDOMNode> brNode;
    8825               0 :     PRInt32 offset = 0;
    8826               0 :     if (!aStarts)
    8827                 :     {
    8828               0 :       nsCOMPtr<nsIDOMNodeList> childNodes;
    8829               0 :       res = aNode->GetChildNodes(getter_AddRefs(childNodes));
    8830               0 :       NS_ENSURE_SUCCESS(res, res);
    8831               0 :       NS_ENSURE_TRUE(childNodes, NS_ERROR_NULL_POINTER);
    8832                 :       PRUint32 childCount;
    8833               0 :       res = childNodes->GetLength(&childCount);
    8834               0 :       NS_ENSURE_SUCCESS(res, res);
    8835               0 :       offset = childCount;
    8836                 :     }
    8837               0 :     res = mHTMLEditor->CreateBR(aNode, offset, address_of(brNode));
    8838               0 :     NS_ENSURE_SUCCESS(res, res);
    8839                 :   }
    8840               0 :   return NS_OK;
    8841                 : }
    8842                 : 
    8843                 : nsresult
    8844               0 : nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode)
    8845                 : {
    8846               0 :   nsresult res = MakeSureElemStartsOrEndsOnCR(aNode, false);
    8847               0 :   NS_ENSURE_SUCCESS(res, res);
    8848               0 :   res = MakeSureElemStartsOrEndsOnCR(aNode, true);
    8849               0 :   return res;
    8850                 : }
    8851                 : 
    8852                 : nsresult
    8853               0 : nsHTMLEditRules::AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignType, bool aContentsOnly)
    8854                 : {
    8855               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    8856                 : 
    8857               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
    8858               0 :   bool isBlock = IsBlockNode(node);
    8859               0 :   if (!isBlock && !nsHTMLEditUtils::IsHR(node)) {
    8860                 :     // we deal only with blocks; early way out
    8861               0 :     return NS_OK;
    8862                 :   }
    8863                 : 
    8864               0 :   nsresult res = RemoveAlignment(node, *aAlignType, aContentsOnly);
    8865               0 :   NS_ENSURE_SUCCESS(res, res);
    8866               0 :   NS_NAMED_LITERAL_STRING(attr, "align");
    8867               0 :   if (mHTMLEditor->IsCSSEnabled()) {
    8868                 :     // let's use CSS alignment; we use margin-left and margin-right for tables
    8869                 :     // and text-align for other block-level elements
    8870               0 :     res = mHTMLEditor->SetAttributeOrEquivalent(aElement, attr, *aAlignType, false); 
    8871               0 :     NS_ENSURE_SUCCESS(res, res);
    8872                 :   }
    8873                 :   else {
    8874                 :     // HTML case; this code is supposed to be called ONLY if the element
    8875                 :     // supports the align attribute but we'll never know...
    8876               0 :     if (nsHTMLEditUtils::SupportsAlignAttr(node)) {
    8877               0 :       res = mHTMLEditor->SetAttribute(aElement, attr, *aAlignType);
    8878               0 :       NS_ENSURE_SUCCESS(res, res);
    8879                 :     }
    8880                 :   }
    8881               0 :   return NS_OK;
    8882                 : }
    8883                 : 
    8884                 : nsresult
    8885               0 : nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, PRInt8 aRelativeChange)
    8886                 : {
    8887               0 :   NS_ENSURE_ARG_POINTER(aNode);
    8888                 : 
    8889               0 :   if (aRelativeChange != 1 && aRelativeChange != -1) {
    8890               0 :     return NS_ERROR_ILLEGAL_VALUE;
    8891                 :   }
    8892                 : 
    8893               0 :   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
    8894               0 :   if (!element) {
    8895               0 :     return NS_OK;
    8896                 :   }
    8897                 : 
    8898               0 :   nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, element);    
    8899               0 :   nsAutoString value;
    8900               0 :   mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(aNode, marginProperty, value);
    8901                 :   float f;
    8902               0 :   nsCOMPtr<nsIAtom> unit;
    8903               0 :   mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
    8904               0 :   if (0 == f) {
    8905               0 :     nsAutoString defaultLengthUnit;
    8906               0 :     mHTMLEditor->mHTMLCSSUtils->GetDefaultLengthUnit(defaultLengthUnit);
    8907               0 :     unit = do_GetAtom(defaultLengthUnit);
    8908                 :   }
    8909               0 :   if      (nsEditProperty::cssInUnit == unit)
    8910               0 :             f += NS_EDITOR_INDENT_INCREMENT_IN * aRelativeChange;
    8911               0 :   else if (nsEditProperty::cssCmUnit == unit)
    8912               0 :             f += NS_EDITOR_INDENT_INCREMENT_CM * aRelativeChange;
    8913               0 :   else if (nsEditProperty::cssMmUnit == unit)
    8914               0 :             f += NS_EDITOR_INDENT_INCREMENT_MM * aRelativeChange;
    8915               0 :   else if (nsEditProperty::cssPtUnit == unit)
    8916               0 :             f += NS_EDITOR_INDENT_INCREMENT_PT * aRelativeChange;
    8917               0 :   else if (nsEditProperty::cssPcUnit == unit)
    8918               0 :             f += NS_EDITOR_INDENT_INCREMENT_PC * aRelativeChange;
    8919               0 :   else if (nsEditProperty::cssEmUnit == unit)
    8920               0 :             f += NS_EDITOR_INDENT_INCREMENT_EM * aRelativeChange;
    8921               0 :   else if (nsEditProperty::cssExUnit == unit)
    8922               0 :             f += NS_EDITOR_INDENT_INCREMENT_EX * aRelativeChange;
    8923               0 :   else if (nsEditProperty::cssPxUnit == unit)
    8924               0 :             f += NS_EDITOR_INDENT_INCREMENT_PX * aRelativeChange;
    8925               0 :   else if (nsEditProperty::cssPercentUnit == unit)
    8926               0 :             f += NS_EDITOR_INDENT_INCREMENT_PERCENT * aRelativeChange;    
    8927                 : 
    8928               0 :   if (0 < f) {
    8929               0 :     nsAutoString newValue;
    8930               0 :     newValue.AppendFloat(f);
    8931               0 :     newValue.Append(nsDependentAtomString(unit));
    8932               0 :     mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(element, marginProperty, newValue, false);
    8933               0 :     return NS_OK;
    8934                 :   }
    8935                 : 
    8936               0 :   mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, marginProperty, value, false);
    8937                 : 
    8938                 :   // remove unnecessary DIV blocks:
    8939                 :   // we could skip this section but that would cause a FAIL in
    8940                 :   // editor/libeditor/html/tests/browserscope/richtext.html, which expects
    8941                 :   // to unapply a CSS "indent" (<div style="margin-left: 40px;">) by
    8942                 :   // removing the DIV container instead of just removing the CSS property.
    8943               0 :   nsCOMPtr<dom::Element> node = do_QueryInterface(aNode);
    8944               0 :   if (!node || !node->IsHTML(nsGkAtoms::div) ||
    8945               0 :       node == mHTMLEditor->GetActiveEditingHost() ||
    8946               0 :       !mHTMLEditor->IsNodeInActiveEditor(node) ||
    8947               0 :       nsHTMLEditor::HasAttributes(node)) {
    8948               0 :     return NS_OK;
    8949                 :   }
    8950                 : 
    8951               0 :   return mHTMLEditor->RemoveContainer(element);
    8952                 : }
    8953                 : 
    8954                 : //
    8955                 : // Support for Absolute Positioning
    8956                 : //
    8957                 : 
    8958                 : nsresult
    8959               0 : nsHTMLEditRules::WillAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled)
    8960                 : {
    8961               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    8962               0 :   nsresult res = WillInsert(aSelection, aCancel);
    8963               0 :   NS_ENSURE_SUCCESS(res, res);
    8964                 : 
    8965                 :   // initialize out param
    8966                 :   // we want to ignore result of WillInsert()
    8967               0 :   *aCancel = false;
    8968               0 :   *aHandled = true;
    8969                 :   
    8970               0 :   nsCOMPtr<nsIDOMElement> focusElement;
    8971               0 :   res = mHTMLEditor->GetSelectionContainer(getter_AddRefs(focusElement));
    8972               0 :   if (focusElement) {
    8973               0 :     nsCOMPtr<nsIDOMNode> node = do_QueryInterface(focusElement);
    8974               0 :     if (nsHTMLEditUtils::IsImage(node)) {
    8975               0 :       mNewBlock = node;
    8976               0 :       return NS_OK;
    8977                 :     }
    8978                 :   }
    8979                 : 
    8980               0 :   res = NormalizeSelection(aSelection);
    8981               0 :   NS_ENSURE_SUCCESS(res, res);
    8982               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    8983                 :   
    8984                 :   // convert the selection ranges into "promoted" selection ranges:
    8985                 :   // this basically just expands the range to include the immediate
    8986                 :   // block parent, and then further expands to include any ancestors
    8987                 :   // whose children are all in the range
    8988                 :   
    8989               0 :   nsCOMArray<nsIDOMRange> arrayOfRanges;
    8990               0 :   res = GetPromotedRanges(aSelection, arrayOfRanges, kSetAbsolutePosition);
    8991               0 :   NS_ENSURE_SUCCESS(res, res);
    8992                 :   
    8993                 :   // use these ranges to contruct a list of nodes to act on.
    8994               0 :   nsCOMArray<nsIDOMNode> arrayOfNodes;
    8995               0 :   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, kSetAbsolutePosition);
    8996               0 :   NS_ENSURE_SUCCESS(res, res);                                 
    8997                 :                                      
    8998               0 :   NS_NAMED_LITERAL_STRING(divType, "div");
    8999                 : 
    9000                 : 
    9001                 :   // if nothing visible in list, make an empty block
    9002               0 :   if (ListIsEmptyLine(arrayOfNodes))
    9003                 :   {
    9004               0 :     nsCOMPtr<nsIDOMNode> parent, thePositionedDiv;
    9005                 :     PRInt32 offset;
    9006                 :     
    9007                 :     // get selection location
    9008               0 :     res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
    9009               0 :     NS_ENSURE_SUCCESS(res, res);
    9010                 :     // make sure we can put a block here
    9011               0 :     res = SplitAsNeeded(&divType, address_of(parent), &offset);
    9012               0 :     NS_ENSURE_SUCCESS(res, res);
    9013               0 :     res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(thePositionedDiv));
    9014               0 :     NS_ENSURE_SUCCESS(res, res);
    9015                 :     // remember our new block for postprocessing
    9016               0 :     mNewBlock = thePositionedDiv;
    9017                 :     // delete anything that was in the list of nodes
    9018               0 :     for (PRInt32 j = arrayOfNodes.Count() - 1; j >= 0; --j) 
    9019                 :     {
    9020               0 :       nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
    9021               0 :       res = mHTMLEditor->DeleteNode(curNode);
    9022               0 :       NS_ENSURE_SUCCESS(res, res);
    9023               0 :       res = arrayOfNodes.RemoveObjectAt(0);
    9024               0 :       NS_ENSURE_SUCCESS(res, res);
    9025                 :     }
    9026                 :     // put selection in new block
    9027               0 :     res = aSelection->Collapse(thePositionedDiv,0);
    9028               0 :     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
    9029               0 :     *aHandled = true;
    9030               0 :     return res;
    9031                 :   }
    9032                 : 
    9033                 :   // Ok, now go through all the nodes and put them in a blockquote, 
    9034                 :   // or whatever is appropriate.  Wohoo!
    9035                 :   PRInt32 i;
    9036               0 :   nsCOMPtr<nsIDOMNode> curParent, curPositionedDiv, curList, indentedLI, sibling;
    9037               0 :   PRInt32 listCount = arrayOfNodes.Count();
    9038               0 :   for (i=0; i<listCount; i++)
    9039                 :   {
    9040                 :     // here's where we actually figure out what to do
    9041               0 :     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
    9042                 : 
    9043                 :     // Ignore all non-editable nodes.  Leave them be.
    9044               0 :     if (!mHTMLEditor->IsEditable(curNode)) continue;
    9045                 : 
    9046                 :     PRInt32 offset;
    9047               0 :     res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
    9048               0 :     NS_ENSURE_SUCCESS(res, res);
    9049                 :      
    9050                 :     // some logic for putting list items into nested lists...
    9051               0 :     if (nsHTMLEditUtils::IsList(curParent))
    9052                 :     {
    9053                 :       // check to see if curList is still appropriate.  Which it is if
    9054                 :       // curNode is still right after it in the same list.
    9055               0 :       if (curList)
    9056                 :       {
    9057               0 :         sibling = nsnull;
    9058               0 :         mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    9059                 :       }
    9060                 :       
    9061               0 :       if (!curList || (sibling && sibling != curList) )
    9062                 :       {
    9063               0 :         nsAutoString listTag;
    9064               0 :         nsEditor::GetTagString(curParent,listTag);
    9065               0 :         ToLowerCase(listTag);
    9066                 :         // create a new nested list of correct type
    9067               0 :         res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
    9068               0 :         NS_ENSURE_SUCCESS(res, res);
    9069               0 :         if (!curPositionedDiv) {
    9070                 :           PRInt32 parentOffset;
    9071               0 :           nsCOMPtr<nsIDOMNode> curParentParent;
    9072               0 :           res = nsEditor::GetNodeLocation(curParent, address_of(curParentParent), &parentOffset);
    9073               0 :           res = mHTMLEditor->CreateNode(divType, curParentParent, parentOffset, getter_AddRefs(curPositionedDiv));
    9074               0 :           mNewBlock = curPositionedDiv;
    9075                 :         }
    9076               0 :         res = mHTMLEditor->CreateNode(listTag, curPositionedDiv, -1, getter_AddRefs(curList));
    9077               0 :         NS_ENSURE_SUCCESS(res, res);
    9078                 :         // curList is now the correct thing to put curNode in
    9079                 :         // remember our new block for postprocessing
    9080                 :         // mNewBlock = curList;
    9081                 :       }
    9082                 :       // tuck the node into the end of the active list
    9083               0 :       res = mHTMLEditor->MoveNode(curNode, curList, -1);
    9084               0 :       NS_ENSURE_SUCCESS(res, res);
    9085                 :       // forget curPositionedDiv, if any
    9086                 :       // curPositionedDiv = nsnull;
    9087                 :     }
    9088                 :     
    9089                 :     else // not a list item, use blockquote?
    9090                 :     {
    9091                 :       // if we are inside a list item, we don't want to blockquote, we want
    9092                 :       // to sublist the list item.  We may have several nodes listed in the
    9093                 :       // array of nodes to act on, that are in the same list item.  Since
    9094                 :       // we only want to indent that li once, we must keep track of the most
    9095                 :       // recent indented list item, and not indent it if we find another node
    9096                 :       // to act on that is still inside the same li.
    9097               0 :       nsCOMPtr<nsIDOMNode> listitem=IsInListItem(curNode);
    9098               0 :       if (listitem)
    9099                 :       {
    9100               0 :         if (indentedLI == listitem) continue;  // already indented this list item
    9101               0 :         res = nsEditor::GetNodeLocation(listitem, address_of(curParent), &offset);
    9102               0 :         NS_ENSURE_SUCCESS(res, res);
    9103                 :         // check to see if curList is still appropriate.  Which it is if
    9104                 :         // curNode is still right after it in the same list.
    9105               0 :         if (curList)
    9106                 :         {
    9107               0 :           sibling = nsnull;
    9108               0 :           mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling));
    9109                 :         }
    9110                 :          
    9111               0 :         if (!curList || (sibling && sibling != curList) )
    9112                 :         {
    9113               0 :           nsAutoString listTag;
    9114               0 :           nsEditor::GetTagString(curParent,listTag);
    9115               0 :           ToLowerCase(listTag);
    9116                 :           // create a new nested list of correct type
    9117               0 :           res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
    9118               0 :           NS_ENSURE_SUCCESS(res, res);
    9119               0 :           if (!curPositionedDiv) {
    9120                 :           PRInt32 parentOffset;
    9121               0 :           nsCOMPtr<nsIDOMNode> curParentParent;
    9122               0 :           res = nsEditor::GetNodeLocation(curParent, address_of(curParentParent), &parentOffset);
    9123               0 :           res = mHTMLEditor->CreateNode(divType, curParentParent, parentOffset, getter_AddRefs(curPositionedDiv));
    9124               0 :             mNewBlock = curPositionedDiv;
    9125                 :           }
    9126               0 :           res = mHTMLEditor->CreateNode(listTag, curPositionedDiv, -1, getter_AddRefs(curList));
    9127               0 :           NS_ENSURE_SUCCESS(res, res);
    9128                 :         }
    9129               0 :         res = mHTMLEditor->MoveNode(listitem, curList, -1);
    9130               0 :         NS_ENSURE_SUCCESS(res, res);
    9131                 :         // remember we indented this li
    9132               0 :         indentedLI = listitem;
    9133                 :       }
    9134                 :       
    9135                 :       else
    9136                 :       {
    9137                 :         // need to make a div to put things in if we haven't already
    9138                 : 
    9139               0 :         if (!curPositionedDiv) 
    9140                 :         {
    9141               0 :           if (nsHTMLEditUtils::IsDiv(curNode))
    9142                 :           {
    9143               0 :             curPositionedDiv = curNode;
    9144               0 :             mNewBlock = curPositionedDiv;
    9145               0 :             curList = nsnull;
    9146               0 :             continue;
    9147                 :           }
    9148               0 :           res = SplitAsNeeded(&divType, address_of(curParent), &offset);
    9149               0 :           NS_ENSURE_SUCCESS(res, res);
    9150               0 :           res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curPositionedDiv));
    9151               0 :           NS_ENSURE_SUCCESS(res, res);
    9152                 :           // remember our new block for postprocessing
    9153               0 :           mNewBlock = curPositionedDiv;
    9154                 :           // curPositionedDiv is now the correct thing to put curNode in
    9155                 :         }
    9156                 :           
    9157                 :         // tuck the node into the end of the active blockquote
    9158               0 :         res = mHTMLEditor->MoveNode(curNode, curPositionedDiv, -1);
    9159               0 :         NS_ENSURE_SUCCESS(res, res);
    9160                 :         // forget curList, if any
    9161               0 :         curList = nsnull;
    9162                 :       }
    9163                 :     }
    9164                 :   }
    9165               0 :   return res;
    9166                 : }
    9167                 : 
    9168                 : nsresult
    9169               0 : nsHTMLEditRules::DidAbsolutePosition()
    9170                 : {
    9171               0 :   nsCOMPtr<nsIHTMLAbsPosEditor> absPosHTMLEditor = mHTMLEditor;
    9172               0 :   nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(mNewBlock);
    9173               0 :   return absPosHTMLEditor->AbsolutelyPositionElement(elt, true);
    9174                 : }
    9175                 : 
    9176                 : nsresult
    9177               0 : nsHTMLEditRules::WillRemoveAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled)
    9178                 : {
    9179               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    9180               0 :   nsresult res = WillInsert(aSelection, aCancel);
    9181               0 :   NS_ENSURE_SUCCESS(res, res);
    9182                 : 
    9183                 :   // initialize out param
    9184                 :   // we want to ignore aCancel from WillInsert()
    9185               0 :   *aCancel = false;
    9186               0 :   *aHandled = true;
    9187                 : 
    9188               0 :   nsCOMPtr<nsIDOMElement>  elt;
    9189               0 :   res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt));
    9190               0 :   NS_ENSURE_SUCCESS(res, res);
    9191                 : 
    9192               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    9193                 : 
    9194               0 :   nsCOMPtr<nsIHTMLAbsPosEditor> absPosHTMLEditor = mHTMLEditor;
    9195               0 :   return absPosHTMLEditor->AbsolutelyPositionElement(elt, false);
    9196                 : }
    9197                 : 
    9198                 : nsresult
    9199               0 : nsHTMLEditRules::WillRelativeChangeZIndex(nsISelection *aSelection,
    9200                 :                                           PRInt32 aChange,
    9201                 :                                           bool *aCancel,
    9202                 :                                           bool * aHandled)
    9203                 : {
    9204               0 :   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
    9205               0 :   nsresult res = WillInsert(aSelection, aCancel);
    9206               0 :   NS_ENSURE_SUCCESS(res, res);
    9207                 : 
    9208                 :   // initialize out param
    9209                 :   // we want to ignore aCancel from WillInsert()
    9210               0 :   *aCancel = false;
    9211               0 :   *aHandled = true;
    9212                 : 
    9213               0 :   nsCOMPtr<nsIDOMElement>  elt;
    9214               0 :   res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt));
    9215               0 :   NS_ENSURE_SUCCESS(res, res);
    9216                 : 
    9217               0 :   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
    9218                 : 
    9219               0 :   nsCOMPtr<nsIHTMLAbsPosEditor> absPosHTMLEditor = mHTMLEditor;
    9220                 :   PRInt32 zIndex;
    9221               0 :   return absPosHTMLEditor->RelativeChangeElementZIndex(elt, aChange, &zIndex);
    9222                 : }
    9223                 : 
    9224                 : NS_IMETHODIMP
    9225               0 : nsHTMLEditRules::DocumentModified()
    9226                 : {
    9227               0 :   nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, &nsHTMLEditRules::DocumentModifiedWorker));
    9228               0 :   return NS_OK;
    9229                 : }
    9230                 : 
    9231                 : void
    9232               0 : nsHTMLEditRules::DocumentModifiedWorker()
    9233                 : {
    9234               0 :   if (!mHTMLEditor) {
    9235               0 :     return;
    9236                 :   }
    9237                 : 
    9238                 :   // DeleteNode below may cause a flush, which could destroy the editor
    9239               0 :   nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
    9240                 : 
    9241               0 :   nsCOMPtr<nsIHTMLEditor> kungFuDeathGrip(mHTMLEditor);
    9242               0 :   nsCOMPtr<nsISelection> selection;
    9243               0 :   nsresult rv = mHTMLEditor->GetSelection(getter_AddRefs(selection));
    9244               0 :   if (NS_FAILED(rv)) {
    9245                 :     return;
    9246                 :   }
    9247                 : 
    9248                 :   // Delete our bogus node, if we have one, since the document might not be
    9249                 :   // empty any more.
    9250               0 :   if (mBogusNode) {
    9251               0 :     mEditor->DeleteNode(mBogusNode);
    9252               0 :     mBogusNode = nsnull;
    9253                 :   }
    9254                 : 
    9255                 :   // Try to recreate the bogus node if needed.
    9256               0 :   CreateBogusNodeIfNeeded(selection);
    9257                 : }

Generated by: LCOV version 1.7