LCOV - app.info - editor/libeditor/html/nsHTMLEditRules.cpp

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