LCOV - code coverage report
Current view: directory - editor/libeditor/base - nsEditor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2339 2 0.1 %
Date: 2012-06-02 Functions: 213 2 0.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *   Daniel Glazman <glazman@netscape.com>
      25                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      26                 :  *   Mats Palmgren <matspal@gmail.com>
      27                 :  *   Jesper Kristensen <mail@jesperkristensen.dk>
      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 "pratom.h"
      44                 : #include "nsIDOMDocument.h"
      45                 : #include "nsIDOMHTMLElement.h"
      46                 : #include "nsIDOMNSEvent.h"
      47                 : #include "nsIMEStateManager.h"
      48                 : #include "nsFocusManager.h"
      49                 : #include "nsUnicharUtils.h"
      50                 : #include "nsReadableUtils.h"
      51                 : #include "nsIObserverService.h"
      52                 : #include "mozilla/Services.h"
      53                 : #include "mozISpellCheckingEngine.h"
      54                 : #include "nsIEditorSpellCheck.h"
      55                 : #include "mozInlineSpellChecker.h"
      56                 : 
      57                 : #include "nsIDOMText.h"
      58                 : #include "nsIDOMElement.h"
      59                 : #include "nsIDOMAttr.h"
      60                 : #include "nsIDOMNode.h"
      61                 : #include "nsIDOMDocumentFragment.h"
      62                 : #include "nsIDOMNamedNodeMap.h"
      63                 : #include "nsIDOMNodeList.h"
      64                 : #include "nsIDOMRange.h"
      65                 : #include "nsIDOMHTMLBRElement.h"
      66                 : #include "nsIDocument.h"
      67                 : #include "nsITransactionManager.h"
      68                 : #include "nsIAbsorbingTransaction.h"
      69                 : #include "nsIPresShell.h"
      70                 : #include "nsISelection.h"
      71                 : #include "nsISelectionPrivate.h"
      72                 : #include "nsISelectionController.h"
      73                 : #include "nsIEnumerator.h"
      74                 : #include "nsEditProperty.h"
      75                 : #include "nsIAtom.h"
      76                 : #include "nsCaret.h"
      77                 : #include "nsIWidget.h"
      78                 : #include "nsIPlaintextEditor.h"
      79                 : #include "nsIPrivateDOMEvent.h"
      80                 : #include "nsGUIEvent.h"
      81                 : 
      82                 : #include "nsIFrame.h"  // Needed by IME code
      83                 : 
      84                 : #include "nsCSSStyleSheet.h"
      85                 : 
      86                 : #include "nsIContent.h"
      87                 : #include "nsDOMString.h"
      88                 : #include "nsServiceManagerUtils.h"
      89                 : 
      90                 : // transactions the editor knows how to build
      91                 : #include "EditAggregateTxn.h"
      92                 : #include "PlaceholderTxn.h"
      93                 : #include "ChangeAttributeTxn.h"
      94                 : #include "CreateElementTxn.h"
      95                 : #include "InsertElementTxn.h"
      96                 : #include "DeleteElementTxn.h"
      97                 : #include "InsertTextTxn.h"
      98                 : #include "DeleteTextTxn.h"
      99                 : #include "DeleteRangeTxn.h"
     100                 : #include "SplitElementTxn.h"
     101                 : #include "JoinElementTxn.h"
     102                 : #include "nsStyleSheetTxns.h"
     103                 : #include "IMETextTxn.h"
     104                 : #include "nsString.h"
     105                 : 
     106                 : #include "nsEditor.h"
     107                 : #include "nsEditorUtils.h"
     108                 : #include "nsEditorEventListener.h"
     109                 : #include "nsISelectionDisplay.h"
     110                 : #include "nsIInlineSpellChecker.h"
     111                 : #include "nsINameSpaceManager.h"
     112                 : #include "nsIHTMLDocument.h"
     113                 : #include "nsIParserService.h"
     114                 : 
     115                 : #include "nsITransferable.h"
     116                 : #include "nsComputedDOMStyle.h"
     117                 : #include "nsTextEditUtils.h"
     118                 : #include "nsComputedDOMStyle.h"
     119                 : 
     120                 : #include "mozilla/FunctionTimer.h"
     121                 : #include "mozilla/Preferences.h"
     122                 : #include "mozilla/dom/Element.h"
     123                 : #include "nsContentUtils.h"
     124                 : #include "nsCCUncollectableMarker.h"
     125                 : 
     126                 : #define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1)
     127                 : #define NS_ERROR_EDITOR_NO_TEXTNODE  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2)
     128                 : 
     129                 : #ifdef NS_DEBUG_EDITOR
     130                 : static bool gNoisy = false;
     131                 : #endif
     132                 : 
     133                 : #ifdef DEBUG
     134                 : #include "nsIDOMHTMLDocument.h"
     135                 : #endif
     136                 : 
     137                 : using namespace mozilla;
     138                 : using namespace mozilla::widget;
     139                 : 
     140                 : // Defined in nsEditorRegistration.cpp
     141                 : extern nsIParserService *sParserService;
     142                 : 
     143                 : //---------------------------------------------------------------------------
     144                 : //
     145                 : // nsEditor: base editor class implementation
     146                 : //
     147                 : //---------------------------------------------------------------------------
     148                 : 
     149               0 : nsEditor::nsEditor()
     150                 : :  mModCount(0)
     151                 : ,  mFlags(0)
     152                 : ,  mUpdateCount(0)
     153                 : ,  mSpellcheckCheckboxState(eTriUnset)
     154                 : ,  mPlaceHolderTxn(nsnull)
     155                 : ,  mPlaceHolderName(nsnull)
     156                 : ,  mPlaceHolderBatch(0)
     157                 : ,  mSelState(nsnull)
     158                 : ,  mSavedSel()
     159                 : ,  mRangeUpdater()
     160                 : ,  mAction(nsnull)
     161                 : ,  mDirection(eNone)
     162                 : ,  mIMETextNode(nsnull)
     163                 : ,  mIMETextOffset(0)
     164                 : ,  mIMEBufferLength(0)
     165                 : ,  mInIMEMode(false)
     166                 : ,  mIsIMEComposing(false)
     167                 : ,  mShouldTxnSetSelection(true)
     168                 : ,  mDidPreDestroy(false)
     169                 : ,  mDidPostCreate(false)
     170                 : ,  mDocDirtyState(-1)
     171                 : ,  mDocWeak(nsnull)
     172                 : ,  mPhonetic(nsnull)
     173               0 : ,  mLastKeypressEventWasTrusted(eTriUnset)
     174                 : {
     175                 :   //initialize member variables here
     176               0 : }
     177                 : 
     178               0 : nsEditor::~nsEditor()
     179                 : {
     180               0 :   NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?");
     181                 : 
     182               0 :   mTxnMgr = nsnull;
     183                 : 
     184               0 :   delete mPhonetic;
     185               0 : }
     186                 : 
     187            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsEditor)
     188                 : 
     189               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEditor)
     190               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRootElement)
     191               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInlineSpellChecker)
     192               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTxnMgr)
     193               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mIMETextRangeList)
     194               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mIMETextNode)
     195               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mActionListeners)
     196               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mEditorObservers)
     197               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mDocStateListeners)
     198               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventTarget)
     199               0 :  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventListener)
     200               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     201                 : 
     202               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor)
     203                 :  nsIDocument* currentDoc =
     204               0 :    tmp->mRootElement ? tmp->mRootElement->GetCurrentDoc() : nsnull;
     205               0 :  if (currentDoc &&
     206               0 :      nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
     207               0 :    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
     208                 :  }
     209               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRootElement)
     210               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInlineSpellChecker)
     211               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTxnMgr)
     212               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIMETextRangeList)
     213               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIMETextNode)
     214               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mActionListeners)
     215               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mEditorObservers)
     216               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mDocStateListeners)
     217               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventTarget)
     218               0 :  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventListener)
     219               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     220                 : 
     221               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor)
     222               0 :  NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
     223               0 :  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     224               0 :  NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport)
     225               0 :  NS_INTERFACE_MAP_ENTRY(nsIEditor)
     226               0 :  NS_INTERFACE_MAP_ENTRY(nsIObserver)
     227               0 :  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
     228               0 : NS_INTERFACE_MAP_END
     229                 : 
     230               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditor)
     231               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditor)
     232                 : 
     233                 : 
     234                 : NS_IMETHODIMP
     235               0 : nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
     236                 : {
     237               0 :   NS_PRECONDITION(aDoc, "bad arg");
     238               0 :   if (!aDoc)
     239               0 :     return NS_ERROR_NULL_POINTER;
     240                 : 
     241                 :   // First only set flags, but other stuff shouldn't be initialized now.
     242                 :   // Don't move this call after initializing mDocWeak.
     243                 :   // SetFlags() can check whether it's called during initialization or not by
     244                 :   // them.  Note that SetFlags() will be called by PostCreate().
     245                 : #ifdef DEBUG
     246                 :   nsresult rv =
     247                 : #endif
     248               0 :   SetFlags(aFlags);
     249               0 :   NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
     250                 : 
     251               0 :   mDocWeak = do_GetWeakReference(aDoc);  // weak reference to doc
     252                 :   // HTML editors currently don't have their own selection controller,
     253                 :   // so they'll pass null as aSelCon, and we'll get the selection controller
     254                 :   // off of the presshell.
     255               0 :   nsCOMPtr<nsISelectionController> selCon;
     256               0 :   if (aSelCon) {
     257               0 :     mSelConWeak = do_GetWeakReference(aSelCon);   // weak reference to selectioncontroller
     258               0 :     selCon = aSelCon;
     259                 :   } else {
     260               0 :     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     261               0 :     selCon = do_QueryInterface(presShell);
     262                 :   }
     263               0 :   NS_ASSERTION(selCon, "Selection controller should be available at this point");
     264                 : 
     265                 :   //set up root element if we are passed one.  
     266               0 :   if (aRoot)
     267               0 :     mRootElement = do_QueryInterface(aRoot);
     268                 : 
     269               0 :   mUpdateCount=0;
     270                 : 
     271                 :   /* initialize IME stuff */
     272               0 :   mIMETextNode = nsnull;
     273               0 :   mIMETextOffset = 0;
     274               0 :   mIMEBufferLength = 0;
     275                 :   
     276                 :   /* Show the caret */
     277               0 :   selCon->SetCaretReadOnly(false);
     278               0 :   selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
     279                 : 
     280               0 :   selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user
     281                 : 
     282               0 :   NS_POSTCONDITION(mDocWeak, "bad state");
     283                 : 
     284                 :   // Make sure that the editor will be destroyed properly
     285               0 :   mDidPreDestroy = false;
     286                 :   // Make sure that the ediotr will be created properly
     287               0 :   mDidPostCreate = false;
     288                 : 
     289               0 :   return NS_OK;
     290                 : }
     291                 : 
     292                 : 
     293                 : NS_IMETHODIMP
     294               0 : nsEditor::PostCreate()
     295                 : {
     296                 :   // Synchronize some stuff for the flags.  SetFlags() will initialize
     297                 :   // something by the flag difference.  This is first time of that, so, all
     298                 :   // initializations must be run.  For such reason, we need to invert mFlags
     299                 :   // value first.
     300               0 :   mFlags = ~mFlags;
     301               0 :   nsresult rv = SetFlags(~mFlags);
     302               0 :   NS_ENSURE_SUCCESS(rv, rv);
     303                 : 
     304                 :   // These operations only need to happen on the first PostCreate call
     305               0 :   if (!mDidPostCreate) {
     306               0 :     mDidPostCreate = true;
     307                 : 
     308                 :     // Set up listeners
     309               0 :     CreateEventListeners();
     310               0 :     rv = InstallEventListeners();
     311               0 :     NS_ENSURE_SUCCESS(rv, rv);
     312                 : 
     313                 :     // nuke the modification count, so the doc appears unmodified
     314                 :     // do this before we notify listeners
     315               0 :     ResetModificationCount();
     316                 : 
     317                 :     // update the UI with our state
     318               0 :     NotifyDocumentListeners(eDocumentCreated);
     319               0 :     NotifyDocumentListeners(eDocumentStateChanged);
     320                 : 
     321               0 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     322               0 :     if (obs) {
     323               0 :       obs->AddObserver(this,
     324                 :                        SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
     325               0 :                        false);
     326                 :     }
     327                 :   }
     328                 : 
     329                 :   // update nsTextStateManager and caret if we have focus
     330               0 :   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
     331               0 :   if (focusedContent) {
     332               0 :     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     333               0 :     NS_ASSERTION(ps, "no pres shell even though we have focus");
     334               0 :     NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED);
     335               0 :     nsPresContext* pc = ps->GetPresContext(); 
     336                 : 
     337               0 :     nsIMEStateManager::OnTextStateBlur(pc, nsnull);
     338               0 :     nsIMEStateManager::OnTextStateFocus(pc, focusedContent);
     339                 : 
     340               0 :     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(focusedContent);
     341               0 :     if (target) {
     342               0 :       InitializeSelection(target);
     343                 :     }
     344                 : 
     345                 :     // If the text control gets reframed during focus, Focus() would not be
     346                 :     // called, so take a chance here to see if we need to spell check the text
     347                 :     // control.
     348                 :     nsEditorEventListener* listener =
     349               0 :       reinterpret_cast<nsEditorEventListener*> (mEventListener.get());
     350               0 :     listener->SpellCheckIfNeeded();
     351                 :   }
     352               0 :   return NS_OK;
     353                 : }
     354                 : 
     355                 : /* virtual */
     356                 : void
     357               0 : nsEditor::CreateEventListeners()
     358                 : {
     359                 :   // Don't create the handler twice
     360               0 :   if (!mEventListener) {
     361               0 :     mEventListener = new nsEditorEventListener();
     362                 :   }
     363               0 : }
     364                 : 
     365                 : nsresult
     366               0 : nsEditor::InstallEventListeners()
     367                 : {
     368               0 :   NS_ENSURE_TRUE(mDocWeak && mEventListener,
     369                 :                  NS_ERROR_NOT_INITIALIZED);
     370                 : 
     371                 :   // Initialize the event target.
     372               0 :   nsCOMPtr<nsIContent> rootContent = do_QueryInterface(GetRoot());
     373               0 :   NS_ENSURE_TRUE(rootContent, NS_ERROR_NOT_AVAILABLE);
     374               0 :   mEventTarget = do_QueryInterface(rootContent->GetParent());
     375               0 :   NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_AVAILABLE);
     376                 : 
     377                 :   nsEditorEventListener* listener =
     378               0 :     reinterpret_cast<nsEditorEventListener*>(mEventListener.get());
     379               0 :   return listener->Connect(this);
     380                 : }
     381                 : 
     382                 : void
     383               0 : nsEditor::RemoveEventListeners()
     384                 : {
     385               0 :   if (!mDocWeak || !mEventListener) {
     386               0 :     return;
     387                 :   }
     388               0 :   reinterpret_cast<nsEditorEventListener*>(mEventListener.get())->Disconnect();
     389               0 :   mEventTarget = nsnull;
     390                 : }
     391                 : 
     392                 : bool
     393               0 : nsEditor::GetDesiredSpellCheckState()
     394                 : {
     395                 :   // Check user override on this element
     396               0 :   if (mSpellcheckCheckboxState != eTriUnset) {
     397               0 :     return (mSpellcheckCheckboxState == eTriTrue);
     398                 :   }
     399                 : 
     400                 :   // Check user preferences
     401               0 :   PRInt32 spellcheckLevel = Preferences::GetInt("layout.spellcheckDefault", 1);
     402                 : 
     403               0 :   if (spellcheckLevel == 0) {
     404               0 :     return false;                    // Spellchecking forced off globally
     405                 :   }
     406                 : 
     407               0 :   if (!CanEnableSpellCheck()) {
     408               0 :     return false;
     409                 :   }
     410                 : 
     411               0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     412               0 :   if (presShell) {
     413               0 :     nsPresContext* context = presShell->GetPresContext();
     414               0 :     if (context && !context->IsDynamic()) {
     415               0 :       return false;
     416                 :     }
     417                 :   }
     418                 : 
     419                 :   // Check DOM state
     420               0 :   nsCOMPtr<nsIContent> content = GetRoot();
     421               0 :   if (!content) {
     422               0 :     return false;
     423                 :   }
     424                 : 
     425               0 :   if (content->IsRootOfNativeAnonymousSubtree()) {
     426               0 :     content = content->GetParent();
     427                 :   }
     428                 : 
     429               0 :   nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(content);
     430               0 :   if (!element) {
     431               0 :     return false;
     432                 :   }
     433                 : 
     434                 :   bool enable;
     435               0 :   element->GetSpellcheck(&enable);
     436                 : 
     437               0 :   return enable;
     438                 : }
     439                 : 
     440                 : NS_IMETHODIMP
     441               0 : nsEditor::PreDestroy(bool aDestroyingFrames)
     442                 : {
     443               0 :   if (mDidPreDestroy)
     444               0 :     return NS_OK;
     445                 : 
     446               0 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     447               0 :   if (obs) {
     448               0 :     obs->RemoveObserver(this,
     449               0 :                         SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
     450                 :   }
     451                 : 
     452                 :   // Let spellchecker clean up its observers etc. It is important not to
     453                 :   // actually free the spellchecker here, since the spellchecker could have
     454                 :   // caused flush notifications, which could have gotten here if a textbox
     455                 :   // is being removed. Setting the spellchecker to NULL could free the
     456                 :   // object that is still in use! It will be freed when the editor is
     457                 :   // destroyed.
     458               0 :   if (mInlineSpellChecker)
     459               0 :     mInlineSpellChecker->Cleanup(aDestroyingFrames);
     460                 : 
     461                 :   // tell our listeners that the doc is going away
     462               0 :   NotifyDocumentListeners(eDocumentToBeDestroyed);
     463                 : 
     464                 :   // Unregister event listeners
     465               0 :   RemoveEventListeners();
     466               0 :   mActionListeners.Clear();
     467               0 :   mEditorObservers.Clear();
     468               0 :   mDocStateListeners.Clear();
     469               0 :   mInlineSpellChecker = nsnull;
     470               0 :   mSpellcheckCheckboxState = eTriUnset;
     471               0 :   mRootElement = nsnull;
     472                 : 
     473               0 :   mDidPreDestroy = true;
     474               0 :   return NS_OK;
     475                 : }
     476                 : 
     477                 : NS_IMETHODIMP
     478               0 : nsEditor::GetFlags(PRUint32 *aFlags)
     479                 : {
     480               0 :   *aFlags = mFlags;
     481               0 :   return NS_OK;
     482                 : }
     483                 : 
     484                 : NS_IMETHODIMP
     485               0 : nsEditor::SetFlags(PRUint32 aFlags)
     486                 : {
     487               0 :   if (mFlags == aFlags) {
     488               0 :     return NS_OK;
     489                 :   }
     490                 : 
     491               0 :   bool spellcheckerWasEnabled = CanEnableSpellCheck();
     492               0 :   mFlags = aFlags;
     493                 : 
     494               0 :   if (!mDocWeak) {
     495                 :     // If we're initializing, we shouldn't do anything now.
     496                 :     // SetFlags() will be called by PostCreate(),
     497                 :     // we should synchronize some stuff for the flags at that time.
     498               0 :     return NS_OK;
     499                 :   }
     500                 : 
     501                 :   // The flag change may cause the spellchecker state change
     502               0 :   if (CanEnableSpellCheck() != spellcheckerWasEnabled) {
     503               0 :     nsresult rv = SyncRealTimeSpell();
     504               0 :     NS_ENSURE_SUCCESS(rv, rv);
     505                 :   }
     506                 : 
     507                 :   // Might be changing editable state, so, we need to reset current IME state
     508                 :   // if we're focused and the flag change causes IME state change.
     509               0 :   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
     510               0 :   if (focusedContent) {
     511               0 :     IMEState newState;
     512               0 :     nsresult rv = GetPreferredIMEState(&newState);
     513               0 :     if (NS_SUCCEEDED(rv)) {
     514                 :       // NOTE: When the enabled state isn't going to be modified, this method
     515                 :       // is going to do nothing.
     516               0 :       nsIMEStateManager::UpdateIMEState(newState, focusedContent);
     517                 :     }
     518                 :   }
     519                 : 
     520               0 :   return NS_OK;
     521                 : }
     522                 : 
     523                 : NS_IMETHODIMP
     524               0 : nsEditor::GetIsSelectionEditable(bool *aIsSelectionEditable)
     525                 : {
     526               0 :   NS_ENSURE_ARG_POINTER(aIsSelectionEditable);
     527                 : 
     528                 :   // get current selection
     529               0 :   nsCOMPtr<nsISelection> selection;
     530               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
     531               0 :   NS_ENSURE_SUCCESS(res, res);
     532               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     533                 : 
     534                 :   // XXX we just check that the anchor node is editable at the moment
     535                 :   //     we should check that all nodes in the selection are editable
     536               0 :   nsCOMPtr<nsIDOMNode> anchorNode;
     537               0 :   selection->GetAnchorNode(getter_AddRefs(anchorNode));
     538               0 :   *aIsSelectionEditable = anchorNode && IsEditable(anchorNode);
     539                 : 
     540               0 :   return NS_OK;
     541                 : }
     542                 : 
     543                 : NS_IMETHODIMP
     544               0 : nsEditor::GetIsDocumentEditable(bool *aIsDocumentEditable)
     545                 : {
     546               0 :   NS_ENSURE_ARG_POINTER(aIsDocumentEditable);
     547               0 :   nsCOMPtr<nsIDOMDocument> doc;
     548               0 :   GetDocument(getter_AddRefs(doc));
     549               0 :   *aIsDocumentEditable = doc ? true : false;
     550                 : 
     551               0 :   return NS_OK;
     552                 : }
     553                 : 
     554                 : NS_IMETHODIMP 
     555               0 : nsEditor::GetDocument(nsIDOMDocument **aDoc)
     556                 : {
     557               0 :   NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
     558               0 :   *aDoc = nsnull; // init out param
     559               0 :   NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized");
     560               0 :   nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
     561               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
     562               0 :   NS_ADDREF(*aDoc = doc);
     563               0 :   return NS_OK;
     564                 : }
     565                 : 
     566                 : already_AddRefed<nsIPresShell>
     567               0 : nsEditor::GetPresShell()
     568                 : {
     569               0 :   NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak");
     570               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
     571               0 :   NS_ENSURE_TRUE(doc, NULL);
     572               0 :   nsCOMPtr<nsIPresShell> ps = doc->GetShell();
     573               0 :   return ps.forget();
     574                 : }
     575                 : 
     576                 : 
     577                 : /* attribute string contentsMIMEType; */
     578                 : NS_IMETHODIMP
     579               0 : nsEditor::GetContentsMIMEType(char * *aContentsMIMEType)
     580                 : {
     581               0 :   NS_ENSURE_ARG_POINTER(aContentsMIMEType);
     582               0 :   *aContentsMIMEType = ToNewCString(mContentMIMEType);
     583               0 :   return NS_OK;
     584                 : }
     585                 : 
     586                 : NS_IMETHODIMP
     587               0 : nsEditor::SetContentsMIMEType(const char * aContentsMIMEType)
     588                 : {
     589               0 :   mContentMIMEType.Assign(aContentsMIMEType ? aContentsMIMEType : "");
     590               0 :   return NS_OK;
     591                 : }
     592                 : 
     593                 : NS_IMETHODIMP
     594               0 : nsEditor::GetSelectionController(nsISelectionController **aSel)
     595                 : {
     596               0 :   NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
     597               0 :   *aSel = nsnull; // init out param
     598               0 :   nsCOMPtr<nsISelectionController> selCon;
     599               0 :   if (mSelConWeak) {
     600               0 :     selCon = do_QueryReferent(mSelConWeak);
     601                 :   } else {
     602               0 :     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     603               0 :     selCon = do_QueryInterface(presShell);
     604                 :   }
     605               0 :   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
     606               0 :   NS_ADDREF(*aSel = selCon);
     607               0 :   return NS_OK;
     608                 : }
     609                 : 
     610                 : 
     611                 : NS_IMETHODIMP
     612               0 : nsEditor::DeleteSelection(EDirection aAction)
     613                 : {
     614               0 :   return DeleteSelectionImpl(aAction);
     615                 : }
     616                 : 
     617                 : 
     618                 : 
     619                 : NS_IMETHODIMP
     620               0 : nsEditor::GetSelection(nsISelection **aSelection)
     621                 : {
     622               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
     623               0 :   *aSelection = nsnull;
     624               0 :   nsCOMPtr<nsISelectionController> selcon;
     625               0 :   GetSelectionController(getter_AddRefs(selcon));
     626               0 :   NS_ENSURE_TRUE(selcon, NS_ERROR_NOT_INITIALIZED);
     627               0 :   return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);  // does an addref
     628                 : }
     629                 : 
     630                 : NS_IMETHODIMP 
     631               0 : nsEditor::DoTransaction(nsITransaction *aTxn)
     632                 : {
     633                 : #ifdef NS_DEBUG_EDITOR
     634                 :   if (gNoisy) { printf("Editor::DoTransaction ----------\n"); }
     635                 : #endif
     636                 : 
     637               0 :   nsresult result = NS_OK;
     638                 :   
     639               0 :   if (mPlaceHolderBatch && !mPlaceHolderTxn)
     640                 :   {
     641                 :     // it's pretty darn amazing how many different types of pointers
     642                 :     // this transaction goes through here.  I bet this is a record.
     643                 :     
     644                 :     // We start off with an EditTxn since that's what the factory returns.
     645               0 :     nsRefPtr<EditTxn> editTxn = new PlaceholderTxn();
     646               0 :     if (!editTxn) { return NS_ERROR_OUT_OF_MEMORY; }
     647                 : 
     648                 :     // Then we QI to an nsIAbsorbingTransaction to get at placeholder functionality
     649               0 :     nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
     650               0 :     editTxn->QueryInterface(NS_GET_IID(nsIAbsorbingTransaction), getter_AddRefs(plcTxn));
     651                 :     // have to use line above instead of "plcTxn = do_QueryInterface(editTxn);"
     652                 :     // due to our broken interface model for transactions.
     653                 : 
     654                 :     // save off weak reference to placeholder txn
     655               0 :     mPlaceHolderTxn = do_GetWeakReference(plcTxn);
     656               0 :     plcTxn->Init(mPlaceHolderName, mSelState, this);
     657               0 :     mSelState = nsnull;  // placeholder txn took ownership of this pointer
     658                 : 
     659                 :     // finally we QI to an nsITransaction since that's what DoTransaction() expects
     660               0 :     nsCOMPtr<nsITransaction> theTxn = do_QueryInterface(plcTxn);
     661               0 :     DoTransaction(theTxn);  // we will recurse, but will not hit this case in the nested call
     662                 : 
     663               0 :     if (mTxnMgr)
     664                 :     {
     665               0 :       nsCOMPtr<nsITransaction> topTxn;
     666               0 :       result = mTxnMgr->PeekUndoStack(getter_AddRefs(topTxn));
     667               0 :       NS_ENSURE_SUCCESS(result, result);
     668               0 :       if (topTxn)
     669                 :       {
     670               0 :         plcTxn = do_QueryInterface(topTxn);
     671               0 :         if (plcTxn)
     672                 :         {
     673                 :           // there is a palceholder transaction on top of the undo stack.  It is 
     674                 :           // either the one we just created, or an earlier one that we are now merging
     675                 :           // into.  From here on out remember this placeholder instead of the one
     676                 :           // we just created.
     677               0 :           mPlaceHolderTxn = do_GetWeakReference(plcTxn);
     678                 :         }
     679                 :       }
     680                 :     }
     681                 :   }
     682                 : 
     683               0 :   if (aTxn)
     684                 :   {  
     685                 :     // XXX: Why are we doing selection specific batching stuff here?
     686                 :     // XXX: Most entry points into the editor have auto variables that
     687                 :     // XXX: should trigger Begin/EndUpdateViewBatch() calls that will make
     688                 :     // XXX: these selection batch calls no-ops.
     689                 :     // XXX:
     690                 :     // XXX: I suspect that this was placed here to avoid multiple
     691                 :     // XXX: selection changed notifications from happening until after
     692                 :     // XXX: the transaction was done. I suppose that can still happen
     693                 :     // XXX: if an embedding application called DoTransaction() directly
     694                 :     // XXX: to pump its own transactions through the system, but in that
     695                 :     // XXX: case, wouldn't we want to use Begin/EndUpdateViewBatch() or
     696                 :     // XXX: its auto equivalent nsAutoUpdateViewBatch to ensure that
     697                 :     // XXX: selection listeners have access to accurate frame data?
     698                 :     // XXX:
     699                 :     // XXX: Note that if we did add Begin/EndUpdateViewBatch() calls
     700                 :     // XXX: we will need to make sure that they are disabled during
     701                 :     // XXX: the init of the editor for text widgets to avoid layout
     702                 :     // XXX: re-entry during initial reflow. - kin
     703                 : 
     704                 :     // get the selection and start a batch change
     705               0 :     nsCOMPtr<nsISelection>selection;
     706               0 :     result = GetSelection(getter_AddRefs(selection));
     707               0 :     NS_ENSURE_SUCCESS(result, result);
     708               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     709               0 :     nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
     710                 : 
     711               0 :     selPrivate->StartBatchChanges();
     712                 : 
     713               0 :     if (mTxnMgr) {
     714               0 :       result = mTxnMgr->DoTransaction(aTxn);
     715                 :     }
     716                 :     else {
     717               0 :       result = aTxn->DoTransaction();
     718                 :     }
     719               0 :     if (NS_SUCCEEDED(result)) {
     720               0 :       result = DoAfterDoTransaction(aTxn);
     721                 :     }
     722                 : 
     723               0 :     selPrivate->EndBatchChanges(); // no need to check result here, don't lose result of operation
     724                 :   }
     725                 :  
     726               0 :   NS_ENSURE_SUCCESS(result, result);
     727                 : 
     728               0 :   return result;
     729                 : }
     730                 : 
     731                 : 
     732                 : NS_IMETHODIMP
     733               0 : nsEditor::EnableUndo(bool aEnable)
     734                 : {
     735               0 :   nsresult result=NS_OK;
     736                 : 
     737               0 :   if (true==aEnable)
     738                 :   {
     739               0 :     if (!mTxnMgr)
     740                 :     {
     741               0 :       mTxnMgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
     742               0 :       if (NS_FAILED(result) || !mTxnMgr) {
     743               0 :         return NS_ERROR_NOT_AVAILABLE;
     744                 :       }
     745                 :     }
     746               0 :     mTxnMgr->SetMaxTransactionCount(-1);
     747                 :   }
     748                 :   else
     749                 :   { // disable the transaction manager if it is enabled
     750               0 :     if (mTxnMgr)
     751                 :     {
     752               0 :       mTxnMgr->Clear();
     753               0 :       mTxnMgr->SetMaxTransactionCount(0);
     754                 :     }
     755                 :   }
     756                 : 
     757               0 :   return NS_OK;
     758                 : }
     759                 : 
     760                 : NS_IMETHODIMP
     761               0 : nsEditor::GetNumberOfUndoItems(PRInt32* aNumItems)
     762                 : {
     763               0 :   *aNumItems = 0;
     764               0 :   return mTxnMgr ? mTxnMgr->GetNumberOfUndoItems(aNumItems) : NS_OK;
     765                 : }
     766                 : 
     767                 : NS_IMETHODIMP
     768               0 : nsEditor::GetNumberOfRedoItems(PRInt32* aNumItems)
     769                 : {
     770               0 :   *aNumItems = 0;
     771               0 :   return mTxnMgr ? mTxnMgr->GetNumberOfRedoItems(aNumItems) : NS_OK;
     772                 : }
     773                 : 
     774                 : NS_IMETHODIMP
     775               0 : nsEditor::GetTransactionManager(nsITransactionManager* *aTxnManager)
     776                 : {
     777               0 :   NS_ENSURE_ARG_POINTER(aTxnManager);
     778                 :   
     779               0 :   *aTxnManager = NULL;
     780               0 :   NS_ENSURE_TRUE(mTxnMgr, NS_ERROR_FAILURE);
     781                 : 
     782               0 :   NS_ADDREF(*aTxnManager = mTxnMgr);
     783               0 :   return NS_OK;
     784                 : }
     785                 : 
     786                 : NS_IMETHODIMP
     787               0 : nsEditor::SetTransactionManager(nsITransactionManager *aTxnManager)
     788                 : {
     789               0 :   NS_ENSURE_TRUE(aTxnManager, NS_ERROR_FAILURE);
     790                 : 
     791               0 :   mTxnMgr = aTxnManager;
     792               0 :   return NS_OK;
     793                 : }
     794                 : 
     795                 : NS_IMETHODIMP 
     796               0 : nsEditor::Undo(PRUint32 aCount)
     797                 : {
     798                 : #ifdef NS_DEBUG_EDITOR
     799                 :   if (gNoisy) { printf("Editor::Undo ----------\n"); }
     800                 : #endif
     801                 : 
     802               0 :   ForceCompositionEnd();
     803                 : 
     804               0 :   bool hasTxnMgr, hasTransaction = false;
     805               0 :   CanUndo(&hasTxnMgr, &hasTransaction);
     806               0 :   NS_ENSURE_TRUE(hasTransaction, NS_OK);
     807                 : 
     808               0 :   nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
     809                 : 
     810               0 :   if (!mTxnMgr) {
     811               0 :     return NS_OK;
     812                 :   }
     813                 : 
     814               0 :   for (PRUint32 i = 0; i < aCount; ++i) {
     815               0 :     nsresult rv = mTxnMgr->UndoTransaction();
     816               0 :     NS_ENSURE_SUCCESS(rv, rv);
     817                 : 
     818               0 :     rv = DoAfterUndoTransaction();
     819               0 :     NS_ENSURE_SUCCESS(rv, rv);
     820                 :   }
     821                 : 
     822               0 :   return NS_OK;
     823                 : }
     824                 : 
     825                 : 
     826               0 : NS_IMETHODIMP nsEditor::CanUndo(bool *aIsEnabled, bool *aCanUndo)
     827                 : {
     828               0 :   NS_ENSURE_TRUE(aIsEnabled && aCanUndo, NS_ERROR_NULL_POINTER);
     829               0 :   *aIsEnabled = !!mTxnMgr;
     830               0 :   if (*aIsEnabled) {
     831               0 :     PRInt32 numTxns = 0;
     832               0 :     mTxnMgr->GetNumberOfUndoItems(&numTxns);
     833               0 :     *aCanUndo = !!numTxns;
     834                 :   } else {
     835               0 :     *aCanUndo = false;
     836                 :   }
     837               0 :   return NS_OK;
     838                 : }
     839                 : 
     840                 : 
     841                 : NS_IMETHODIMP 
     842               0 : nsEditor::Redo(PRUint32 aCount)
     843                 : {
     844                 : #ifdef NS_DEBUG_EDITOR
     845                 :   if (gNoisy) { printf("Editor::Redo ----------\n"); }
     846                 : #endif
     847                 : 
     848               0 :   bool hasTxnMgr, hasTransaction = false;
     849               0 :   CanRedo(&hasTxnMgr, &hasTransaction);
     850               0 :   NS_ENSURE_TRUE(hasTransaction, NS_OK);
     851                 : 
     852               0 :   nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
     853                 : 
     854               0 :   if (!mTxnMgr) {
     855               0 :     return NS_OK;
     856                 :   }
     857                 : 
     858               0 :   for (PRUint32 i = 0; i < aCount; ++i) {
     859               0 :     nsresult rv = mTxnMgr->RedoTransaction();
     860               0 :     NS_ENSURE_SUCCESS(rv, rv);
     861                 : 
     862               0 :     rv = DoAfterRedoTransaction();
     863               0 :     NS_ENSURE_SUCCESS(rv, rv);
     864                 :   }
     865                 : 
     866               0 :   return NS_OK;
     867                 : }
     868                 : 
     869                 : 
     870               0 : NS_IMETHODIMP nsEditor::CanRedo(bool *aIsEnabled, bool *aCanRedo)
     871                 : {
     872               0 :   NS_ENSURE_TRUE(aIsEnabled && aCanRedo, NS_ERROR_NULL_POINTER);
     873                 : 
     874               0 :   *aIsEnabled = !!mTxnMgr;
     875               0 :   if (*aIsEnabled) {
     876               0 :     PRInt32 numTxns = 0;
     877               0 :     mTxnMgr->GetNumberOfRedoItems(&numTxns);
     878               0 :     *aCanRedo = !!numTxns;
     879                 :   } else {
     880               0 :     *aCanRedo = false;
     881                 :   }
     882               0 :   return NS_OK;
     883                 : }
     884                 : 
     885                 : 
     886                 : NS_IMETHODIMP 
     887               0 : nsEditor::BeginTransaction()
     888                 : {
     889               0 :   BeginUpdateViewBatch();
     890                 : 
     891               0 :   if (mTxnMgr) {
     892               0 :     mTxnMgr->BeginBatch();
     893                 :   }
     894                 : 
     895               0 :   return NS_OK;
     896                 : }
     897                 : 
     898                 : NS_IMETHODIMP 
     899               0 : nsEditor::EndTransaction()
     900                 : {
     901               0 :   if (mTxnMgr) {
     902               0 :     mTxnMgr->EndBatch();
     903                 :   }
     904                 : 
     905               0 :   EndUpdateViewBatch();
     906                 : 
     907               0 :   return NS_OK;
     908                 : }
     909                 : 
     910                 : 
     911                 : // These two routines are similar to the above, but do not use
     912                 : // the transaction managers batching feature.  Instead we use
     913                 : // a placeholder transaction to wrap up any further transaction
     914                 : // while the batch is open.  The advantage of this is that
     915                 : // placeholder transactions can later merge, if needed.  Merging
     916                 : // is unavailable between transaction manager batches.
     917                 : 
     918                 : NS_IMETHODIMP 
     919               0 : nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName)
     920                 : {
     921               0 :   NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!");
     922               0 :   if (!mPlaceHolderBatch)
     923                 :   {
     924                 :     // time to turn on the batch
     925               0 :     BeginUpdateViewBatch();
     926               0 :     mPlaceHolderTxn = nsnull;
     927               0 :     mPlaceHolderName = aName;
     928               0 :     nsCOMPtr<nsISelection> selection;
     929               0 :     nsresult res = GetSelection(getter_AddRefs(selection));
     930               0 :     if (NS_SUCCEEDED(res)) {
     931               0 :       mSelState = new nsSelectionState();
     932               0 :       mSelState->SaveSelection(selection);
     933                 :     }
     934                 :   }
     935               0 :   mPlaceHolderBatch++;
     936                 : 
     937               0 :   return NS_OK;
     938                 : }
     939                 : 
     940                 : NS_IMETHODIMP 
     941               0 : nsEditor::EndPlaceHolderTransaction()
     942                 : {
     943               0 :   NS_PRECONDITION(mPlaceHolderBatch > 0, "zero or negative placeholder batch count when ending batch!");
     944               0 :   if (mPlaceHolderBatch == 1)
     945                 :   {
     946               0 :     nsCOMPtr<nsISelection>selection;
     947               0 :     GetSelection(getter_AddRefs(selection));
     948                 : 
     949               0 :     nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
     950                 : 
     951                 :     // By making the assumption that no reflow happens during the calls
     952                 :     // to EndUpdateViewBatch and ScrollSelectionIntoView, we are able to
     953                 :     // allow the selection to cache a frame offset which is used by the
     954                 :     // caret drawing code. We only enable this cache here; at other times,
     955                 :     // we have no way to know whether reflow invalidates it
     956                 :     // See bugs 35296 and 199412.
     957               0 :     if (selPrivate) {
     958               0 :       selPrivate->SetCanCacheFrameOffset(true);
     959                 :     }
     960                 : 
     961                 :     {
     962                 :       // Hide the caret here to avoid hiding it twice, once in EndUpdateViewBatch
     963                 :       // and once in ScrollSelectionIntoView.
     964               0 :       nsRefPtr<nsCaret> caret;
     965               0 :       nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     966                 : 
     967               0 :       if (presShell)
     968               0 :         caret = presShell->GetCaret();
     969                 : 
     970               0 :       StCaretHider caretHider(caret);
     971                 : 
     972                 :       // time to turn off the batch
     973               0 :       EndUpdateViewBatch();
     974                 :       // make sure selection is in view
     975                 : 
     976                 :       // After ScrollSelectionIntoView(), the pending notifications might be
     977                 :       // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
     978               0 :       ScrollSelectionIntoView(false);
     979                 :     }
     980                 : 
     981                 :     // cached for frame offset are Not available now
     982               0 :     if (selPrivate) {
     983               0 :       selPrivate->SetCanCacheFrameOffset(false);
     984                 :     }
     985                 : 
     986               0 :     if (mSelState)
     987                 :     {
     988                 :       // we saved the selection state, but never got to hand it to placeholder 
     989                 :       // (else we ould have nulled out this pointer), so destroy it to prevent leaks.
     990               0 :       delete mSelState;
     991               0 :       mSelState = nsnull;
     992                 :     }
     993               0 :     if (mPlaceHolderTxn)  // we might have never made a placeholder if no action took place
     994                 :     {
     995               0 :       nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mPlaceHolderTxn);
     996               0 :       if (plcTxn) 
     997                 :       {
     998               0 :         plcTxn->EndPlaceHolderBatch();
     999                 :       }
    1000                 :       else  
    1001                 :       {
    1002                 :         // in the future we will check to make sure undo is off here,
    1003                 :         // since that is the only known case where the placeholdertxn would disappear on us.
    1004                 :         // For now just removing the assert.
    1005                 :       }
    1006                 :       // notify editor observers of action but if composing, it's done by
    1007                 :       // text event handler.
    1008               0 :       if (!mInIMEMode) NotifyEditorObservers();
    1009                 :     }
    1010                 :   }
    1011               0 :   mPlaceHolderBatch--;
    1012                 :   
    1013               0 :   return NS_OK;
    1014                 : }
    1015                 : 
    1016                 : NS_IMETHODIMP
    1017               0 : nsEditor::ShouldTxnSetSelection(bool *aResult)
    1018                 : {
    1019               0 :   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
    1020               0 :   *aResult = mShouldTxnSetSelection;
    1021               0 :   return NS_OK;
    1022                 : }
    1023                 : 
    1024                 : NS_IMETHODIMP  
    1025               0 : nsEditor::SetShouldTxnSetSelection(bool aShould)
    1026                 : {
    1027               0 :   mShouldTxnSetSelection = aShould;
    1028               0 :   return NS_OK;
    1029                 : }
    1030                 : 
    1031                 : NS_IMETHODIMP
    1032               0 : nsEditor::GetDocumentIsEmpty(bool *aDocumentIsEmpty)
    1033                 : {
    1034               0 :   *aDocumentIsEmpty = true;
    1035                 : 
    1036               0 :   dom::Element* root = GetRoot();
    1037               0 :   NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER); 
    1038                 : 
    1039               0 :   *aDocumentIsEmpty = !root->HasChildren();
    1040               0 :   return NS_OK;
    1041                 : }
    1042                 : 
    1043                 : 
    1044                 : // XXX: the rule system should tell us which node to select all on (ie, the root, or the body)
    1045               0 : NS_IMETHODIMP nsEditor::SelectAll()
    1046                 : {
    1047               0 :   if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
    1048               0 :   ForceCompositionEnd();
    1049                 : 
    1050               0 :   nsCOMPtr<nsISelectionController> selCon;
    1051               0 :   GetSelectionController(getter_AddRefs(selCon));
    1052               0 :   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
    1053               0 :   nsCOMPtr<nsISelection> selection;
    1054               0 :   nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
    1055               0 :   if (NS_SUCCEEDED(result) && selection)
    1056                 :   {
    1057               0 :     result = SelectEntireDocument(selection);
    1058                 :   }
    1059               0 :   return result;
    1060                 : }
    1061                 : 
    1062               0 : NS_IMETHODIMP nsEditor::BeginningOfDocument()
    1063                 : {
    1064               0 :   if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
    1065                 : 
    1066                 :   // get the selection
    1067               0 :   nsCOMPtr<nsISelection> selection;
    1068               0 :   nsresult result = GetSelection(getter_AddRefs(selection));
    1069               0 :   NS_ENSURE_SUCCESS(result, result);
    1070               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
    1071                 :     
    1072                 :   // get the root element 
    1073               0 :   dom::Element* rootElement = GetRoot();
    1074               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER); 
    1075                 :   
    1076                 :   // find first editable thingy
    1077               0 :   nsCOMPtr<nsINode> firstNode = GetFirstEditableNode(rootElement);
    1078               0 :   if (!firstNode) {
    1079                 :     // just the root node, set selection to inside the root
    1080               0 :     return selection->CollapseNative(rootElement, 0);
    1081                 :   }
    1082                 : 
    1083               0 :   if (firstNode->NodeType() == nsIDOMNode::TEXT_NODE) {
    1084                 :     // If firstNode is text, set selection to beginning of the text node.
    1085               0 :     return selection->CollapseNative(firstNode, 0);
    1086                 :   }
    1087                 : 
    1088                 :   // Otherwise, it's a leaf node and we set the selection just in front of it.
    1089               0 :   nsCOMPtr<nsIContent> parent = firstNode->GetParent();
    1090               0 :   if (!parent) {
    1091               0 :     return NS_ERROR_NULL_POINTER;
    1092                 :   }
    1093                 : 
    1094               0 :   PRInt32 offsetInParent = parent->IndexOf(firstNode);
    1095               0 :   return selection->CollapseNative(parent, offsetInParent);
    1096                 : }
    1097                 : 
    1098                 : NS_IMETHODIMP
    1099               0 : nsEditor::EndOfDocument() 
    1100                 : { 
    1101               0 :   if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; } 
    1102                 :   nsresult res; 
    1103                 : 
    1104                 :   // get selection 
    1105               0 :   nsCOMPtr<nsISelection> selection; 
    1106               0 :   res = GetSelection(getter_AddRefs(selection)); 
    1107               0 :   NS_ENSURE_SUCCESS(res, res); 
    1108               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); 
    1109                 :   
    1110                 :   // get the root element 
    1111               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(GetRoot());
    1112               0 :   NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); 
    1113               0 :   nsCOMPtr<nsIDOMNode> child;
    1114                 : 
    1115               0 :   do {
    1116               0 :     node->GetLastChild(getter_AddRefs(child));
    1117                 : 
    1118               0 :     if (child) {
    1119               0 :       if (IsContainer(child)) {
    1120               0 :         node = child;
    1121                 :       } else {
    1122               0 :         break;
    1123                 :       }
    1124                 :     }
    1125               0 :   } while (child);
    1126                 : 
    1127               0 :   PRUint32 length = 0;
    1128               0 :   res = GetLengthOfDOMNode(node, length);
    1129               0 :   NS_ENSURE_SUCCESS(res, res);
    1130                 : 
    1131               0 :   return selection->Collapse(node, (PRInt32)length);
    1132                 : } 
    1133                 :   
    1134                 : NS_IMETHODIMP
    1135               0 : nsEditor::GetDocumentModified(bool *outDocModified)
    1136                 : {
    1137               0 :   NS_ENSURE_TRUE(outDocModified, NS_ERROR_NULL_POINTER);
    1138                 : 
    1139               0 :   PRInt32  modCount = 0;
    1140               0 :   GetModificationCount(&modCount);
    1141                 : 
    1142               0 :   *outDocModified = (modCount != 0);
    1143               0 :   return NS_OK;
    1144                 : }
    1145                 : 
    1146                 : NS_IMETHODIMP
    1147               0 : nsEditor::GetDocumentCharacterSet(nsACString &characterSet)
    1148                 : {
    1149               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    1150               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
    1151                 : 
    1152               0 :   characterSet = doc->GetDocumentCharacterSet();
    1153               0 :   return NS_OK;
    1154                 : }
    1155                 : 
    1156                 : NS_IMETHODIMP
    1157               0 : nsEditor::SetDocumentCharacterSet(const nsACString& characterSet)
    1158                 : {
    1159               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    1160               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
    1161                 : 
    1162               0 :   doc->SetDocumentCharacterSet(characterSet);
    1163               0 :   return NS_OK;
    1164                 : }
    1165                 : 
    1166                 : NS_IMETHODIMP
    1167               0 : nsEditor::Cut()
    1168                 : {
    1169               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1170                 : }
    1171                 : 
    1172                 : NS_IMETHODIMP
    1173               0 : nsEditor::CanCut(bool *aCanCut)
    1174                 : {
    1175               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1176                 : }
    1177                 : 
    1178                 : NS_IMETHODIMP
    1179               0 : nsEditor::Copy()
    1180                 : {
    1181               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1182                 : }
    1183                 : 
    1184                 : NS_IMETHODIMP
    1185               0 : nsEditor::CanCopy(bool *aCanCut)
    1186                 : {
    1187               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1188                 : }
    1189                 : 
    1190                 : NS_IMETHODIMP
    1191               0 : nsEditor::Paste(PRInt32 aSelectionType)
    1192                 : {
    1193               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1194                 : }
    1195                 : 
    1196                 : NS_IMETHODIMP
    1197               0 : nsEditor::PasteTransferable(nsITransferable *aTransferable)
    1198                 : {
    1199               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1200                 : }
    1201                 : 
    1202                 : NS_IMETHODIMP
    1203               0 : nsEditor::CanPaste(PRInt32 aSelectionType, bool *aCanPaste)
    1204                 : {
    1205               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1206                 : }
    1207                 : 
    1208                 : NS_IMETHODIMP
    1209               0 : nsEditor::CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste)
    1210                 : {
    1211               0 :   return NS_ERROR_NOT_IMPLEMENTED; 
    1212                 : }
    1213                 : 
    1214                 : NS_IMETHODIMP 
    1215               0 : nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, const nsAString & aValue)
    1216                 : {
    1217               0 :   nsRefPtr<ChangeAttributeTxn> txn;
    1218                 :   nsresult result = CreateTxnForSetAttribute(aElement, aAttribute, aValue,
    1219               0 :                                              getter_AddRefs(txn));
    1220               0 :   if (NS_SUCCEEDED(result))  {
    1221               0 :     result = DoTransaction(txn);  
    1222                 :   }
    1223               0 :   return result;
    1224                 : }
    1225                 : 
    1226                 : NS_IMETHODIMP 
    1227               0 : nsEditor::GetAttributeValue(nsIDOMElement *aElement, 
    1228                 :                             const nsAString & aAttribute, 
    1229                 :                             nsAString & aResultValue, 
    1230                 :                             bool *aResultIsSet)
    1231                 : {
    1232               0 :   NS_ENSURE_TRUE(aResultIsSet, NS_ERROR_NULL_POINTER);
    1233               0 :   *aResultIsSet = false;
    1234               0 :   if (!aElement) {
    1235               0 :     return NS_OK;
    1236                 :   }
    1237               0 :   nsAutoString value;
    1238               0 :   nsresult rv = aElement->GetAttribute(aAttribute, value);
    1239               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1240               0 :   if (!DOMStringIsNull(value)) {
    1241               0 :     *aResultIsSet = true;
    1242               0 :     aResultValue = value;
    1243                 :   }
    1244               0 :   return rv;
    1245                 : }
    1246                 : 
    1247                 : NS_IMETHODIMP 
    1248               0 : nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsAString& aAttribute)
    1249                 : {
    1250               0 :   nsRefPtr<ChangeAttributeTxn> txn;
    1251                 :   nsresult result = CreateTxnForRemoveAttribute(aElement, aAttribute,
    1252               0 :                                                 getter_AddRefs(txn));
    1253               0 :   if (NS_SUCCEEDED(result))  {
    1254               0 :     result = DoTransaction(txn);  
    1255                 :   }
    1256               0 :   return result;
    1257                 : }
    1258                 : 
    1259                 : 
    1260                 : NS_IMETHODIMP
    1261               0 : nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
    1262                 : {  
    1263                 :   //  mark the node dirty.
    1264               0 :   nsCOMPtr<nsIContent> element (do_QueryInterface(aNode));
    1265               0 :   if (element)
    1266                 :     element->SetAttr(kNameSpaceID_None, nsEditProperty::mozdirty,
    1267               0 :                      EmptyString(), false);
    1268               0 :   return NS_OK;
    1269                 : }
    1270                 : 
    1271               0 : NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate,
    1272                 :                                               nsIInlineSpellChecker ** aInlineSpellChecker)
    1273                 : {
    1274               0 :   NS_ENSURE_ARG_POINTER(aInlineSpellChecker);
    1275                 : 
    1276               0 :   if (mDidPreDestroy) {
    1277                 :     // Don't allow people to get or create the spell checker once the editor
    1278                 :     // is going away.
    1279               0 :     *aInlineSpellChecker = nsnull;
    1280               0 :     return autoCreate ? NS_ERROR_NOT_AVAILABLE : NS_OK;
    1281                 :   }
    1282                 : 
    1283                 :   // We don't want to show the spell checking UI if there are no spell check dictionaries available.
    1284               0 :   bool canSpell = mozInlineSpellChecker::CanEnableInlineSpellChecking();
    1285               0 :   if (!canSpell) {
    1286               0 :     *aInlineSpellChecker = nsnull;
    1287               0 :     return NS_ERROR_FAILURE;
    1288                 :   }
    1289                 : 
    1290                 :   nsresult rv;
    1291               0 :   if (!mInlineSpellChecker && autoCreate) {
    1292               0 :     mInlineSpellChecker = do_CreateInstance(MOZ_INLINESPELLCHECKER_CONTRACTID, &rv);
    1293               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1294                 :   }
    1295                 : 
    1296               0 :   if (mInlineSpellChecker) {
    1297               0 :     rv = mInlineSpellChecker->Init(this);
    1298               0 :     if (NS_FAILED(rv))
    1299               0 :       mInlineSpellChecker = nsnull;
    1300               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1301                 :   }
    1302                 : 
    1303               0 :   NS_IF_ADDREF(*aInlineSpellChecker = mInlineSpellChecker);
    1304                 : 
    1305               0 :   return NS_OK;
    1306                 : }
    1307                 : 
    1308               0 : NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
    1309                 :                                 const PRUnichar *aData)
    1310                 : {
    1311               0 :   NS_ASSERTION(!strcmp(aTopic,
    1312                 :                        SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
    1313                 :                "Unexpected observer topic");
    1314                 : 
    1315                 :   // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
    1316               0 :   SyncRealTimeSpell();
    1317                 : 
    1318                 :   // When nsIEditorSpellCheck::GetCurrentDictionary changes
    1319               0 :   if (mInlineSpellChecker) {
    1320                 :     // if the current dictionary is no longer available, find another one
    1321               0 :     nsCOMPtr<nsIEditorSpellCheck> editorSpellCheck;
    1322               0 :     mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck));
    1323               0 :     if (editorSpellCheck) {
    1324                 :       // Note: This might change the current dictionary, which may call
    1325                 :       // this observer recursively.
    1326               0 :       editorSpellCheck->CheckCurrentDictionary();
    1327                 :     }
    1328                 : 
    1329                 :     // update the inline spell checker to reflect the new current dictionary
    1330               0 :     mInlineSpellChecker->SpellCheckRange(nsnull); // causes recheck
    1331                 :   }
    1332                 : 
    1333               0 :   return NS_OK;
    1334                 : }
    1335                 : 
    1336               0 : NS_IMETHODIMP nsEditor::SyncRealTimeSpell()
    1337                 : {
    1338                 :   NS_TIME_FUNCTION;
    1339                 : 
    1340               0 :   bool enable = GetDesiredSpellCheckState();
    1341                 : 
    1342                 :   // Initializes mInlineSpellChecker
    1343               0 :   nsCOMPtr<nsIInlineSpellChecker> spellChecker;
    1344               0 :   GetInlineSpellChecker(enable, getter_AddRefs(spellChecker));
    1345                 : 
    1346               0 :   if (mInlineSpellChecker) {
    1347                 :     // We might have a mInlineSpellChecker even if there are no dictionaries
    1348                 :     // available since we don't destroy the mInlineSpellChecker when the last
    1349                 :     // dictionariy is removed, but in that case spellChecker is null
    1350               0 :     mInlineSpellChecker->SetEnableRealTimeSpell(enable && spellChecker);
    1351                 :   }
    1352                 : 
    1353               0 :   return NS_OK;
    1354                 : }
    1355                 : 
    1356               0 : NS_IMETHODIMP nsEditor::SetSpellcheckUserOverride(bool enable)
    1357                 : {
    1358               0 :   mSpellcheckCheckboxState = enable ? eTriTrue : eTriFalse;
    1359                 : 
    1360               0 :   return SyncRealTimeSpell();
    1361                 : }
    1362                 : 
    1363               0 : NS_IMETHODIMP nsEditor::CreateNode(const nsAString& aTag,
    1364                 :                                    nsIDOMNode *    aParent,
    1365                 :                                    PRInt32         aPosition,
    1366                 :                                    nsIDOMNode **   aNewNode)
    1367                 : {
    1368                 :   PRInt32 i;
    1369                 : 
    1370               0 :   nsAutoRules beginRulesSniffing(this, kOpCreateNode, nsIEditor::eNext);
    1371                 :   
    1372               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1373               0 :     mActionListeners[i]->WillCreateNode(aTag, aParent, aPosition);
    1374                 : 
    1375               0 :   nsRefPtr<CreateElementTxn> txn;
    1376                 :   nsresult result = CreateTxnForCreateElement(aTag, aParent, aPosition,
    1377               0 :                                               getter_AddRefs(txn));
    1378               0 :   if (NS_SUCCEEDED(result)) 
    1379                 :   {
    1380               0 :     result = DoTransaction(txn);  
    1381               0 :     if (NS_SUCCEEDED(result)) 
    1382                 :     {
    1383               0 :       result = txn->GetNewNode(aNewNode);
    1384               0 :       NS_ASSERTION((NS_SUCCEEDED(result)), "GetNewNode can't fail if txn::DoTransaction succeeded.");
    1385                 :     }
    1386                 :   }
    1387                 :   
    1388               0 :   mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
    1389                 :   
    1390               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1391               0 :     mActionListeners[i]->DidCreateNode(aTag, *aNewNode, aParent, aPosition, result);
    1392                 : 
    1393               0 :   return result;
    1394                 : }
    1395                 : 
    1396                 : 
    1397               0 : NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
    1398                 :                                    nsIDOMNode * aParent,
    1399                 :                                    PRInt32      aPosition)
    1400                 : {
    1401                 :   PRInt32 i;
    1402               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertNode, nsIEditor::eNext);
    1403                 : 
    1404               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1405               0 :     mActionListeners[i]->WillInsertNode(aNode, aParent, aPosition);
    1406                 : 
    1407               0 :   nsRefPtr<InsertElementTxn> txn;
    1408                 :   nsresult result = CreateTxnForInsertElement(aNode, aParent, aPosition,
    1409               0 :                                               getter_AddRefs(txn));
    1410               0 :   if (NS_SUCCEEDED(result))  {
    1411               0 :     result = DoTransaction(txn);  
    1412                 :   }
    1413                 : 
    1414               0 :   mRangeUpdater.SelAdjInsertNode(aParent, aPosition);
    1415                 : 
    1416               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1417               0 :     mActionListeners[i]->DidInsertNode(aNode, aParent, aPosition, result);
    1418                 : 
    1419               0 :   return result;
    1420                 : }
    1421                 : 
    1422                 : 
    1423                 : NS_IMETHODIMP 
    1424               0 : nsEditor::SplitNode(nsIDOMNode * aNode,
    1425                 :                     PRInt32      aOffset,
    1426                 :                     nsIDOMNode **aNewLeftNode)
    1427                 : {
    1428                 :   PRInt32 i;
    1429               0 :   nsAutoRules beginRulesSniffing(this, kOpSplitNode, nsIEditor::eNext);
    1430                 : 
    1431               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1432               0 :     mActionListeners[i]->WillSplitNode(aNode, aOffset);
    1433                 : 
    1434               0 :   nsRefPtr<SplitElementTxn> txn;
    1435               0 :   nsresult result = CreateTxnForSplitNode(aNode, aOffset, getter_AddRefs(txn));
    1436               0 :   if (NS_SUCCEEDED(result))  
    1437                 :   {
    1438               0 :     result = DoTransaction(txn);
    1439               0 :     if (NS_SUCCEEDED(result))
    1440                 :     {
    1441               0 :       result = txn->GetNewNode(aNewLeftNode);
    1442               0 :       NS_ASSERTION((NS_SUCCEEDED(result)), "result must succeeded for GetNewNode");
    1443                 :     }
    1444                 :   }
    1445                 : 
    1446               0 :   mRangeUpdater.SelAdjSplitNode(aNode, aOffset, *aNewLeftNode);
    1447                 : 
    1448               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1449                 :   {
    1450               0 :     nsIDOMNode *ptr = *aNewLeftNode;
    1451               0 :     mActionListeners[i]->DidSplitNode(aNode, aOffset, ptr, result);
    1452                 :   }
    1453                 : 
    1454               0 :   return result;
    1455                 : }
    1456                 : 
    1457                 : 
    1458                 : 
    1459                 : NS_IMETHODIMP
    1460               0 : nsEditor::JoinNodes(nsIDOMNode * aLeftNode,
    1461                 :                     nsIDOMNode * aRightNode,
    1462                 :                     nsIDOMNode * aParent)
    1463                 : {
    1464                 :   PRInt32 i, offset;
    1465               0 :   nsAutoRules beginRulesSniffing(this, kOpJoinNode, nsIEditor::ePrevious);
    1466                 : 
    1467                 :   // remember some values; later used for saved selection updating.
    1468                 :   // find the offset between the nodes to be joined.
    1469               0 :   nsresult result = GetChildOffset(aRightNode, aParent, offset);
    1470               0 :   NS_ENSURE_SUCCESS(result, result);
    1471                 :   // find the number of children of the lefthand node
    1472                 :   PRUint32 oldLeftNodeLen;
    1473               0 :   result = GetLengthOfDOMNode(aLeftNode, oldLeftNodeLen);
    1474               0 :   NS_ENSURE_SUCCESS(result, result);
    1475                 : 
    1476               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1477               0 :     mActionListeners[i]->WillJoinNodes(aLeftNode, aRightNode, aParent);
    1478                 : 
    1479               0 :   nsRefPtr<JoinElementTxn> txn;
    1480               0 :   result = CreateTxnForJoinNode(aLeftNode, aRightNode, getter_AddRefs(txn));
    1481               0 :   if (NS_SUCCEEDED(result))  {
    1482               0 :     result = DoTransaction(txn);  
    1483                 :   }
    1484                 : 
    1485               0 :   mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, aParent, offset, (PRInt32)oldLeftNodeLen);
    1486                 :   
    1487               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1488               0 :     mActionListeners[i]->DidJoinNodes(aLeftNode, aRightNode, aParent, result);
    1489                 : 
    1490               0 :   return result;
    1491                 : }
    1492                 : 
    1493                 : 
    1494               0 : NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
    1495                 : {
    1496                 :   PRInt32 i, offset;
    1497               0 :   nsCOMPtr<nsIDOMNode> parent;
    1498               0 :   nsAutoRules beginRulesSniffing(this, kOpCreateNode, nsIEditor::ePrevious);
    1499                 : 
    1500                 :   // save node location for selection updating code.
    1501               0 :   nsresult result = GetNodeLocation(aElement, address_of(parent), &offset);
    1502               0 :   NS_ENSURE_SUCCESS(result, result);
    1503                 : 
    1504               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1505               0 :     mActionListeners[i]->WillDeleteNode(aElement);
    1506                 : 
    1507               0 :   nsRefPtr<DeleteElementTxn> txn;
    1508               0 :   result = CreateTxnForDeleteElement(aElement, getter_AddRefs(txn));
    1509               0 :   if (NS_SUCCEEDED(result))  {
    1510               0 :     result = DoTransaction(txn);  
    1511                 :   }
    1512                 : 
    1513               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    1514               0 :     mActionListeners[i]->DidDeleteNode(aElement, result);
    1515                 : 
    1516               0 :   return result;
    1517                 : }
    1518                 : 
    1519                 : ///////////////////////////////////////////////////////////////////////////
    1520                 : // ReplaceContainer: replace inNode with a new node (outNode) which is contructed 
    1521                 : //                   to be of type aNodeType.  Put inNodes children into outNode.
    1522                 : //                   Callers responsibility to make sure inNode's children can 
    1523                 : //                   go in outNode.
    1524                 : nsresult
    1525               0 : nsEditor::ReplaceContainer(nsIDOMNode *inNode, 
    1526                 :                            nsCOMPtr<nsIDOMNode> *outNode, 
    1527                 :                            const nsAString &aNodeType,
    1528                 :                            const nsAString *aAttribute,
    1529                 :                            const nsAString *aValue,
    1530                 :                            bool aCloneAttributes)
    1531                 : {
    1532               0 :   NS_ENSURE_TRUE(inNode && outNode, NS_ERROR_NULL_POINTER);
    1533               0 :   nsCOMPtr<nsIDOMNode> parent;
    1534                 :   PRInt32 offset;
    1535               0 :   nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
    1536               0 :   NS_ENSURE_SUCCESS(res, res);
    1537                 : 
    1538                 :   // create new container
    1539               0 :   nsCOMPtr<nsIContent> newContent;
    1540                 : 
    1541                 :   //new call to use instead to get proper HTML element, bug# 39919
    1542               0 :   res = CreateHTMLContent(aNodeType, getter_AddRefs(newContent));
    1543               0 :   nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(newContent);
    1544               0 :   NS_ENSURE_SUCCESS(res, res);
    1545               0 :     *outNode = do_QueryInterface(elem);
    1546                 :   
    1547                 :   // set attribute if needed
    1548               0 :   if (aAttribute && aValue && !aAttribute->IsEmpty())
    1549                 :   {
    1550               0 :     res = elem->SetAttribute(*aAttribute, *aValue);
    1551               0 :     NS_ENSURE_SUCCESS(res, res);
    1552                 :   }
    1553               0 :   if (aCloneAttributes)
    1554                 :   {
    1555               0 :     nsCOMPtr<nsIDOMNode>newNode = do_QueryInterface(elem);
    1556               0 :     res = CloneAttributes(newNode, inNode);
    1557               0 :     NS_ENSURE_SUCCESS(res, res);
    1558                 :   }
    1559                 :   
    1560                 :   // notify our internal selection state listener
    1561                 :   // (Note: A nsAutoSelectionReset object must be created
    1562                 :   //  before calling this to initialize mRangeUpdater)
    1563               0 :   nsAutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, inNode, *outNode);
    1564                 :   {
    1565               0 :     nsAutoTxnsConserveSelection conserveSelection(this);
    1566               0 :     nsCOMPtr<nsIDOMNode> child;
    1567                 :     bool bHasMoreChildren;
    1568               0 :     inNode->HasChildNodes(&bHasMoreChildren);
    1569               0 :     while (bHasMoreChildren)
    1570                 :     {
    1571               0 :       inNode->GetFirstChild(getter_AddRefs(child));
    1572               0 :       res = DeleteNode(child);
    1573               0 :       NS_ENSURE_SUCCESS(res, res);
    1574                 : 
    1575               0 :       res = InsertNode(child, *outNode, -1);
    1576               0 :       NS_ENSURE_SUCCESS(res, res);
    1577               0 :       inNode->HasChildNodes(&bHasMoreChildren);
    1578                 :     }
    1579                 :   }
    1580                 :   // insert new container into tree
    1581               0 :   res = InsertNode( *outNode, parent, offset);
    1582               0 :   NS_ENSURE_SUCCESS(res, res);
    1583                 :   
    1584                 :   // delete old container
    1585               0 :   return DeleteNode(inNode);
    1586                 : }
    1587                 : 
    1588                 : ///////////////////////////////////////////////////////////////////////////
    1589                 : // RemoveContainer: remove inNode, reparenting its children into their
    1590                 : //                  the parent of inNode
    1591                 : //
    1592                 : nsresult
    1593               0 : nsEditor::RemoveContainer(nsINode* aNode)
    1594                 : {
    1595               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
    1596               0 :   return RemoveContainer(node);
    1597                 : }
    1598                 : 
    1599                 : nsresult
    1600               0 : nsEditor::RemoveContainer(nsIDOMNode *inNode)
    1601                 : {
    1602               0 :   NS_ENSURE_TRUE(inNode, NS_ERROR_NULL_POINTER);
    1603               0 :   nsCOMPtr<nsIDOMNode> parent;
    1604                 :   PRInt32 offset;
    1605                 :   
    1606               0 :   nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
    1607               0 :   NS_ENSURE_SUCCESS(res, res);
    1608                 :   
    1609                 :   // loop through the child nodes of inNode and promote them
    1610                 :   // into inNode's parent.
    1611                 :   bool bHasMoreChildren;
    1612               0 :   inNode->HasChildNodes(&bHasMoreChildren);
    1613               0 :   nsCOMPtr<nsIDOMNodeList> nodeList;
    1614               0 :   res = inNode->GetChildNodes(getter_AddRefs(nodeList));
    1615               0 :   NS_ENSURE_SUCCESS(res, res);
    1616               0 :   NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
    1617                 :   PRUint32 nodeOrigLen;
    1618               0 :   nodeList->GetLength(&nodeOrigLen);
    1619                 : 
    1620                 :   // notify our internal selection state listener
    1621               0 :   nsAutoRemoveContainerSelNotify selNotify(mRangeUpdater, inNode, parent, offset, nodeOrigLen);
    1622                 :                                    
    1623               0 :   nsCOMPtr<nsIDOMNode> child;
    1624               0 :   while (bHasMoreChildren)
    1625                 :   {
    1626               0 :     inNode->GetLastChild(getter_AddRefs(child));
    1627               0 :     res = DeleteNode(child);
    1628               0 :     NS_ENSURE_SUCCESS(res, res);
    1629               0 :     res = InsertNode(child, parent, offset);
    1630               0 :     NS_ENSURE_SUCCESS(res, res);
    1631               0 :     inNode->HasChildNodes(&bHasMoreChildren);
    1632                 :   }
    1633               0 :   return DeleteNode(inNode);
    1634                 : }
    1635                 : 
    1636                 : 
    1637                 : ///////////////////////////////////////////////////////////////////////////
    1638                 : // InsertContainerAbove:  insert a new parent for inNode, returned in outNode,
    1639                 : //                   which is contructed to be of type aNodeType.  outNode becomes
    1640                 : //                   a child of inNode's earlier parent.
    1641                 : //                   Callers responsibility to make sure inNode's can be child
    1642                 : //                   of outNode, and outNode can be child of old parent.
    1643                 : nsresult
    1644               0 : nsEditor::InsertContainerAbove( nsIDOMNode *inNode, 
    1645                 :                                 nsCOMPtr<nsIDOMNode> *outNode, 
    1646                 :                                 const nsAString &aNodeType,
    1647                 :                                 const nsAString *aAttribute,
    1648                 :                                 const nsAString *aValue)
    1649                 : {
    1650               0 :   NS_ENSURE_TRUE(inNode && outNode, NS_ERROR_NULL_POINTER);
    1651               0 :   nsCOMPtr<nsIDOMNode> parent;
    1652                 :   PRInt32 offset;
    1653               0 :   nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
    1654               0 :   NS_ENSURE_SUCCESS(res, res);
    1655                 : 
    1656                 :   // create new container
    1657               0 :   nsCOMPtr<nsIContent> newContent;
    1658                 : 
    1659                 :   //new call to use instead to get proper HTML element, bug# 39919
    1660               0 :   res = CreateHTMLContent(aNodeType, getter_AddRefs(newContent));
    1661               0 :   nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(newContent);
    1662               0 :   NS_ENSURE_SUCCESS(res, res);
    1663               0 :   *outNode = do_QueryInterface(elem);
    1664                 :   
    1665                 :   // set attribute if needed
    1666               0 :   if (aAttribute && aValue && !aAttribute->IsEmpty())
    1667                 :   {
    1668               0 :     res = elem->SetAttribute(*aAttribute, *aValue);
    1669               0 :     NS_ENSURE_SUCCESS(res, res);
    1670                 :   }
    1671                 :   
    1672                 :   // notify our internal selection state listener
    1673               0 :   nsAutoInsertContainerSelNotify selNotify(mRangeUpdater);
    1674                 :   
    1675                 :   // put inNode in new parent, outNode
    1676               0 :   res = DeleteNode(inNode);
    1677               0 :   NS_ENSURE_SUCCESS(res, res);
    1678                 : 
    1679                 :   {
    1680               0 :     nsAutoTxnsConserveSelection conserveSelection(this);
    1681               0 :     res = InsertNode(inNode, *outNode, 0);
    1682               0 :     NS_ENSURE_SUCCESS(res, res);
    1683                 :   }
    1684                 : 
    1685                 :   // put new parent in doc
    1686               0 :   return InsertNode(*outNode, parent, offset);
    1687                 : }
    1688                 : 
    1689                 : ///////////////////////////////////////////////////////////////////////////
    1690                 : // MoveNode:  move aNode to {aParent,aOffset}
    1691                 : nsresult
    1692               0 : nsEditor::MoveNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
    1693                 : {
    1694               0 :   NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
    1695                 : 
    1696               0 :   nsCOMPtr<nsIDOMNode> oldParent;
    1697                 :   PRInt32 oldOffset;
    1698               0 :   nsresult res = GetNodeLocation(aNode, address_of(oldParent), &oldOffset);
    1699                 :   
    1700               0 :   if (aOffset == -1)
    1701                 :   {
    1702                 :     PRUint32 unsignedOffset;
    1703                 :     // magic value meaning "move to end of aParent"
    1704               0 :     res = GetLengthOfDOMNode(aParent, unsignedOffset);
    1705               0 :     NS_ENSURE_SUCCESS(res, res);
    1706               0 :     aOffset = (PRInt32)unsignedOffset;
    1707                 :   }
    1708                 :   
    1709                 :   // don't do anything if it's already in right place
    1710               0 :   if ((aParent == oldParent.get()) && (oldOffset == aOffset)) return NS_OK;
    1711                 :   
    1712                 :   // notify our internal selection state listener
    1713               0 :   nsAutoMoveNodeSelNotify selNotify(mRangeUpdater, oldParent, oldOffset, aParent, aOffset);
    1714                 :   
    1715                 :   // need to adjust aOffset if we are moving aNode further along in its current parent
    1716               0 :   if ((aParent == oldParent.get()) && (oldOffset < aOffset)) 
    1717                 :   {
    1718               0 :     aOffset--;  // this is because when we delete aNode, it will make the offsets after it off by one
    1719                 :   }
    1720                 : 
    1721                 :   // put aNode in new parent
    1722               0 :   res = DeleteNode(aNode);
    1723               0 :   NS_ENSURE_SUCCESS(res, res);
    1724               0 :   return InsertNode(aNode, aParent, aOffset);
    1725                 : }
    1726                 : 
    1727                 : 
    1728                 : NS_IMETHODIMP
    1729               0 : nsEditor::AddEditorObserver(nsIEditorObserver *aObserver)
    1730                 : {
    1731                 :   // we don't keep ownership of the observers.  They must
    1732                 :   // remove themselves as observers before they are destroyed.
    1733                 :   
    1734               0 :   NS_ENSURE_TRUE(aObserver, NS_ERROR_NULL_POINTER);
    1735                 : 
    1736                 :   // Make sure the listener isn't already on the list
    1737               0 :   if (mEditorObservers.IndexOf(aObserver) == -1) 
    1738                 :   {
    1739               0 :     if (!mEditorObservers.AppendObject(aObserver))
    1740               0 :       return NS_ERROR_FAILURE;
    1741                 :   }
    1742                 : 
    1743               0 :   return NS_OK;
    1744                 : }
    1745                 : 
    1746                 : 
    1747                 : NS_IMETHODIMP
    1748               0 : nsEditor::RemoveEditorObserver(nsIEditorObserver *aObserver)
    1749                 : {
    1750               0 :   NS_ENSURE_TRUE(aObserver, NS_ERROR_FAILURE);
    1751                 : 
    1752               0 :   if (!mEditorObservers.RemoveObject(aObserver))
    1753               0 :     return NS_ERROR_FAILURE;
    1754                 : 
    1755               0 :   return NS_OK;
    1756                 : }
    1757                 : 
    1758               0 : void nsEditor::NotifyEditorObservers(void)
    1759                 : {
    1760               0 :   for (PRInt32 i = 0; i < mEditorObservers.Count(); i++)
    1761               0 :     mEditorObservers[i]->EditAction();
    1762               0 : }
    1763                 : 
    1764                 : 
    1765                 : NS_IMETHODIMP
    1766               0 : nsEditor::AddEditActionListener(nsIEditActionListener *aListener)
    1767                 : {
    1768               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
    1769                 : 
    1770                 :   // Make sure the listener isn't already on the list
    1771               0 :   if (mActionListeners.IndexOf(aListener) == -1) 
    1772                 :   {
    1773               0 :     if (!mActionListeners.AppendObject(aListener))
    1774               0 :       return NS_ERROR_FAILURE;
    1775                 :   }
    1776                 : 
    1777               0 :   return NS_OK;
    1778                 : }
    1779                 : 
    1780                 : 
    1781                 : NS_IMETHODIMP
    1782               0 : nsEditor::RemoveEditActionListener(nsIEditActionListener *aListener)
    1783                 : {
    1784               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
    1785                 : 
    1786               0 :   if (!mActionListeners.RemoveObject(aListener))
    1787               0 :     return NS_ERROR_FAILURE;
    1788                 : 
    1789               0 :   return NS_OK;
    1790                 : }
    1791                 : 
    1792                 : 
    1793                 : NS_IMETHODIMP
    1794               0 : nsEditor::AddDocumentStateListener(nsIDocumentStateListener *aListener)
    1795                 : {
    1796               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
    1797                 : 
    1798               0 :   if (mDocStateListeners.IndexOf(aListener) == -1)
    1799                 :   {
    1800               0 :     if (!mDocStateListeners.AppendObject(aListener))
    1801               0 :       return NS_ERROR_FAILURE;
    1802                 :   }
    1803                 : 
    1804               0 :   return NS_OK;
    1805                 : }
    1806                 : 
    1807                 : 
    1808                 : NS_IMETHODIMP
    1809               0 : nsEditor::RemoveDocumentStateListener(nsIDocumentStateListener *aListener)
    1810                 : {
    1811               0 :   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
    1812                 : 
    1813               0 :   if (!mDocStateListeners.RemoveObject(aListener))
    1814               0 :     return NS_ERROR_FAILURE;
    1815                 : 
    1816               0 :   return NS_OK;
    1817                 : }
    1818                 : 
    1819                 : 
    1820               0 : NS_IMETHODIMP nsEditor::OutputToString(const nsAString& aFormatType,
    1821                 :                                        PRUint32 aFlags,
    1822                 :                                        nsAString& aOutputString)
    1823                 : {
    1824                 :   // these should be implemented by derived classes.
    1825               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1826                 : }
    1827                 : 
    1828                 : NS_IMETHODIMP
    1829               0 : nsEditor::OutputToStream(nsIOutputStream* aOutputStream,
    1830                 :                          const nsAString& aFormatType,
    1831                 :                          const nsACString& aCharsetOverride,
    1832                 :                          PRUint32 aFlags)
    1833                 : {
    1834                 :   // these should be implemented by derived classes.
    1835               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1836                 : }
    1837                 : 
    1838                 : NS_IMETHODIMP
    1839               0 : nsEditor::DumpContentTree()
    1840                 : {
    1841                 : #ifdef DEBUG
    1842               0 :   nsCOMPtr<nsIContent> root = do_QueryInterface(mRootElement);
    1843               0 :   if (root)  root->List(stdout);
    1844                 : #endif
    1845               0 :   return NS_OK;
    1846                 : }
    1847                 : 
    1848                 : 
    1849                 : NS_IMETHODIMP
    1850               0 : nsEditor::DebugDumpContent()
    1851                 : {
    1852                 : #ifdef DEBUG
    1853               0 :   nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryReferent(mDocWeak);
    1854               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
    1855                 : 
    1856               0 :   nsCOMPtr<nsIDOMHTMLElement>bodyElem;
    1857               0 :   doc->GetBody(getter_AddRefs(bodyElem));
    1858               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElem);
    1859               0 :   if (content)
    1860               0 :     content->List();
    1861                 : #endif
    1862               0 :   return NS_OK;
    1863                 : }
    1864                 : 
    1865                 : 
    1866                 : NS_IMETHODIMP
    1867               0 : nsEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed)
    1868                 : {
    1869                 : #ifdef DEBUG
    1870               0 :   NS_NOTREACHED("This should never get called. Overridden by subclasses");
    1871                 : #endif
    1872               0 :   return NS_OK;
    1873                 : }
    1874                 : 
    1875                 : 
    1876                 : bool     
    1877               0 : nsEditor::ArePreservingSelection()
    1878                 : {
    1879               0 :   return !(mSavedSel.IsEmpty());
    1880                 : }
    1881                 : 
    1882                 : nsresult 
    1883               0 : nsEditor::PreserveSelectionAcrossActions(nsISelection *aSel)
    1884                 : {
    1885               0 :   mSavedSel.SaveSelection(aSel);
    1886               0 :   mRangeUpdater.RegisterSelectionState(mSavedSel);
    1887               0 :   return NS_OK;
    1888                 : }
    1889                 : 
    1890                 : nsresult 
    1891               0 : nsEditor::RestorePreservedSelection(nsISelection *aSel)
    1892                 : {
    1893               0 :   if (mSavedSel.IsEmpty()) return NS_ERROR_FAILURE;
    1894               0 :   mSavedSel.RestoreSelection(aSel);
    1895               0 :   StopPreservingSelection();
    1896               0 :   return NS_OK;
    1897                 : }
    1898                 : 
    1899                 : void     
    1900               0 : nsEditor::StopPreservingSelection()
    1901                 : {
    1902               0 :   mRangeUpdater.DropSelectionState(mSavedSel);
    1903               0 :   mSavedSel.MakeEmpty();
    1904               0 : }
    1905                 : 
    1906                 : 
    1907                 : nsresult
    1908               0 : nsEditor::BeginIMEComposition()
    1909                 : {
    1910               0 :   mInIMEMode = true;
    1911               0 :   if (mPhonetic) {
    1912               0 :     mPhonetic->Truncate(0);
    1913                 :   }
    1914               0 :   return NS_OK;
    1915                 : }
    1916                 : 
    1917                 : nsresult
    1918               0 : nsEditor::EndIMEComposition()
    1919                 : {
    1920               0 :   NS_ENSURE_TRUE(mInIMEMode, NS_OK); // nothing to do
    1921                 : 
    1922               0 :   nsresult rv = NS_OK;
    1923                 : 
    1924                 :   // commit the IME transaction..we can get at it via the transaction mgr.
    1925                 :   // Note that this means IME won't work without an undo stack!
    1926               0 :   if (mTxnMgr) {
    1927               0 :     nsCOMPtr<nsITransaction> txn;
    1928               0 :     rv = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));
    1929               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "PeekUndoStack() failed");
    1930               0 :     nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
    1931               0 :     if (plcTxn) {
    1932               0 :       rv = plcTxn->Commit();
    1933               0 :       NS_ASSERTION(NS_SUCCEEDED(rv),
    1934                 :                    "nsIAbsorbingTransaction::Commit() failed");
    1935                 :     }
    1936                 :   }
    1937                 : 
    1938                 :   /* reset the data we need to construct a transaction */
    1939               0 :   mIMETextNode = nsnull;
    1940               0 :   mIMETextOffset = 0;
    1941               0 :   mIMEBufferLength = 0;
    1942               0 :   mInIMEMode = false;
    1943               0 :   mIsIMEComposing = false;
    1944                 : 
    1945                 :   // notify editor observers of action
    1946               0 :   NotifyEditorObservers();
    1947                 : 
    1948               0 :   return rv;
    1949                 : }
    1950                 : 
    1951                 : 
    1952                 : NS_IMETHODIMP
    1953               0 : nsEditor::GetPhonetic(nsAString& aPhonetic)
    1954                 : {
    1955               0 :   if (mPhonetic)
    1956               0 :     aPhonetic = *mPhonetic;
    1957                 :   else
    1958               0 :     aPhonetic.Truncate(0);
    1959                 : 
    1960               0 :   return NS_OK;
    1961                 : }
    1962                 : 
    1963                 : 
    1964                 : static nsresult
    1965               0 : GetEditorContentWindow(dom::Element *aRoot, nsIWidget **aResult)
    1966                 : {
    1967               0 :   NS_ENSURE_TRUE(aRoot && aResult, NS_ERROR_NULL_POINTER);
    1968                 : 
    1969               0 :   *aResult = 0;
    1970                 : 
    1971                 :   // Not ref counted
    1972               0 :   nsIFrame *frame = aRoot->GetPrimaryFrame();
    1973                 : 
    1974               0 :   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
    1975                 : 
    1976               0 :   *aResult = frame->GetNearestWidget();
    1977               0 :   NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
    1978                 : 
    1979               0 :   NS_ADDREF(*aResult);
    1980               0 :   return NS_OK;
    1981                 : }
    1982                 : 
    1983                 : nsresult
    1984               0 : nsEditor::GetWidget(nsIWidget **aWidget)
    1985                 : {
    1986               0 :   NS_ENSURE_TRUE(aWidget, NS_ERROR_NULL_POINTER);
    1987               0 :   *aWidget = nsnull;
    1988                 : 
    1989               0 :   nsCOMPtr<nsIWidget> widget;
    1990               0 :   nsresult res = GetEditorContentWindow(GetRoot(), getter_AddRefs(widget));
    1991               0 :   NS_ENSURE_SUCCESS(res, res);
    1992               0 :   NS_ENSURE_TRUE(widget, NS_ERROR_NOT_AVAILABLE);
    1993                 : 
    1994               0 :   NS_ADDREF(*aWidget = widget);
    1995                 : 
    1996               0 :   return NS_OK;
    1997                 : }
    1998                 : 
    1999                 : NS_IMETHODIMP
    2000               0 : nsEditor::ForceCompositionEnd()
    2001                 : {
    2002                 : 
    2003                 : // We can test mInIMEMode and do some optimization for Mac and Window
    2004                 : // Howerver, since UNIX support over-the-spot, we cannot rely on that 
    2005                 : // flag for Unix.
    2006                 : // We should use LookAndFeel to resolve this
    2007                 : 
    2008                 : #if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2)
    2009                 :   // XXXmnakano see bug 558976, ResetInputState() has two meaning which are
    2010                 :   // "commit the composition" and "cursor is moved".  This method name is
    2011                 :   // "ForceCompositionEnd", so, ResetInputState() should be used only for the
    2012                 :   // former here.  However, ResetInputState() is also used for the latter here
    2013                 :   // because even if we don't have composition, we call ResetInputState() on
    2014                 :   // Linux.  Currently, nsGtkIMModule can know the timing of the cursor move,
    2015                 :   // so, the latter meaning should be gone and we should remove this #if.
    2016                 :   if(! mInIMEMode)
    2017                 :     return NS_OK;
    2018                 : #endif
    2019                 : 
    2020               0 :   nsCOMPtr<nsIWidget> widget;
    2021               0 :   nsresult res = GetWidget(getter_AddRefs(widget));
    2022               0 :   NS_ENSURE_SUCCESS(res, res);
    2023                 : 
    2024               0 :   if (widget) {
    2025               0 :     res = widget->ResetInputState();
    2026               0 :     NS_ENSURE_SUCCESS(res, res);
    2027                 :   }
    2028                 : 
    2029               0 :   return NS_OK;
    2030                 : }
    2031                 : 
    2032                 : NS_IMETHODIMP
    2033               0 : nsEditor::GetPreferredIMEState(IMEState *aState)
    2034                 : {
    2035               0 :   NS_ENSURE_ARG_POINTER(aState);
    2036               0 :   aState->mEnabled = IMEState::ENABLED;
    2037               0 :   aState->mOpen = IMEState::DONT_CHANGE_OPEN_STATE;
    2038                 : 
    2039               0 :   if (IsReadonly() || IsDisabled()) {
    2040               0 :     aState->mEnabled = IMEState::DISABLED;
    2041               0 :     return NS_OK;
    2042                 :   }
    2043                 : 
    2044               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(GetRoot());
    2045               0 :   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
    2046                 : 
    2047               0 :   nsIFrame* frame = content->GetPrimaryFrame();
    2048               0 :   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
    2049                 : 
    2050               0 :   switch (frame->GetStyleUIReset()->mIMEMode) {
    2051                 :     case NS_STYLE_IME_MODE_AUTO:
    2052               0 :       if (IsPasswordEditor())
    2053               0 :         aState->mEnabled = IMEState::PASSWORD;
    2054               0 :       break;
    2055                 :     case NS_STYLE_IME_MODE_DISABLED:
    2056                 :       // we should use password state for |ime-mode: disabled;|.
    2057               0 :       aState->mEnabled = IMEState::PASSWORD;
    2058               0 :       break;
    2059                 :     case NS_STYLE_IME_MODE_ACTIVE:
    2060               0 :       aState->mOpen = IMEState::OPEN;
    2061               0 :       break;
    2062                 :     case NS_STYLE_IME_MODE_INACTIVE:
    2063               0 :       aState->mOpen = IMEState::CLOSED;
    2064               0 :       break;
    2065                 :   }
    2066                 : 
    2067               0 :   return NS_OK;
    2068                 : }
    2069                 : 
    2070                 : NS_IMETHODIMP
    2071               0 : nsEditor::GetComposing(bool* aResult)
    2072                 : {
    2073               0 :   NS_ENSURE_ARG_POINTER(aResult);
    2074               0 :   *aResult = IsIMEComposing();
    2075               0 :   return NS_OK;
    2076                 : }
    2077                 : 
    2078                 : 
    2079                 : /* Non-interface, public methods */
    2080                 : 
    2081                 : NS_IMETHODIMP
    2082               0 : nsEditor::GetRootElement(nsIDOMElement **aRootElement)
    2083                 : {
    2084               0 :   NS_ENSURE_ARG_POINTER(aRootElement);
    2085               0 :   NS_ENSURE_TRUE(mRootElement, NS_ERROR_NOT_AVAILABLE);
    2086               0 :   nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(mRootElement);
    2087               0 :   rootElement.forget(aRootElement);
    2088               0 :   return NS_OK;
    2089                 : }
    2090                 : 
    2091                 : 
    2092                 : /** All editor operations which alter the doc should be prefaced
    2093                 :  *  with a call to StartOperation, naming the action and direction */
    2094                 : NS_IMETHODIMP
    2095               0 : nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
    2096                 : {
    2097               0 :   mAction = opID;
    2098               0 :   mDirection = aDirection;
    2099               0 :   return NS_OK;
    2100                 : }
    2101                 : 
    2102                 : 
    2103                 : /** All editor operations which alter the doc should be followed
    2104                 :  *  with a call to EndOperation */
    2105                 : NS_IMETHODIMP
    2106               0 : nsEditor::EndOperation()
    2107                 : {
    2108               0 :   mAction = nsnull;
    2109               0 :   mDirection = eNone;
    2110               0 :   return NS_OK;
    2111                 : }
    2112                 : 
    2113                 : NS_IMETHODIMP
    2114               0 : nsEditor::CloneAttribute(const nsAString & aAttribute,
    2115                 :                          nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
    2116                 : {
    2117               0 :   NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
    2118                 : 
    2119               0 :   nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
    2120               0 :   nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
    2121               0 :   NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
    2122                 : 
    2123               0 :   nsAutoString attrValue;
    2124                 :   bool isAttrSet;
    2125                 :   nsresult rv = GetAttributeValue(sourceElement,
    2126                 :                                   aAttribute,
    2127                 :                                   attrValue,
    2128               0 :                                   &isAttrSet);
    2129               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2130               0 :   if (isAttrSet)
    2131               0 :     rv = SetAttribute(destElement, aAttribute, attrValue);
    2132                 :   else
    2133               0 :     rv = RemoveAttribute(destElement, aAttribute);
    2134                 : 
    2135               0 :   return rv;
    2136                 : }
    2137                 : 
    2138                 : // Objects must be DOM elements
    2139                 : NS_IMETHODIMP
    2140               0 : nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
    2141                 : {
    2142               0 :   NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
    2143                 : 
    2144               0 :   nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
    2145               0 :   nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
    2146               0 :   NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
    2147                 : 
    2148               0 :   nsCOMPtr<nsIDOMNamedNodeMap> sourceAttributes;
    2149               0 :   sourceElement->GetAttributes(getter_AddRefs(sourceAttributes));
    2150               0 :   nsCOMPtr<nsIDOMNamedNodeMap> destAttributes;
    2151               0 :   destElement->GetAttributes(getter_AddRefs(destAttributes));
    2152               0 :   NS_ENSURE_TRUE(sourceAttributes && destAttributes, NS_ERROR_FAILURE);
    2153                 : 
    2154               0 :   nsAutoEditBatch beginBatching(this);
    2155                 : 
    2156                 :   // Use transaction system for undo only if destination
    2157                 :   //   is already in the document
    2158               0 :   nsCOMPtr<nsIDOMNode> p = aDestNode;
    2159               0 :   nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
    2160               0 :   NS_ENSURE_TRUE(rootNode, NS_ERROR_NULL_POINTER);
    2161               0 :   bool destInBody = true;
    2162               0 :   while (p && p != rootNode)
    2163                 :   {
    2164               0 :     nsCOMPtr<nsIDOMNode> tmp;
    2165               0 :     if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp)
    2166                 :     {
    2167               0 :       destInBody = false;
    2168                 :       break;
    2169                 :     }
    2170               0 :     p = tmp;
    2171                 :   }
    2172                 : 
    2173                 :   PRUint32 sourceCount;
    2174               0 :   sourceAttributes->GetLength(&sourceCount);
    2175                 :   PRUint32 i, destCount;
    2176               0 :   destAttributes->GetLength(&destCount);
    2177               0 :   nsCOMPtr<nsIDOMNode> attrNode;
    2178                 : 
    2179                 :   // Clear existing attributes
    2180               0 :   for (i = 0; i < destCount; i++)
    2181                 :   {
    2182                 :     // always remove item number 0 (first item in list)
    2183               0 :     if( NS_SUCCEEDED(destAttributes->Item(0, getter_AddRefs(attrNode))) && attrNode)
    2184                 :     {
    2185               0 :       nsCOMPtr<nsIDOMAttr> destAttribute = do_QueryInterface(attrNode);
    2186               0 :       if (destAttribute)
    2187                 :       {
    2188               0 :         nsAutoString str;
    2189               0 :         if (NS_SUCCEEDED(destAttribute->GetName(str)))
    2190                 :         {
    2191               0 :           if (destInBody)
    2192               0 :             RemoveAttribute(destElement, str);
    2193                 :           else
    2194               0 :             destElement->RemoveAttribute(str);
    2195                 :         }
    2196                 :       }
    2197                 :     }
    2198                 :   }
    2199                 : 
    2200               0 :   nsresult result = NS_OK;
    2201                 : 
    2202                 :   // Set just the attributes that the source element has
    2203               0 :   for (i = 0; i < sourceCount; i++)
    2204                 :   {
    2205               0 :     if( NS_SUCCEEDED(sourceAttributes->Item(i, getter_AddRefs(attrNode))) && attrNode)
    2206                 :     {
    2207               0 :       nsCOMPtr<nsIDOMAttr> sourceAttribute = do_QueryInterface(attrNode);
    2208               0 :       if (sourceAttribute)
    2209                 :       {
    2210               0 :         nsAutoString sourceAttrName;
    2211               0 :         if (NS_SUCCEEDED(sourceAttribute->GetName(sourceAttrName)))
    2212                 :         {
    2213               0 :           nsAutoString sourceAttrValue;
    2214                 :           /*
    2215                 :           Presence of an attribute in the named node map indicates that it was set on the 
    2216                 :           element even if it has no value.
    2217                 :           */
    2218               0 :           if (NS_SUCCEEDED(sourceAttribute->GetValue(sourceAttrValue)))
    2219                 :           {
    2220               0 :             if (destInBody) {
    2221               0 :               result = SetAttributeOrEquivalent(destElement, sourceAttrName, sourceAttrValue, false);
    2222                 :             }
    2223                 :             else {
    2224                 :               // the element is not inserted in the document yet, we don't want to put a
    2225                 :               // transaction on the UndoStack
    2226               0 :               result = SetAttributeOrEquivalent(destElement, sourceAttrName, sourceAttrValue, true);
    2227                 :             }
    2228                 :           } else {
    2229                 :             // Do we ever get here?
    2230                 : #if DEBUG_cmanske
    2231                 :             printf("Attribute in sourceAttribute has empty value in nsEditor::CloneAttributes()\n");
    2232                 : #endif
    2233                 :           }
    2234                 :         }        
    2235                 :       }
    2236                 :     }
    2237                 :   }
    2238               0 :   return result;
    2239                 : }
    2240                 : 
    2241                 : 
    2242               0 : NS_IMETHODIMP nsEditor::ScrollSelectionIntoView(bool aScrollToAnchor)
    2243                 : {
    2244               0 :   nsCOMPtr<nsISelectionController> selCon;
    2245               0 :   if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
    2246                 :   {
    2247               0 :     PRInt16 region = nsISelectionController::SELECTION_FOCUS_REGION;
    2248                 : 
    2249               0 :     if (aScrollToAnchor)
    2250               0 :       region = nsISelectionController::SELECTION_ANCHOR_REGION;
    2251                 : 
    2252               0 :     selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    2253               0 :                                     region, 0);
    2254                 :   }
    2255                 : 
    2256               0 :   return NS_OK;
    2257                 : }
    2258                 : 
    2259               0 : NS_IMETHODIMP nsEditor::InsertTextImpl(const nsAString& aStringToInsert, 
    2260                 :                                           nsCOMPtr<nsIDOMNode> *aInOutNode, 
    2261                 :                                           PRInt32 *aInOutOffset,
    2262                 :                                           nsIDOMDocument *aDoc)
    2263                 : {
    2264                 :   // NOTE: caller *must* have already used nsAutoTxnsConserveSelection stack-based
    2265                 :   // class to turn off txn selection updating.  Caller also turned on rules sniffing
    2266                 :   // if desired.
    2267                 :   
    2268                 :   nsresult res;
    2269               0 :   NS_ENSURE_TRUE(aInOutNode && *aInOutNode && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER);
    2270               0 :   if (!mInIMEMode && aStringToInsert.IsEmpty()) return NS_OK;
    2271               0 :   nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
    2272               0 :   if (!nodeAsText && IsPlaintextEditor()) {
    2273               0 :     nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
    2274                 :     // In some cases, aInOutNode is the anonymous DIV, and aInOutOffset is 0.
    2275                 :     // To avoid injecting unneeded text nodes, we first look to see if we have
    2276                 :     // one available.  In that case, we'll just adjust aInOutNode and aInOutOffset
    2277                 :     // accordingly.
    2278               0 :     if (*aInOutNode == rootNode && *aInOutOffset == 0) {
    2279               0 :       nsCOMPtr<nsIDOMNode> possibleTextNode;
    2280               0 :       res = (*aInOutNode)->GetFirstChild(getter_AddRefs(possibleTextNode));
    2281               0 :       if (NS_SUCCEEDED(res)) {
    2282               0 :         nodeAsText = do_QueryInterface(possibleTextNode);
    2283               0 :         if (nodeAsText) {
    2284               0 :           *aInOutNode = possibleTextNode;
    2285                 :         }
    2286                 :       }
    2287                 :     }
    2288                 :     // In some other cases, aInOutNode is the anonymous DIV, and aInOutOffset points
    2289                 :     // to the terminating mozBR.  In that case, we'll adjust aInOutNode and aInOutOffset
    2290                 :     // to the preceding text node, if any.
    2291               0 :     if (!nodeAsText && *aInOutNode == rootNode && *aInOutOffset > 0) {
    2292               0 :       nsCOMPtr<nsIDOMNodeList> children;
    2293               0 :       res = (*aInOutNode)->GetChildNodes(getter_AddRefs(children));
    2294               0 :       if (NS_SUCCEEDED(res)) {
    2295               0 :         nsCOMPtr<nsIDOMNode> possibleMozBRNode;
    2296               0 :         children->Item(*aInOutOffset, getter_AddRefs(possibleMozBRNode));
    2297               0 :         if (possibleMozBRNode && nsTextEditUtils::IsMozBR(possibleMozBRNode)) {
    2298               0 :           nsCOMPtr<nsIDOMNode> possibleTextNode;
    2299               0 :           res = children->Item(*aInOutOffset - 1, getter_AddRefs(possibleTextNode));
    2300               0 :           if (NS_SUCCEEDED(res)) {
    2301               0 :             nodeAsText = do_QueryInterface(possibleTextNode);
    2302               0 :             if (nodeAsText) {
    2303                 :               PRUint32 length;
    2304               0 :               res = nodeAsText->GetLength(&length);
    2305               0 :               if (NS_SUCCEEDED(res)) {
    2306               0 :                 *aInOutOffset = PRInt32(length);
    2307               0 :                 *aInOutNode = possibleTextNode;
    2308                 :               }
    2309                 :             }
    2310                 :           }
    2311                 :         } else {
    2312                 :           // The selection might be at the end of the last textnode child,
    2313                 :           // in which case we can just append to the textnode in question.
    2314               0 :           nsCOMPtr<nsIDOMNode> possibleTextNode;
    2315               0 :           res = children->Item(*aInOutOffset - 1, getter_AddRefs(possibleTextNode));
    2316               0 :           nodeAsText = do_QueryInterface(possibleTextNode);
    2317               0 :           if (nodeAsText) {
    2318                 :             PRUint32 length;
    2319               0 :             res = nodeAsText->GetLength(&length);
    2320               0 :             if (NS_SUCCEEDED(res)) {
    2321               0 :               *aInOutOffset = PRInt32(length);
    2322               0 :               *aInOutNode = possibleTextNode;
    2323                 :             }
    2324                 :           }
    2325                 :         }
    2326                 :       }
    2327                 :     }
    2328                 :     // Sometimes, aInOutNode is the mozBR element itself.  In that case, we'll
    2329                 :     // adjust the insertion point to the previous text node, if one exists, or
    2330                 :     // to the parent anonymous DIV.
    2331               0 :     if (nsTextEditUtils::IsMozBR(*aInOutNode) && *aInOutOffset == 0) {
    2332               0 :       nsCOMPtr<nsIDOMNode> previous;
    2333               0 :       (*aInOutNode)->GetPreviousSibling(getter_AddRefs(previous));
    2334               0 :       nodeAsText = do_QueryInterface(previous);
    2335               0 :       if (nodeAsText) {
    2336                 :         PRUint32 length;
    2337               0 :         res = nodeAsText->GetLength(&length);
    2338               0 :         if (NS_SUCCEEDED(res)) {
    2339               0 :           *aInOutOffset = PRInt32(length);
    2340               0 :           *aInOutNode = previous;
    2341                 :         }
    2342                 :       } else {
    2343               0 :         nsCOMPtr<nsIDOMNode> parent;
    2344               0 :         (*aInOutNode)->GetParentNode(getter_AddRefs(parent));
    2345               0 :         if (parent == rootNode) {
    2346               0 :           *aInOutNode = parent;
    2347                 :         }
    2348                 :       }
    2349                 :     }
    2350                 :   }
    2351               0 :   PRInt32 offset = *aInOutOffset;
    2352               0 :   if (mInIMEMode)
    2353                 :   {
    2354               0 :     if (!nodeAsText)
    2355                 :     {
    2356                 :       // create a text node
    2357               0 :       res = aDoc->CreateTextNode(EmptyString(), getter_AddRefs(nodeAsText));
    2358               0 :       NS_ENSURE_SUCCESS(res, res);
    2359               0 :       NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER);
    2360               0 :       nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(nodeAsText);
    2361                 :       // then we insert it into the dom tree
    2362               0 :       res = InsertNode(newNode, *aInOutNode, offset);
    2363               0 :       NS_ENSURE_SUCCESS(res, res);
    2364               0 :       offset = 0;
    2365                 :     }
    2366               0 :     res = InsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
    2367               0 :     NS_ENSURE_SUCCESS(res, res);
    2368                 :   }
    2369                 :   else
    2370                 :   {
    2371               0 :     if (nodeAsText)
    2372                 :     {
    2373                 :       // we are inserting text into an existing text node.
    2374               0 :       res = InsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
    2375               0 :       NS_ENSURE_SUCCESS(res, res);
    2376               0 :       *aInOutOffset += aStringToInsert.Length();
    2377                 :     }
    2378                 :     else
    2379                 :     {
    2380                 :       // we are inserting text into a non-text node
    2381                 :       // first we have to create a textnode (this also populates it with the text)
    2382               0 :       res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
    2383               0 :       NS_ENSURE_SUCCESS(res, res);
    2384               0 :       NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER);
    2385               0 :       nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(nodeAsText);
    2386                 :       // then we insert it into the dom tree
    2387               0 :       res = InsertNode(newNode, *aInOutNode, offset);
    2388               0 :       NS_ENSURE_SUCCESS(res, res);
    2389               0 :       *aInOutNode = newNode;
    2390               0 :       *aInOutOffset = aStringToInsert.Length();
    2391                 :     }
    2392                 :   }
    2393               0 :   return res;
    2394                 : }
    2395                 : 
    2396                 : 
    2397               0 : nsresult nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, 
    2398                 :                                               nsIDOMCharacterData *aTextNode, 
    2399                 :                                               PRInt32 aOffset,
    2400                 :                                               bool aSuppressIME)
    2401                 : {
    2402               0 :   nsRefPtr<EditTxn> txn;
    2403               0 :   nsresult result = NS_OK;
    2404               0 :   bool isIMETransaction = false;
    2405                 :   // aSuppressIME is used when editor must insert text, yet this text is not
    2406                 :   // part of current ime operation.  example: adjusting whitespace around an ime insertion.
    2407               0 :   if (mIMETextRangeList && mInIMEMode && !aSuppressIME)
    2408                 :   {
    2409               0 :     if (!mIMETextNode)
    2410                 :     {
    2411               0 :       mIMETextNode = aTextNode;
    2412               0 :       mIMETextOffset = aOffset;
    2413                 :     }
    2414                 :     PRUint16 len ;
    2415               0 :     len = mIMETextRangeList->GetLength();
    2416               0 :     if (len > 0)
    2417                 :     {
    2418               0 :       nsCOMPtr<nsIPrivateTextRange> range;
    2419               0 :       for (PRUint16 i = 0; i < len; i++) 
    2420                 :       {
    2421               0 :         range = mIMETextRangeList->Item(i);
    2422               0 :         if (range)
    2423                 :         {
    2424                 :           PRUint16 type;
    2425               0 :           result = range->GetRangeType(&type);
    2426               0 :           if (NS_SUCCEEDED(result)) 
    2427                 :           {
    2428               0 :             if (type == nsIPrivateTextRange::TEXTRANGE_RAWINPUT) 
    2429                 :             {
    2430                 :               PRUint16 start, end;
    2431               0 :               result = range->GetRangeStart(&start);
    2432               0 :               if (NS_SUCCEEDED(result)) 
    2433                 :               {
    2434               0 :                 result = range->GetRangeEnd(&end);
    2435               0 :                 if (NS_SUCCEEDED(result)) 
    2436                 :                 {
    2437               0 :                   if (!mPhonetic)
    2438               0 :                     mPhonetic = new nsString();
    2439               0 :                   if (mPhonetic)
    2440                 :                   {
    2441               0 :                     nsAutoString tmp(aStringToInsert);                  
    2442               0 :                     tmp.Mid(*mPhonetic, start, end-start);
    2443                 :                   }
    2444                 :                 }
    2445                 :               }
    2446                 :             } // if
    2447                 :           }
    2448                 :         } // if
    2449                 :       } // for
    2450                 :     } // if
    2451                 : 
    2452               0 :     nsRefPtr<IMETextTxn> imeTxn;
    2453               0 :     result = CreateTxnForIMEText(aStringToInsert, getter_AddRefs(imeTxn));
    2454               0 :     txn = imeTxn;
    2455               0 :     isIMETransaction = true;
    2456                 :   }
    2457                 :   else
    2458                 :   {
    2459               0 :     nsRefPtr<InsertTextTxn> insertTxn;
    2460                 :     result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset,
    2461               0 :                                     getter_AddRefs(insertTxn));
    2462               0 :     txn = insertTxn;
    2463                 :   }
    2464               0 :   NS_ENSURE_SUCCESS(result, result);
    2465                 : 
    2466                 :   // let listeners know what's up
    2467                 :   PRInt32 i;
    2468               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    2469               0 :     mActionListeners[i]->WillInsertText(aTextNode, aOffset, aStringToInsert);
    2470                 :   
    2471                 :   // XXX we may not need these view batches anymore.  This is handled at a higher level now I believe
    2472               0 :   BeginUpdateViewBatch();
    2473               0 :   result = DoTransaction(txn);
    2474               0 :   EndUpdateViewBatch();
    2475                 : 
    2476               0 :   mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert);
    2477                 :   
    2478                 :   // let listeners know what happened
    2479               0 :   for (i = 0; i < mActionListeners.Count(); i++)
    2480               0 :     mActionListeners[i]->DidInsertText(aTextNode, aOffset, aStringToInsert, result);
    2481                 : 
    2482                 :   // Added some cruft here for bug 43366.  Layout was crashing because we left an 
    2483                 :   // empty text node lying around in the document.  So I delete empty text nodes
    2484                 :   // caused by IME.  I have to mark the IME transaction as "fixed", which means
    2485                 :   // that furure ime txns won't merge with it.  This is because we don't want
    2486                 :   // future ime txns trying to put their text into a node that is no longer in
    2487                 :   // the document.  This does not break undo/redo, because all these txns are 
    2488                 :   // wrapped in a parent PlaceHolder txn, and placeholder txns are already 
    2489                 :   // savvy to having multiple ime txns inside them.
    2490                 :   
    2491                 :   // delete empty ime text node if there is one
    2492               0 :   if (isIMETransaction && mIMETextNode)
    2493                 :   {
    2494                 :     PRUint32 len;
    2495               0 :     mIMETextNode->GetLength(&len);
    2496               0 :     if (!len)
    2497                 :     {
    2498               0 :       DeleteNode(mIMETextNode);
    2499               0 :       mIMETextNode = nsnull;
    2500               0 :       static_cast<IMETextTxn*>(txn.get())->MarkFixed();  // mark the ime txn "fixed"
    2501                 :     }
    2502                 :   }
    2503                 :   
    2504               0 :   return result;
    2505                 : }
    2506                 : 
    2507                 : 
    2508               0 : NS_IMETHODIMP nsEditor::SelectEntireDocument(nsISelection *aSelection)
    2509                 : {
    2510               0 :   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
    2511                 : 
    2512               0 :   nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
    2513               0 :   if (!rootElement) { return NS_ERROR_NOT_INITIALIZED; }
    2514                 : 
    2515               0 :   return aSelection->SelectAllChildren(rootElement);
    2516                 : }
    2517                 : 
    2518                 : 
    2519                 : nsINode*
    2520               0 : nsEditor::GetFirstEditableNode(nsINode* aRoot)
    2521                 : {
    2522               0 :   MOZ_ASSERT(aRoot);
    2523                 : 
    2524               0 :   nsIContent* node = GetLeftmostChild(aRoot);
    2525               0 :   if (node && !IsEditable(node)) {
    2526               0 :     node = GetNextNode(node, /* aEditableNode = */ true);
    2527                 :   }
    2528                 : 
    2529               0 :   return (node != aRoot) ? node : nsnull;
    2530                 : }
    2531                 : 
    2532                 : 
    2533                 : NS_IMETHODIMP
    2534               0 : nsEditor::NotifyDocumentListeners(TDocumentListenerNotification aNotificationType)
    2535                 : {
    2536               0 :   PRInt32 numListeners = mDocStateListeners.Count();
    2537               0 :   if (!numListeners)    // maybe there just aren't any.
    2538               0 :     return NS_OK;
    2539                 :  
    2540               0 :   nsCOMArray<nsIDocumentStateListener> listeners(mDocStateListeners);
    2541               0 :   nsresult rv = NS_OK;
    2542                 :   PRInt32 i;
    2543                 : 
    2544               0 :   switch (aNotificationType)
    2545                 :   {
    2546                 :     case eDocumentCreated:
    2547               0 :       for (i = 0; i < numListeners;i++)
    2548                 :       {
    2549               0 :         rv = listeners[i]->NotifyDocumentCreated();
    2550               0 :         if (NS_FAILED(rv))
    2551               0 :           break;
    2552                 :       }
    2553               0 :       break;
    2554                 :       
    2555                 :     case eDocumentToBeDestroyed:
    2556               0 :       for (i = 0; i < numListeners;i++)
    2557                 :       {
    2558               0 :         rv = listeners[i]->NotifyDocumentWillBeDestroyed();
    2559               0 :         if (NS_FAILED(rv))
    2560               0 :           break;
    2561                 :       }
    2562               0 :       break;
    2563                 :   
    2564                 :     case eDocumentStateChanged:
    2565                 :       {
    2566                 :         bool docIsDirty;
    2567               0 :         rv = GetDocumentModified(&docIsDirty);
    2568               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2569                 :         
    2570               0 :         if (docIsDirty == mDocDirtyState)
    2571               0 :           return NS_OK;
    2572                 :         
    2573               0 :         mDocDirtyState = (PRInt8)docIsDirty;
    2574                 :         
    2575               0 :         for (i = 0; i < numListeners;i++)
    2576                 :         {
    2577               0 :           rv = listeners[i]->NotifyDocumentStateChanged(mDocDirtyState);
    2578               0 :           if (NS_FAILED(rv))
    2579               0 :             break;
    2580                 :         }
    2581                 :       }
    2582               0 :       break;
    2583                 :     
    2584                 :     default:
    2585               0 :       NS_NOTREACHED("Unknown notification");
    2586                 :   }
    2587                 : 
    2588               0 :   return rv;
    2589                 : }
    2590                 : 
    2591                 : 
    2592               0 : NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsAString & aStringToInsert,
    2593                 :                                                nsIDOMCharacterData *aTextNode,
    2594                 :                                                PRInt32 aOffset,
    2595                 :                                                InsertTextTxn ** aTxn)
    2596                 : {
    2597               0 :   NS_ENSURE_TRUE(aTextNode && aTxn, NS_ERROR_NULL_POINTER);
    2598                 :   nsresult rv;
    2599                 : 
    2600               0 :   nsRefPtr<InsertTextTxn> txn = new InsertTextTxn();
    2601               0 :   rv = txn->Init(aTextNode, aOffset, aStringToInsert, this);
    2602               0 :   if (NS_SUCCEEDED(rv))
    2603                 :   {
    2604               0 :     txn.forget(aTxn);
    2605                 :   }
    2606                 : 
    2607               0 :   return rv;
    2608                 : }
    2609                 : 
    2610                 : 
    2611               0 : NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
    2612                 :                               PRUint32             aOffset,
    2613                 :                               PRUint32             aLength)
    2614                 : {
    2615               0 :   nsRefPtr<DeleteTextTxn> txn;
    2616                 :   nsresult result = CreateTxnForDeleteText(aElement, aOffset, aLength,
    2617               0 :                                            getter_AddRefs(txn));
    2618               0 :   nsAutoRules beginRulesSniffing(this, kOpDeleteText, nsIEditor::ePrevious);
    2619               0 :   if (NS_SUCCEEDED(result))  
    2620                 :   {
    2621                 :     // let listeners know what's up
    2622                 :     PRInt32 i;
    2623               0 :     for (i = 0; i < mActionListeners.Count(); i++)
    2624               0 :       mActionListeners[i]->WillDeleteText(aElement, aOffset, aLength);
    2625                 :     
    2626               0 :     result = DoTransaction(txn); 
    2627                 :     
    2628                 :     // let listeners know what happened
    2629               0 :     for (i = 0; i < mActionListeners.Count(); i++)
    2630               0 :       mActionListeners[i]->DidDeleteText(aElement, aOffset, aLength, result);
    2631                 :   }
    2632               0 :   return result;
    2633                 : }
    2634                 : 
    2635                 : 
    2636               0 : NS_IMETHODIMP nsEditor::CreateTxnForDeleteText(nsIDOMCharacterData *aElement,
    2637                 :                                                PRUint32             aOffset,
    2638                 :                                                PRUint32             aLength,
    2639                 :                                                DeleteTextTxn      **aTxn)
    2640                 : {
    2641               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    2642                 : 
    2643               0 :   nsRefPtr<DeleteTextTxn> txn = new DeleteTextTxn();
    2644                 : 
    2645               0 :   nsresult rv = txn->Init(this, aElement, aOffset, aLength, &mRangeUpdater);
    2646               0 :   if (NS_SUCCEEDED(rv))
    2647                 :   {
    2648               0 :     txn.forget(aTxn);
    2649                 :   }
    2650                 : 
    2651               0 :   return rv;
    2652                 : }
    2653                 : 
    2654                 : 
    2655                 : 
    2656                 : 
    2657               0 : NS_IMETHODIMP nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode,
    2658                 :                                          PRUint32    aOffset,
    2659                 :                                          SplitElementTxn **aTxn)
    2660                 : {
    2661               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    2662                 : 
    2663               0 :   nsRefPtr<SplitElementTxn> txn = new SplitElementTxn();
    2664                 : 
    2665               0 :   nsresult rv = txn->Init(this, aNode, aOffset);
    2666               0 :   if (NS_SUCCEEDED(rv))
    2667                 :   {
    2668               0 :     txn.forget(aTxn);
    2669                 :   }
    2670                 : 
    2671               0 :   return rv;
    2672                 : }
    2673                 : 
    2674               0 : NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode  *aLeftNode,
    2675                 :                                              nsIDOMNode  *aRightNode,
    2676                 :                                              JoinElementTxn **aTxn)
    2677                 : {
    2678               0 :   NS_ENSURE_TRUE(aLeftNode && aRightNode, NS_ERROR_NULL_POINTER);
    2679                 : 
    2680               0 :   nsRefPtr<JoinElementTxn> txn = new JoinElementTxn();
    2681                 : 
    2682               0 :   nsresult rv = txn->Init(this, aLeftNode, aRightNode);
    2683               0 :   if (NS_SUCCEEDED(rv))
    2684                 :   {
    2685               0 :     txn.forget(aTxn);
    2686                 :   }
    2687                 : 
    2688               0 :   return rv;
    2689                 : }
    2690                 : 
    2691                 : 
    2692                 : // END nsEditor core implementation
    2693                 : 
    2694                 : 
    2695                 : // BEGIN nsEditor public helper methods
    2696                 : 
    2697                 : nsresult
    2698               0 : nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
    2699                 :                         PRInt32      aOffset,
    2700                 :                         nsIDOMNode*  aNewLeftNode,
    2701                 :                         nsIDOMNode*  aParent)
    2702                 : {
    2703                 : #ifdef NS_DEBUG_EDITOR
    2704                 :   if (gNoisy) { printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", (void*)aNewLeftNode, (void*)aExistingRightNode, aOffset); }
    2705                 : #endif
    2706                 : 
    2707               0 :   NS_ASSERTION(((nsnull!=aExistingRightNode) &&
    2708                 :                 (nsnull!=aNewLeftNode) &&
    2709                 :                 (nsnull!=aParent)),
    2710                 :                 "null arg");
    2711                 :   nsresult result;
    2712               0 :   if ((nsnull!=aExistingRightNode) &&
    2713                 :       (nsnull!=aNewLeftNode) &&
    2714                 :       (nsnull!=aParent))
    2715                 :   {
    2716                 :     // get selection
    2717               0 :     nsCOMPtr<nsISelection> selection;
    2718               0 :     result = GetSelection(getter_AddRefs(selection));
    2719               0 :     NS_ENSURE_SUCCESS(result, result);
    2720               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2721                 : 
    2722                 :     // remember some selection points
    2723               0 :     nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
    2724                 :     PRInt32 selStartOffset, selEndOffset;
    2725               0 :     result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
    2726               0 :     if (NS_FAILED(result)) selStartNode = nsnull;  // if selection is cleared, remember that
    2727               0 :     result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
    2728               0 :     if (NS_FAILED(result)) selStartNode = nsnull;  // if selection is cleared, remember that
    2729                 : 
    2730               0 :     nsCOMPtr<nsIDOMNode> resultNode;
    2731               0 :     result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode));
    2732                 :     //printf("  after insert\n"); content->List();  // DEBUG
    2733               0 :     if (NS_SUCCEEDED(result))
    2734                 :     {
    2735                 :       // split the children between the 2 nodes
    2736                 :       // at this point, aExistingRightNode has all the children
    2737                 :       // move all the children whose index is < aOffset to aNewLeftNode
    2738               0 :       if (0<=aOffset) // don't bother unless we're going to move at least one child
    2739                 :       {
    2740                 :         // if it's a text node, just shuffle around some text
    2741               0 :         nsCOMPtr<nsIDOMCharacterData> rightNodeAsText( do_QueryInterface(aExistingRightNode) );
    2742               0 :         nsCOMPtr<nsIDOMCharacterData> leftNodeAsText( do_QueryInterface(aNewLeftNode) );
    2743               0 :         if (leftNodeAsText && rightNodeAsText)
    2744                 :         {
    2745                 :           // fix right node
    2746               0 :           nsAutoString leftText;
    2747               0 :           rightNodeAsText->SubstringData(0, aOffset, leftText);
    2748               0 :           rightNodeAsText->DeleteData(0, aOffset);
    2749                 :           // fix left node
    2750               0 :           leftNodeAsText->SetData(leftText);
    2751                 :           // moose          
    2752                 :         }
    2753                 :         else
    2754                 :         {  // otherwise it's an interior node, so shuffle around the children
    2755                 :            // go through list backwards so deletes don't interfere with the iteration
    2756               0 :           nsCOMPtr<nsIDOMNodeList> childNodes;
    2757               0 :           result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes));
    2758               0 :           if ((NS_SUCCEEDED(result)) && (childNodes))
    2759                 :           {
    2760               0 :             PRInt32 i=aOffset-1;
    2761               0 :             for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
    2762                 :             {
    2763               0 :               nsCOMPtr<nsIDOMNode> childNode;
    2764               0 :               result = childNodes->Item(i, getter_AddRefs(childNode));
    2765               0 :               if ((NS_SUCCEEDED(result)) && (childNode))
    2766                 :               {
    2767               0 :                 result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode));
    2768                 :                 //printf("  after remove\n"); content->List();  // DEBUG
    2769               0 :                 if (NS_SUCCEEDED(result))
    2770                 :                 {
    2771               0 :                   nsCOMPtr<nsIDOMNode> firstChild;
    2772               0 :                   aNewLeftNode->GetFirstChild(getter_AddRefs(firstChild));
    2773               0 :                   result = aNewLeftNode->InsertBefore(childNode, firstChild, getter_AddRefs(resultNode));
    2774                 :                   //printf("  after append\n"); content->List();  // DEBUG
    2775                 :                 }
    2776                 :               }
    2777                 :             }
    2778                 :           }        
    2779                 :         }
    2780                 :         // handle selection
    2781               0 :         nsCOMPtr<nsIPresShell> ps = GetPresShell();
    2782               0 :         if (ps)
    2783               0 :           ps->FlushPendingNotifications(Flush_Frames);
    2784                 : 
    2785               0 :         if (GetShouldTxnSetSelection())
    2786                 :         {
    2787                 :           // editor wants us to set selection at split point
    2788               0 :           selection->Collapse(aNewLeftNode, aOffset);
    2789                 :         }
    2790               0 :         else if (selStartNode)   
    2791                 :         {
    2792                 :           // else adjust the selection if needed.  if selStartNode is null, then there was no selection.
    2793                 :           // HACK: this is overly simplified - multi-range selections need more work than this
    2794               0 :           if (selStartNode.get() == aExistingRightNode)
    2795                 :           {
    2796               0 :             if (selStartOffset < aOffset)
    2797                 :             {
    2798               0 :               selStartNode = aNewLeftNode;
    2799                 :             }
    2800                 :             else
    2801                 :             {
    2802               0 :               selStartOffset -= aOffset;
    2803                 :             }
    2804                 :           }
    2805               0 :           if (selEndNode.get() == aExistingRightNode)
    2806                 :           {
    2807               0 :             if (selEndOffset < aOffset)
    2808                 :             {
    2809               0 :               selEndNode = aNewLeftNode;
    2810                 :             }
    2811                 :             else
    2812                 :             {
    2813               0 :               selEndOffset -= aOffset;
    2814                 :             }
    2815                 :           }
    2816               0 :           selection->Collapse(selStartNode,selStartOffset);
    2817               0 :           selection->Extend(selEndNode,selEndOffset);
    2818                 :         }
    2819                 :       }
    2820               0 :     }
    2821                 :   }
    2822                 :   else
    2823               0 :     result = NS_ERROR_INVALID_ARG;
    2824                 : 
    2825               0 :   return result;
    2826                 : }
    2827                 : 
    2828                 : nsresult
    2829               0 : nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
    2830                 :                         nsIDOMNode * aNodeToJoin,
    2831                 :                         nsIDOMNode * aParent,
    2832                 :                         bool         aNodeToKeepIsFirst)
    2833                 : {
    2834               0 :   NS_ASSERTION(aNodeToKeep && aNodeToJoin && aParent, "null arg");
    2835               0 :   nsresult result = NS_OK;
    2836               0 :   if (aNodeToKeep && aNodeToJoin && aParent)
    2837                 :   {
    2838                 :     // get selection
    2839               0 :     nsCOMPtr<nsISelection> selection;
    2840               0 :     GetSelection(getter_AddRefs(selection));
    2841               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2842                 : 
    2843                 :     // remember some selection points
    2844               0 :     nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
    2845                 :     PRInt32 selStartOffset, selEndOffset, joinOffset, keepOffset;
    2846               0 :     result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
    2847               0 :     if (NS_FAILED(result)) selStartNode = nsnull;
    2848               0 :     result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
    2849                 :     // Joe or Kin should comment here on why the following line is not a copy/paste error
    2850               0 :     if (NS_FAILED(result)) selStartNode = nsnull;
    2851                 : 
    2852               0 :     nsCOMPtr<nsIDOMNode> leftNode;
    2853               0 :     if (aNodeToKeepIsFirst)
    2854               0 :       leftNode = aNodeToKeep;
    2855                 :     else
    2856               0 :       leftNode = aNodeToJoin;
    2857                 : 
    2858                 :     PRUint32 firstNodeLength;
    2859               0 :     result = GetLengthOfDOMNode(leftNode, firstNodeLength);
    2860               0 :     NS_ENSURE_SUCCESS(result, result);
    2861               0 :     nsCOMPtr<nsIDOMNode> parent;
    2862               0 :     result = GetNodeLocation(aNodeToJoin, address_of(parent), &joinOffset);
    2863               0 :     NS_ENSURE_SUCCESS(result, result);
    2864               0 :     result = GetNodeLocation(aNodeToKeep, address_of(parent), &keepOffset);
    2865               0 :     NS_ENSURE_SUCCESS(result, result);
    2866                 :     
    2867                 :     // if selection endpoint is between the nodes, remember it as being
    2868                 :     // in the one that is going away instead.  This simplifies later selection
    2869                 :     // adjustment logic at end of this method.
    2870               0 :     if (selStartNode)
    2871                 :     {
    2872               0 :       if (selStartNode == parent)
    2873                 :       {
    2874               0 :         if (aNodeToKeepIsFirst)
    2875                 :         {
    2876               0 :           if ((selStartOffset > keepOffset) && (selStartOffset <= joinOffset))
    2877                 :           {
    2878               0 :             selStartNode = aNodeToJoin; 
    2879               0 :             selStartOffset = 0;
    2880                 :           }
    2881                 :         }
    2882                 :         else
    2883                 :         {
    2884               0 :           if ((selStartOffset > joinOffset) && (selStartOffset <= keepOffset))
    2885                 :           {
    2886               0 :             selStartNode = aNodeToJoin; 
    2887               0 :             selStartOffset = firstNodeLength;
    2888                 :           }
    2889                 :         }
    2890                 :       }
    2891               0 :       if (selEndNode == parent)
    2892                 :       {
    2893               0 :         if (aNodeToKeepIsFirst)
    2894                 :         {
    2895               0 :           if ((selEndOffset > keepOffset) && (selEndOffset <= joinOffset))
    2896                 :           {
    2897               0 :             selEndNode = aNodeToJoin; 
    2898               0 :             selEndOffset = 0;
    2899                 :           }
    2900                 :         }
    2901                 :         else
    2902                 :         {
    2903               0 :           if ((selEndOffset > joinOffset) && (selEndOffset <= keepOffset))
    2904                 :           {
    2905               0 :             selEndNode = aNodeToJoin; 
    2906               0 :             selEndOffset = firstNodeLength;
    2907                 :           }
    2908                 :         }
    2909                 :       }
    2910                 :     }
    2911                 :     // ok, ready to do join now.
    2912                 :     // if it's a text node, just shuffle around some text
    2913               0 :     nsCOMPtr<nsIDOMCharacterData> keepNodeAsText( do_QueryInterface(aNodeToKeep) );
    2914               0 :     nsCOMPtr<nsIDOMCharacterData> joinNodeAsText( do_QueryInterface(aNodeToJoin) );
    2915               0 :     if (keepNodeAsText && joinNodeAsText)
    2916                 :     {
    2917               0 :       nsAutoString rightText;
    2918               0 :       nsAutoString leftText;
    2919               0 :       if (aNodeToKeepIsFirst)
    2920                 :       {
    2921               0 :         keepNodeAsText->GetData(leftText);
    2922               0 :         joinNodeAsText->GetData(rightText);
    2923                 :       }
    2924                 :       else
    2925                 :       {
    2926               0 :         keepNodeAsText->GetData(rightText);
    2927               0 :         joinNodeAsText->GetData(leftText);
    2928                 :       }
    2929               0 :       leftText += rightText;
    2930               0 :       keepNodeAsText->SetData(leftText);          
    2931                 :     }
    2932                 :     else
    2933                 :     {  // otherwise it's an interior node, so shuffle around the children
    2934               0 :       nsCOMPtr<nsIDOMNodeList> childNodes;
    2935               0 :       result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes));
    2936               0 :       if ((NS_SUCCEEDED(result)) && (childNodes))
    2937                 :       {
    2938                 :         PRInt32 i;  // must be signed int!
    2939               0 :         PRUint32 childCount=0;
    2940               0 :         nsCOMPtr<nsIDOMNode> firstNode; //only used if aNodeToKeepIsFirst is false
    2941               0 :         childNodes->GetLength(&childCount);
    2942               0 :         if (!aNodeToKeepIsFirst)
    2943                 :         { // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
    2944               0 :           result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode));  
    2945                 :           // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok.
    2946                 :         }
    2947               0 :         nsCOMPtr<nsIDOMNode> resultNode;
    2948                 :         // have to go through the list backwards to keep deletes from interfering with iteration
    2949               0 :         nsCOMPtr<nsIDOMNode> previousChild;
    2950               0 :         for (i=childCount-1; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
    2951                 :         {
    2952               0 :           nsCOMPtr<nsIDOMNode> childNode;
    2953               0 :           result = childNodes->Item(i, getter_AddRefs(childNode));
    2954               0 :           if ((NS_SUCCEEDED(result)) && (childNode))
    2955                 :           {
    2956               0 :             if (aNodeToKeepIsFirst)
    2957                 :             { // append children of aNodeToJoin
    2958                 :               //was result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode));
    2959               0 :               result = aNodeToKeep->InsertBefore(childNode, previousChild, getter_AddRefs(resultNode));
    2960               0 :               previousChild = do_QueryInterface(childNode);
    2961                 :             }
    2962                 :             else
    2963                 :             { // prepend children of aNodeToJoin
    2964               0 :               result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode));
    2965               0 :               firstNode = do_QueryInterface(childNode);
    2966                 :             }
    2967                 :           }
    2968                 :         }
    2969                 :       }
    2970               0 :       else if (!childNodes) {
    2971               0 :         result = NS_ERROR_NULL_POINTER;
    2972                 :       }
    2973                 :     }
    2974               0 :     if (NS_SUCCEEDED(result))
    2975                 :     { // delete the extra node
    2976               0 :       nsCOMPtr<nsIDOMNode> resultNode;
    2977               0 :       result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode));
    2978                 :       
    2979               0 :       if (GetShouldTxnSetSelection())
    2980                 :       {
    2981                 :         // editor wants us to set selection at join point
    2982               0 :         selection->Collapse(aNodeToKeep, firstNodeLength);
    2983                 :       }
    2984               0 :       else if (selStartNode)
    2985                 :       {
    2986                 :         // and adjust the selection if needed
    2987                 :         // HACK: this is overly simplified - multi-range selections need more work than this
    2988               0 :         bool bNeedToAdjust = false;
    2989                 :         
    2990                 :         // check to see if we joined nodes where selection starts
    2991               0 :         if (selStartNode.get() == aNodeToJoin)
    2992                 :         {
    2993               0 :           bNeedToAdjust = true;
    2994               0 :           selStartNode = aNodeToKeep;
    2995               0 :           if (aNodeToKeepIsFirst)
    2996                 :           {
    2997               0 :             selStartOffset += firstNodeLength;
    2998                 :           }
    2999                 :         }
    3000               0 :         else if ((selStartNode.get() == aNodeToKeep) && !aNodeToKeepIsFirst)
    3001                 :         {
    3002               0 :           bNeedToAdjust = true;
    3003               0 :           selStartOffset += firstNodeLength;
    3004                 :         }
    3005                 :                 
    3006                 :         // check to see if we joined nodes where selection ends
    3007               0 :         if (selEndNode.get() == aNodeToJoin)
    3008                 :         {
    3009               0 :           bNeedToAdjust = true;
    3010               0 :           selEndNode = aNodeToKeep;
    3011               0 :           if (aNodeToKeepIsFirst)
    3012                 :           {
    3013               0 :             selEndOffset += firstNodeLength;
    3014                 :           }
    3015                 :         }
    3016               0 :         else if ((selEndNode.get() == aNodeToKeep) && !aNodeToKeepIsFirst)
    3017                 :         {
    3018               0 :           bNeedToAdjust = true;
    3019               0 :           selEndOffset += firstNodeLength;
    3020                 :         }
    3021                 :         
    3022                 :         // adjust selection if needed
    3023               0 :         if (bNeedToAdjust)
    3024                 :         {
    3025               0 :           selection->Collapse(selStartNode,selStartOffset);
    3026               0 :           selection->Extend(selEndNode,selEndOffset);          
    3027                 :         }
    3028                 :       }
    3029               0 :     }
    3030                 :   }
    3031                 :   else
    3032               0 :     result = NS_ERROR_INVALID_ARG;
    3033                 : 
    3034               0 :   return result;
    3035                 : }
    3036                 : 
    3037                 : 
    3038                 : nsresult 
    3039               0 : nsEditor::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset)
    3040                 : {
    3041               0 :   NS_ASSERTION((aChild && aParent), "bad args");
    3042                 : 
    3043               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
    3044               0 :   nsCOMPtr<nsIContent> cChild = do_QueryInterface(aChild);
    3045               0 :   NS_ENSURE_TRUE(cChild && content, NS_ERROR_NULL_POINTER);
    3046                 : 
    3047               0 :   aOffset = content->IndexOf(cChild);
    3048                 : 
    3049               0 :   return NS_OK;
    3050                 : }
    3051                 : 
    3052                 : nsresult 
    3053               0 : nsEditor::GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset)
    3054                 : {
    3055               0 :   NS_ASSERTION((inChild && outParent && outOffset), "bad args");
    3056               0 :   nsresult result = NS_ERROR_NULL_POINTER;
    3057               0 :   if (inChild && outParent && outOffset)
    3058                 :   {
    3059               0 :     result = inChild->GetParentNode(getter_AddRefs(*outParent));
    3060               0 :     if ((NS_SUCCEEDED(result)) && (*outParent))
    3061                 :     {
    3062               0 :       result = GetChildOffset(inChild, *outParent, *outOffset);
    3063                 :     }
    3064                 :   }
    3065               0 :   return result;
    3066                 : }
    3067                 : 
    3068                 : // returns the number of things inside aNode.  
    3069                 : // If aNode is text, returns number of characters. If not, returns number of children nodes.
    3070                 : nsresult
    3071               0 : nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) 
    3072                 : {
    3073               0 :   aCount = 0;
    3074               0 :   if (!aNode) { return NS_ERROR_NULL_POINTER; }
    3075               0 :   nsresult result=NS_OK;
    3076               0 :   nsCOMPtr<nsIDOMCharacterData>nodeAsChar = do_QueryInterface(aNode);
    3077               0 :   if (nodeAsChar) {
    3078               0 :     nodeAsChar->GetLength(&aCount);
    3079                 :   }
    3080                 :   else
    3081                 :   {
    3082                 :     bool hasChildNodes;
    3083               0 :     aNode->HasChildNodes(&hasChildNodes);
    3084               0 :     if (hasChildNodes)
    3085                 :     {
    3086               0 :       nsCOMPtr<nsIDOMNodeList>nodeList;
    3087               0 :       result = aNode->GetChildNodes(getter_AddRefs(nodeList));
    3088               0 :       if (NS_SUCCEEDED(result) && nodeList) {
    3089               0 :         nodeList->GetLength(&aCount);
    3090                 :       }
    3091                 :     }
    3092                 :   }
    3093               0 :   return result;
    3094                 : }
    3095                 : 
    3096                 : 
    3097                 : nsresult 
    3098               0 : nsEditor::GetPriorNode(nsIDOMNode  *aParentNode, 
    3099                 :                        PRInt32      aOffset, 
    3100                 :                        bool         aEditableNode, 
    3101                 :                        nsCOMPtr<nsIDOMNode> *aResultNode,
    3102                 :                        bool         bNoBlockCrossing,
    3103                 :                        nsIContent  *aActiveEditorRoot)
    3104                 : {
    3105                 :   // just another version of GetPriorNode that takes a {parent, offset}
    3106                 :   // instead of a node
    3107               0 :   if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
    3108               0 :   *aResultNode = nsnull;
    3109                 :   
    3110                 :   // if we are at beginning of node, or it is a textnode, then just look before it
    3111               0 :   if (!aOffset || IsTextNode(aParentNode))
    3112                 :   {
    3113               0 :     if (bNoBlockCrossing && IsBlockNode(aParentNode))
    3114                 :     {
    3115                 :       // if we aren't allowed to cross blocks, don't look before this block
    3116               0 :       return NS_OK;
    3117                 :     }
    3118                 :     return GetPriorNode(aParentNode, aEditableNode, aResultNode,
    3119               0 :                         bNoBlockCrossing, aActiveEditorRoot);
    3120                 :   }
    3121                 : 
    3122                 :   // else look before the child at 'aOffset'
    3123               0 :   nsCOMPtr<nsIDOMNode> child = GetChildAt(aParentNode, aOffset);
    3124               0 :   if (child)
    3125                 :     return GetPriorNode(child, aEditableNode, aResultNode, bNoBlockCrossing,
    3126               0 :                         aActiveEditorRoot);
    3127                 : 
    3128                 :   // unless there isn't one, in which case we are at the end of the node
    3129                 :   // and want the deep-right child.
    3130               0 :   *aResultNode = GetRightmostChild(aParentNode, bNoBlockCrossing);
    3131               0 :   if (!*aResultNode || !aEditableNode || IsEditable(*aResultNode))
    3132               0 :     return NS_OK;
    3133                 : 
    3134                 :   // restart the search from the non-editable node we just found
    3135               0 :   nsCOMPtr<nsIDOMNode> notEditableNode = *aResultNode;
    3136                 :   return GetPriorNode(notEditableNode, aEditableNode, aResultNode,
    3137               0 :                       bNoBlockCrossing, aActiveEditorRoot);
    3138                 : }
    3139                 : 
    3140                 : 
    3141                 : nsresult 
    3142               0 : nsEditor::GetNextNode(nsIDOMNode   *aParentNode, 
    3143                 :                       PRInt32      aOffset, 
    3144                 :                       bool         aEditableNode, 
    3145                 :                       nsCOMPtr<nsIDOMNode> *aResultNode,
    3146                 :                       bool         bNoBlockCrossing,
    3147                 :                       nsIContent  *aActiveEditorRoot)
    3148                 : {
    3149                 :   // just another version of GetNextNode that takes a {parent, offset}
    3150                 :   // instead of a node
    3151               0 :   if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
    3152                 :   
    3153               0 :   *aResultNode = nsnull;
    3154                 : 
    3155                 :   // if aParentNode is a text node, use its location instead
    3156               0 :   if (IsTextNode(aParentNode))
    3157                 :   {
    3158               0 :     nsCOMPtr<nsIDOMNode> parent;
    3159               0 :     nsEditor::GetNodeLocation(aParentNode, address_of(parent), &aOffset);
    3160               0 :     aParentNode = parent;
    3161               0 :     aOffset++;  // _after_ the text node
    3162                 :   }
    3163                 :   // look at the child at 'aOffset'
    3164               0 :   nsCOMPtr<nsIDOMNode> child = GetChildAt(aParentNode, aOffset);
    3165               0 :   if (child)
    3166                 :   {
    3167               0 :     if (bNoBlockCrossing && IsBlockNode(child))
    3168                 :     {
    3169               0 :       *aResultNode = child;  // return this block
    3170               0 :       return NS_OK;
    3171                 :     }
    3172               0 :     *aResultNode = GetLeftmostChild(child, bNoBlockCrossing);
    3173               0 :     if (!*aResultNode) 
    3174                 :     {
    3175               0 :       *aResultNode = child;
    3176               0 :       return NS_OK;
    3177                 :     }
    3178               0 :     if (!IsDescendantOfBody(*aResultNode))
    3179                 :     {
    3180               0 :       *aResultNode = nsnull;
    3181               0 :       return NS_OK;
    3182                 :     }
    3183                 : 
    3184               0 :     if (!aEditableNode || IsEditable(*aResultNode))
    3185               0 :       return NS_OK;
    3186                 : 
    3187                 :     // restart the search from the non-editable node we just found
    3188               0 :     nsCOMPtr<nsIDOMNode> notEditableNode = do_QueryInterface(*aResultNode);
    3189                 :     return GetNextNode(notEditableNode, aEditableNode, aResultNode,
    3190               0 :                        bNoBlockCrossing, aActiveEditorRoot);
    3191                 :   }
    3192                 :     
    3193                 :   // unless there isn't one, in which case we are at the end of the node
    3194                 :   // and want the next one.
    3195               0 :   if (bNoBlockCrossing && IsBlockNode(aParentNode))
    3196                 :   {
    3197                 :     // don't cross out of parent block
    3198               0 :     return NS_OK;
    3199                 :   }
    3200                 :   return GetNextNode(aParentNode, aEditableNode, aResultNode, bNoBlockCrossing,
    3201               0 :                      aActiveEditorRoot);
    3202                 : }
    3203                 : 
    3204                 : 
    3205                 : nsresult 
    3206               0 : nsEditor::GetPriorNode(nsIDOMNode  *aCurrentNode, 
    3207                 :                        bool         aEditableNode, 
    3208                 :                        nsCOMPtr<nsIDOMNode> *aResultNode,
    3209                 :                        bool         bNoBlockCrossing,
    3210                 :                        nsIContent  *aActiveEditorRoot)
    3211                 : {
    3212               0 :   if (!aCurrentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
    3213                 : 
    3214               0 :   nsCOMPtr<nsINode> currentNode = do_QueryInterface(aCurrentNode);
    3215                 : 
    3216               0 :   if (!IsDescendantOfBody(currentNode) ||
    3217                 :       (aActiveEditorRoot &&
    3218                 :        !nsContentUtils::ContentIsDescendantOf(currentNode,
    3219               0 :                                               aActiveEditorRoot))) {
    3220               0 :     *aResultNode = nsnull;
    3221               0 :     return NS_OK;
    3222                 :   }
    3223                 : 
    3224                 :   *aResultNode =
    3225                 :     do_QueryInterface(FindNode(currentNode, false, aEditableNode,
    3226               0 :                                bNoBlockCrossing, aActiveEditorRoot));
    3227               0 :   return NS_OK;
    3228                 : }
    3229                 : 
    3230                 : nsIContent*
    3231               0 : nsEditor::FindNextLeafNode(nsINode  *aCurrentNode, 
    3232                 :                            bool      aGoForward,
    3233                 :                            bool      bNoBlockCrossing,
    3234                 :                            nsIContent *aActiveEditorRoot)
    3235                 : {
    3236                 :   // called only by GetPriorNode so we don't need to check params.
    3237               0 :   NS_PRECONDITION(IsDescendantOfBody(aCurrentNode) && !IsRootNode(aCurrentNode) &&
    3238                 :                   (!aActiveEditorRoot ||
    3239                 :                    nsContentUtils::ContentIsDescendantOf(aCurrentNode,
    3240                 :                                                          aActiveEditorRoot)),
    3241                 :                   "Bogus arguments");
    3242                 : 
    3243               0 :   nsINode* cur = aCurrentNode;
    3244               0 :   for (;;) {
    3245                 :     // if aCurrentNode has a sibling in the right direction, return
    3246                 :     // that sibling's closest child (or itself if it has no children)
    3247                 :     nsIContent* sibling =
    3248               0 :       aGoForward ? cur->GetNextSibling() : cur->GetPreviousSibling();
    3249               0 :     if (sibling) {
    3250               0 :       if (bNoBlockCrossing && IsBlockNode(sibling)) {
    3251                 :         // don't look inside prevsib, since it is a block
    3252               0 :         return sibling;
    3253                 :       }
    3254                 :       nsIContent *leaf =
    3255               0 :         aGoForward ? GetLeftmostChild(sibling, bNoBlockCrossing) :
    3256               0 :                      GetRightmostChild(sibling, bNoBlockCrossing);
    3257               0 :       if (!leaf) { 
    3258               0 :         return sibling;
    3259                 :       }
    3260                 : 
    3261               0 :       return leaf;
    3262                 :     }
    3263                 : 
    3264               0 :     nsINode *parent = cur->GetNodeParent();
    3265               0 :     if (!parent) {
    3266               0 :       return nsnull;
    3267                 :     }
    3268                 : 
    3269               0 :     NS_ASSERTION(IsDescendantOfBody(parent),
    3270                 :                  "We started with a proper descendant of root, and should stop "
    3271                 :                  "if we ever hit the root, so we better have a descendant of "
    3272                 :                  "root now!");
    3273               0 :     if (IsRootNode(parent) ||
    3274               0 :         (bNoBlockCrossing && IsBlockNode(parent)) ||
    3275                 :         parent == aActiveEditorRoot) {
    3276               0 :       return nsnull;
    3277                 :     }
    3278                 : 
    3279               0 :     cur = parent;
    3280                 :   }
    3281                 : 
    3282                 :   NS_NOTREACHED("What part of for(;;) do you not understand?");
    3283                 :   return nsnull;
    3284                 : }
    3285                 : 
    3286                 : nsresult
    3287               0 : nsEditor::GetNextNode(nsIDOMNode* aCurrentNode,
    3288                 :                       bool aEditableNode,
    3289                 :                       nsCOMPtr<nsIDOMNode> *aResultNode,
    3290                 :                       bool bNoBlockCrossing,
    3291                 :                       nsIContent* aActiveEditorRoot)
    3292                 : {
    3293               0 :   nsCOMPtr<nsINode> currentNode = do_QueryInterface(aCurrentNode);
    3294               0 :   if (!currentNode || !aResultNode) {
    3295               0 :     return NS_ERROR_NULL_POINTER;
    3296                 :   }
    3297                 : 
    3298                 :   *aResultNode = do_QueryInterface(GetNextNode(currentNode, aEditableNode,
    3299                 :                                                bNoBlockCrossing,
    3300               0 :                                                aActiveEditorRoot));
    3301               0 :   return NS_OK;
    3302                 : }
    3303                 : 
    3304                 : nsIContent*
    3305               0 : nsEditor::GetNextNode(nsINode* aCurrentNode,
    3306                 :                       bool aEditableNode,
    3307                 :                       bool bNoBlockCrossing,
    3308                 :                       nsIContent* aActiveEditorRoot)
    3309                 : {
    3310               0 :   MOZ_ASSERT(aCurrentNode);
    3311                 : 
    3312               0 :   if (!IsDescendantOfBody(aCurrentNode) ||
    3313                 :       (aActiveEditorRoot &&
    3314                 :        !nsContentUtils::ContentIsDescendantOf(aCurrentNode,
    3315               0 :                                               aActiveEditorRoot))) {
    3316               0 :     return nsnull;
    3317                 :   }
    3318                 : 
    3319                 :   return FindNode(aCurrentNode, true, aEditableNode, bNoBlockCrossing,
    3320               0 :                   aActiveEditorRoot);
    3321                 : }
    3322                 : 
    3323                 : nsIContent*
    3324               0 : nsEditor::FindNode(nsINode *aCurrentNode,
    3325                 :                    bool     aGoForward,
    3326                 :                    bool     aEditableNode,
    3327                 :                    bool     bNoBlockCrossing,
    3328                 :                    nsIContent *aActiveEditorRoot)
    3329                 : {
    3330               0 :   if (IsRootNode(aCurrentNode) || aCurrentNode == aActiveEditorRoot)
    3331                 :   {
    3332                 :     // Don't allow traversal above the root node! This helps
    3333                 :     // prevent us from accidentally editing browser content
    3334                 :     // when the editor is in a text widget.
    3335                 : 
    3336               0 :     return nsnull;
    3337                 :   }
    3338                 : 
    3339                 :   nsIContent* candidate =
    3340                 :     FindNextLeafNode(aCurrentNode, aGoForward, bNoBlockCrossing,
    3341               0 :                      aActiveEditorRoot);
    3342                 :   
    3343               0 :   if (!candidate) {
    3344               0 :     return nsnull;
    3345                 :   }
    3346                 : 
    3347               0 :   if (!aEditableNode || IsEditable(candidate)) {
    3348               0 :     return candidate;
    3349                 :   }
    3350                 : 
    3351                 :   return FindNode(candidate, aGoForward, aEditableNode, bNoBlockCrossing,
    3352               0 :                   aActiveEditorRoot);
    3353                 : }
    3354                 : 
    3355                 : already_AddRefed<nsIDOMNode>
    3356               0 : nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, 
    3357                 :                             bool bNoBlockCrossing)
    3358                 : {
    3359               0 :   NS_ENSURE_TRUE(aCurrentNode, nsnull);
    3360               0 :   nsCOMPtr<nsIDOMNode> resultNode, temp = aCurrentNode;
    3361                 :   bool hasChildren;
    3362               0 :   aCurrentNode->HasChildNodes(&hasChildren);
    3363               0 :   while (hasChildren) {
    3364               0 :     temp->GetLastChild(getter_AddRefs(resultNode));
    3365               0 :     if (resultNode) {
    3366               0 :       if (bNoBlockCrossing && IsBlockNode(resultNode)) {
    3367               0 :         return resultNode.forget();
    3368                 :       }
    3369               0 :       resultNode->HasChildNodes(&hasChildren);
    3370               0 :       temp = resultNode;
    3371                 :     } else {
    3372               0 :       hasChildren = false;
    3373                 :     }
    3374                 :   }
    3375                 : 
    3376               0 :   return resultNode.forget();
    3377                 : }
    3378                 : 
    3379                 : nsIContent*
    3380               0 : nsEditor::GetRightmostChild(nsINode *aCurrentNode,
    3381                 :                             bool     bNoBlockCrossing)
    3382                 : {
    3383               0 :   NS_ENSURE_TRUE(aCurrentNode, nsnull);
    3384               0 :   nsIContent *cur = aCurrentNode->GetLastChild();
    3385               0 :   if (!cur) {
    3386               0 :     return nsnull;
    3387                 :   }
    3388               0 :   for (;;) {
    3389               0 :     if (bNoBlockCrossing && IsBlockNode(cur)) {
    3390               0 :       return cur;
    3391                 :     }
    3392               0 :     nsIContent* next = cur->GetLastChild();
    3393               0 :     if (!next) {
    3394               0 :       return cur;
    3395                 :     }
    3396               0 :     cur = next;
    3397                 :   }
    3398                 : 
    3399                 :   NS_NOTREACHED("What part of for(;;) do you not understand?");
    3400                 :   return nsnull;
    3401                 : }
    3402                 : 
    3403                 : nsIContent*
    3404               0 : nsEditor::GetLeftmostChild(nsINode *aCurrentNode,
    3405                 :                            bool     bNoBlockCrossing)
    3406                 : {
    3407               0 :   NS_ENSURE_TRUE(aCurrentNode, nsnull);
    3408               0 :   nsIContent *cur = aCurrentNode->GetFirstChild();
    3409               0 :   if (!cur) {
    3410               0 :     return nsnull;
    3411                 :   }
    3412               0 :   for (;;) {
    3413               0 :     if (bNoBlockCrossing && IsBlockNode(cur)) {
    3414               0 :       return cur;
    3415                 :     }
    3416               0 :     nsIContent *next = cur->GetFirstChild();
    3417               0 :     if (!next) {
    3418               0 :       return cur;
    3419                 :     }
    3420               0 :     cur = next;
    3421                 :   }
    3422                 : 
    3423                 :   NS_NOTREACHED("What part of for(;;) do you not understand?");
    3424                 :   return nsnull;
    3425                 : }
    3426                 : 
    3427                 : already_AddRefed<nsIDOMNode>
    3428               0 : nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode,
    3429                 :                            bool bNoBlockCrossing)
    3430                 : {
    3431               0 :   NS_ENSURE_TRUE(aCurrentNode, nsnull);
    3432               0 :   nsCOMPtr<nsIDOMNode> resultNode, temp = aCurrentNode;
    3433                 :   bool hasChildren;
    3434               0 :   aCurrentNode->HasChildNodes(&hasChildren);
    3435               0 :   while (hasChildren) {
    3436               0 :     temp->GetFirstChild(getter_AddRefs(resultNode));
    3437               0 :     if (resultNode) {
    3438               0 :       if (bNoBlockCrossing && IsBlockNode(resultNode)) {
    3439               0 :         return resultNode.forget();
    3440                 :       }
    3441               0 :       resultNode->HasChildNodes(&hasChildren);
    3442               0 :       temp = resultNode;
    3443                 :     } else {
    3444               0 :       hasChildren = false;
    3445                 :     }
    3446                 :   }
    3447                 : 
    3448               0 :   return resultNode.forget();
    3449                 : }
    3450                 : 
    3451                 : bool 
    3452               0 : nsEditor::IsBlockNode(nsIDOMNode *aNode)
    3453                 : {
    3454                 :   // stub to be overridden in nsHTMLEditor.
    3455                 :   // screwing around with the class hierarchy here in order
    3456                 :   // to not duplicate the code in GetNextNode/GetPrevNode
    3457                 :   // across both nsEditor/nsHTMLEditor.  
    3458               0 :   return false;
    3459                 : }
    3460                 : 
    3461                 : bool 
    3462               0 : nsEditor::IsBlockNode(nsINode *aNode)
    3463                 : {
    3464                 :   // stub to be overridden in nsHTMLEditor.
    3465                 :   // screwing around with the class hierarchy here in order
    3466                 :   // to not duplicate the code in GetNextNode/GetPrevNode
    3467                 :   // across both nsEditor/nsHTMLEditor.
    3468               0 :   return false;
    3469                 : }
    3470                 : 
    3471                 : bool
    3472               0 : nsEditor::CanContainTag(nsIDOMNode* aParent, const nsAString &aChildTag)
    3473                 : {
    3474               0 :   nsCOMPtr<nsIDOMElement> parentElement = do_QueryInterface(aParent);
    3475               0 :   NS_ENSURE_TRUE(parentElement, false);
    3476                 :   
    3477               0 :   nsAutoString parentStringTag;
    3478               0 :   parentElement->GetTagName(parentStringTag);
    3479               0 :   return TagCanContainTag(parentStringTag, aChildTag);
    3480                 : }
    3481                 : 
    3482                 : bool 
    3483               0 : nsEditor::TagCanContain(const nsAString &aParentTag, nsIDOMNode* aChild)
    3484                 : {
    3485               0 :   nsAutoString childStringTag;
    3486                 :   
    3487               0 :   if (IsTextNode(aChild)) 
    3488                 :   {
    3489               0 :     childStringTag.AssignLiteral("#text");
    3490                 :   }
    3491                 :   else
    3492                 :   {
    3493               0 :     nsCOMPtr<nsIDOMElement> childElement = do_QueryInterface(aChild);
    3494               0 :     NS_ENSURE_TRUE(childElement, false);
    3495               0 :     childElement->GetTagName(childStringTag);
    3496                 :   }
    3497               0 :   return TagCanContainTag(aParentTag, childStringTag);
    3498                 : }
    3499                 : 
    3500                 : bool 
    3501               0 : nsEditor::TagCanContainTag(const nsAString &aParentTag, const nsAString &aChildTag)
    3502                 : {
    3503               0 :   return true;
    3504                 : }
    3505                 : 
    3506                 : bool
    3507               0 : nsEditor::IsRootNode(nsIDOMNode *inNode)
    3508                 : {
    3509               0 :   NS_ENSURE_TRUE(inNode, false);
    3510                 : 
    3511               0 :   nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
    3512                 : 
    3513               0 :   return inNode == rootNode;
    3514                 : }
    3515                 : 
    3516                 : bool 
    3517               0 : nsEditor::IsRootNode(nsINode *inNode) 
    3518                 : {
    3519               0 :   NS_ENSURE_TRUE(inNode, false);
    3520                 : 
    3521               0 :   nsCOMPtr<nsINode> rootNode = GetRoot();
    3522                 : 
    3523               0 :   return inNode == rootNode;
    3524                 : }
    3525                 : 
    3526                 : bool 
    3527               0 : nsEditor::IsDescendantOfBody(nsIDOMNode *inNode) 
    3528                 : {
    3529               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(inNode);
    3530               0 :   return IsDescendantOfBody(node);
    3531                 : }
    3532                 : 
    3533                 : bool
    3534               0 : nsEditor::IsDescendantOfBody(nsINode *inNode)
    3535                 : {
    3536               0 :   NS_ENSURE_TRUE(inNode, false);
    3537               0 :   nsCOMPtr<nsIContent> root = GetRoot();
    3538               0 :   NS_ENSURE_TRUE(root, false);
    3539                 : 
    3540               0 :   return nsContentUtils::ContentIsDescendantOf(inNode, root);
    3541                 : }
    3542                 : 
    3543                 : bool 
    3544               0 : nsEditor::IsContainer(nsIDOMNode *aNode)
    3545                 : {
    3546               0 :   return aNode ? true : false;
    3547                 : }
    3548                 : 
    3549                 : bool
    3550               0 : nsEditor::IsTextInDirtyFrameVisible(nsIContent *aNode)
    3551                 : {
    3552                 :   // virtual method
    3553                 :   //
    3554                 :   // If this is a simple non-html editor,
    3555                 :   // the best we can do is to assume it's visible.
    3556                 : 
    3557               0 :   return true;
    3558                 : }
    3559                 : 
    3560                 : static inline bool
    3561               0 : IsElementVisible(dom::Element* aElement)
    3562                 : {
    3563               0 :   if (aElement->GetPrimaryFrame()) {
    3564                 :     // It's visible, for our purposes
    3565               0 :     return true;
    3566                 :   }
    3567                 : 
    3568               0 :   nsIContent *cur = aElement;
    3569               0 :   for (; ;) {
    3570                 :     // Walk up the tree looking for the nearest ancestor with a frame.
    3571                 :     // The state of the child right below it will determine whether
    3572                 :     // we might possibly have a frame or not.
    3573               0 :     bool haveLazyBitOnChild = cur->HasFlag(NODE_NEEDS_FRAME);
    3574               0 :     cur = cur->GetFlattenedTreeParent();
    3575               0 :     if (!cur) {
    3576               0 :       if (!haveLazyBitOnChild) {
    3577                 :         // None of our ancestors have lazy bits set, so we shouldn't
    3578                 :         // have a frame
    3579               0 :         return false;
    3580                 :       }
    3581                 : 
    3582                 :       // The root has a lazy frame construction bit.  We need to check
    3583                 :       // our style.
    3584               0 :       break;
    3585                 :     }
    3586                 : 
    3587               0 :     if (cur->GetPrimaryFrame()) {
    3588               0 :       if (!haveLazyBitOnChild) {
    3589                 :         // Our ancestor directly under |cur| doesn't have lazy bits;
    3590                 :         // that means we won't get a frame
    3591               0 :         return false;
    3592                 :       }
    3593                 : 
    3594               0 :       if (cur->GetPrimaryFrame()->IsLeaf()) {
    3595                 :         // Nothing under here will ever get frames
    3596               0 :         return false;
    3597                 :       }
    3598                 : 
    3599                 :       // Otherwise, we might end up with a frame when that lazy bit is
    3600                 :       // processed.  Figure out our actual style.
    3601               0 :       break;
    3602                 :     }
    3603                 :   }
    3604                 : 
    3605                 :   // Now it might be that we have no frame because we're in a
    3606                 :   // display:none subtree, or it might be that we're just dealing with
    3607                 :   // lazy frame construction and it hasn't happened yet.  Check which
    3608                 :   // one it is.
    3609                 :   nsRefPtr<nsStyleContext> styleContext =
    3610                 :     nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
    3611               0 :                                                          nsnull, nsnull);
    3612               0 :   if (styleContext) {
    3613               0 :     return styleContext->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_NONE;
    3614                 :   }
    3615               0 :   return false;
    3616                 : }
    3617                 : 
    3618                 : bool 
    3619               0 : nsEditor::IsEditable(nsIDOMNode *aNode)
    3620                 : {
    3621               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
    3622               0 :   return IsEditable(content);
    3623                 : }
    3624                 : 
    3625                 : bool
    3626               0 : nsEditor::IsEditable(nsIContent *aNode)
    3627                 : {
    3628               0 :   NS_ENSURE_TRUE(aNode, false);
    3629                 : 
    3630               0 :   if (IsMozEditorBogusNode(aNode) || !IsModifiableNode(aNode)) return false;
    3631                 : 
    3632                 :   // see if it has a frame.  If so, we'll edit it.
    3633                 :   // special case for textnodes: frame must have width.
    3634               0 :   if (aNode->IsElement() && !IsElementVisible(aNode->AsElement())) {
    3635                 :     // If the element has no frame, it's not editable.  Note that we
    3636                 :     // need to check IsElement() here, because some of our tests
    3637                 :     // rely on frameless textnodes being visible.
    3638               0 :     return false;
    3639                 :   }
    3640               0 :   switch (aNode->NodeType()) {
    3641                 :     case nsIDOMNode::ELEMENT_NODE:
    3642               0 :       return true; // not a text node; not invisible
    3643                 :     case nsIDOMNode::TEXT_NODE:
    3644               0 :       return IsTextInDirtyFrameVisible(aNode);
    3645                 :     default:
    3646               0 :       return false;
    3647                 :   }
    3648                 : }
    3649                 : 
    3650                 : bool
    3651               0 : nsEditor::IsMozEditorBogusNode(nsIContent *element)
    3652                 : {
    3653                 :   return element &&
    3654                 :          element->AttrValueIs(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
    3655               0 :                               kMOZEditorBogusNodeValue, eCaseMatters);
    3656                 : }
    3657                 : 
    3658                 : nsresult
    3659               0 : nsEditor::CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount) 
    3660                 : {
    3661               0 :   outCount = 0;
    3662               0 :   if (!aNode) { return NS_ERROR_NULL_POINTER; }
    3663               0 :   nsresult res=NS_OK;
    3664                 :   bool hasChildNodes;
    3665               0 :   aNode->HasChildNodes(&hasChildNodes);
    3666               0 :   if (hasChildNodes)
    3667                 :   {
    3668               0 :     nsCOMPtr<nsIDOMNodeList>nodeList;
    3669               0 :     res = aNode->GetChildNodes(getter_AddRefs(nodeList));
    3670               0 :     if (NS_SUCCEEDED(res) && nodeList) 
    3671                 :     {
    3672                 :       PRUint32 i;
    3673                 :       PRUint32 len;
    3674               0 :       nodeList->GetLength(&len);
    3675               0 :       for (i=0 ; i<len; i++)
    3676                 :       {
    3677               0 :         nsCOMPtr<nsIDOMNode> child;
    3678               0 :         res = nodeList->Item((PRInt32)i, getter_AddRefs(child));
    3679               0 :         if ((NS_SUCCEEDED(res)) && (child))
    3680                 :         {
    3681               0 :           if (IsEditable(child))
    3682                 :           {
    3683               0 :             outCount++;
    3684                 :           }
    3685                 :         }
    3686                 :       }
    3687                 :     }
    3688               0 :     else if (!nodeList)
    3689               0 :       res = NS_ERROR_NULL_POINTER;
    3690                 :   }
    3691               0 :   return res;
    3692                 : }
    3693                 : 
    3694                 : //END nsEditor static utility methods
    3695                 : 
    3696                 : 
    3697               0 : NS_IMETHODIMP nsEditor::IncrementModificationCount(PRInt32 inNumMods)
    3698                 : {
    3699               0 :   PRUint32 oldModCount = mModCount;
    3700                 : 
    3701               0 :   mModCount += inNumMods;
    3702                 : 
    3703               0 :   if ((oldModCount == 0 && mModCount != 0)
    3704                 :    || (oldModCount != 0 && mModCount == 0))
    3705               0 :     NotifyDocumentListeners(eDocumentStateChanged);
    3706               0 :   return NS_OK;
    3707                 : }
    3708                 : 
    3709                 : 
    3710               0 : NS_IMETHODIMP nsEditor::GetModificationCount(PRInt32 *outModCount)
    3711                 : {
    3712               0 :   NS_ENSURE_ARG_POINTER(outModCount);
    3713               0 :   *outModCount = mModCount;
    3714               0 :   return NS_OK;
    3715                 : }
    3716                 : 
    3717                 : 
    3718               0 : NS_IMETHODIMP nsEditor::ResetModificationCount()
    3719                 : {
    3720               0 :   bool doNotify = (mModCount != 0);
    3721                 : 
    3722               0 :   mModCount = 0;
    3723                 : 
    3724               0 :   if (doNotify)
    3725               0 :     NotifyDocumentListeners(eDocumentStateChanged);
    3726               0 :   return NS_OK;
    3727                 : }
    3728                 : 
    3729                 : //END nsEditor Private methods
    3730                 : 
    3731                 : 
    3732                 : 
    3733                 : ///////////////////////////////////////////////////////////////////////////
    3734                 : // GetTag: digs out the atom for the tag of this node
    3735                 : //
    3736                 : nsIAtom *
    3737               0 : nsEditor::GetTag(nsIDOMNode *aNode)
    3738                 : {
    3739               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
    3740                 : 
    3741               0 :   if (!content) 
    3742                 :   {
    3743               0 :     NS_ASSERTION(aNode, "null node passed to nsEditor::Tag()");
    3744                 : 
    3745               0 :     return nsnull;
    3746                 :   }
    3747                 :   
    3748               0 :   return content->Tag();
    3749                 : }
    3750                 : 
    3751                 : 
    3752                 : ///////////////////////////////////////////////////////////////////////////
    3753                 : // GetTagString: digs out string for the tag of this node
    3754                 : //                    
    3755                 : nsresult 
    3756               0 : nsEditor::GetTagString(nsIDOMNode *aNode, nsAString& outString)
    3757                 : {
    3758               0 :   if (!aNode) 
    3759                 :   {
    3760               0 :     NS_NOTREACHED("null node passed to nsEditor::GetTag()");
    3761               0 :     return NS_ERROR_NULL_POINTER;
    3762                 :   }
    3763                 :   
    3764               0 :   nsIAtom *atom = GetTag(aNode);
    3765               0 :   if (!atom)
    3766                 :   {
    3767               0 :     return NS_ERROR_FAILURE;
    3768                 :   }
    3769                 : 
    3770               0 :   atom->ToString(outString);
    3771               0 :   return NS_OK;
    3772                 : }
    3773                 : 
    3774                 : 
    3775                 : ///////////////////////////////////////////////////////////////////////////
    3776                 : // NodesSameType: do these nodes have the same tag?
    3777                 : //                    
    3778                 : bool 
    3779               0 : nsEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
    3780                 : {
    3781               0 :   if (!aNode1 || !aNode2) 
    3782                 :   {
    3783               0 :     NS_NOTREACHED("null node passed to nsEditor::NodesSameType()");
    3784               0 :     return false;
    3785                 :   }
    3786                 :   
    3787               0 :   return GetTag(aNode1) == GetTag(aNode2);
    3788                 : }
    3789                 : 
    3790                 : 
    3791                 : // IsTextOrElementNode: true if node of dom type element or text
    3792                 : //               
    3793                 : bool
    3794               0 : nsEditor::IsTextOrElementNode(nsIDOMNode *aNode)
    3795                 : {
    3796               0 :   if (!aNode)
    3797                 :   {
    3798               0 :     NS_NOTREACHED("null node passed to IsTextOrElementNode()");
    3799               0 :     return false;
    3800                 :   }
    3801                 :   
    3802                 :   PRUint16 nodeType;
    3803               0 :   aNode->GetNodeType(&nodeType);
    3804               0 :   return ((nodeType == nsIDOMNode::ELEMENT_NODE) || (nodeType == nsIDOMNode::TEXT_NODE));
    3805                 : }
    3806                 : 
    3807                 : 
    3808                 : 
    3809                 : ///////////////////////////////////////////////////////////////////////////
    3810                 : // IsTextNode: true if node of dom type text
    3811                 : //               
    3812                 : bool
    3813               0 : nsEditor::IsTextNode(nsIDOMNode *aNode)
    3814                 : {
    3815               0 :   if (!aNode)
    3816                 :   {
    3817               0 :     NS_NOTREACHED("null node passed to IsTextNode()");
    3818               0 :     return false;
    3819                 :   }
    3820                 :   
    3821                 :   PRUint16 nodeType;
    3822               0 :   aNode->GetNodeType(&nodeType);
    3823               0 :   return (nodeType == nsIDOMNode::TEXT_NODE);
    3824                 : }
    3825                 : 
    3826                 : bool
    3827               0 : nsEditor::IsTextNode(nsINode *aNode)
    3828                 : {
    3829               0 :   return aNode->NodeType() == nsIDOMNode::TEXT_NODE;
    3830                 : }
    3831                 : 
    3832                 : ///////////////////////////////////////////////////////////////////////////
    3833                 : // GetIndexOf: returns the position index of the node in the parent
    3834                 : //
    3835                 : PRInt32 
    3836               0 : nsEditor::GetIndexOf(nsIDOMNode *parent, nsIDOMNode *child)
    3837                 : {
    3838               0 :   nsCOMPtr<nsINode> parentNode = do_QueryInterface(parent);
    3839               0 :   NS_PRECONDITION(parentNode, "null parentNode in nsEditor::GetIndexOf");
    3840               0 :   NS_PRECONDITION(parentNode->IsNodeOfType(nsINode::eCONTENT) ||
    3841                 :                     parentNode->IsNodeOfType(nsINode::eDOCUMENT),
    3842                 :                   "The parent node must be an element node or a document node");
    3843                 : 
    3844               0 :   nsCOMPtr<nsIContent> cChild = do_QueryInterface(child);
    3845               0 :   NS_PRECONDITION(cChild, "null content in nsEditor::GetIndexOf");
    3846                 : 
    3847               0 :   return parentNode->IndexOf(cChild);
    3848                 : }
    3849                 :   
    3850                 : 
    3851                 : ///////////////////////////////////////////////////////////////////////////
    3852                 : // GetChildAt: returns the node at this position index in the parent
    3853                 : //
    3854                 : nsCOMPtr<nsIDOMNode> 
    3855               0 : nsEditor::GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
    3856                 : {
    3857               0 :   nsCOMPtr<nsIDOMNode> resultNode;
    3858                 :   
    3859               0 :   nsCOMPtr<nsIContent> parent = do_QueryInterface(aParent);
    3860                 : 
    3861               0 :   NS_ENSURE_TRUE(parent, resultNode);
    3862                 : 
    3863               0 :   resultNode = do_QueryInterface(parent->GetChildAt(aOffset));
    3864                 : 
    3865                 :   return resultNode;
    3866                 : }
    3867                 : 
    3868                 : ///////////////////////////////////////////////////////////////////////////
    3869                 : // GetNodeAtRangeOffsetPoint: returns the node at this position in a range,
    3870                 : // assuming that aParentOrNode is the node itself if it's a text node, or
    3871                 : // the node's parent otherwise.
    3872                 : //
    3873                 : nsCOMPtr<nsIDOMNode>
    3874               0 : nsEditor::GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, PRInt32 aOffset)
    3875                 : {
    3876               0 :   if (IsTextNode(aParentOrNode)) {
    3877               0 :     return aParentOrNode;
    3878                 :   }
    3879               0 :   return GetChildAt(aParentOrNode, aOffset);
    3880                 : }
    3881                 : 
    3882                 : 
    3883                 : ///////////////////////////////////////////////////////////////////////////
    3884                 : // GetStartNodeAndOffset: returns whatever the start parent & offset is of 
    3885                 : //                        the first range in the selection.
    3886                 : nsresult 
    3887               0 : nsEditor::GetStartNodeAndOffset(nsISelection *aSelection,
    3888                 :                                        nsIDOMNode **outStartNode,
    3889                 :                                        PRInt32 *outStartOffset)
    3890                 : {
    3891               0 :   NS_ENSURE_TRUE(outStartNode && outStartOffset && aSelection, NS_ERROR_NULL_POINTER);
    3892                 : 
    3893               0 :   *outStartNode = nsnull;
    3894               0 :   *outStartOffset = 0;
    3895                 : 
    3896               0 :   nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
    3897               0 :   nsCOMPtr<nsIEnumerator> enumerator;
    3898               0 :   nsresult result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
    3899               0 :   NS_ENSURE_SUCCESS(result, result);
    3900               0 :   NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
    3901                 : 
    3902               0 :   enumerator->First(); 
    3903               0 :   nsCOMPtr<nsISupports> currentItem;
    3904               0 :   result = enumerator->CurrentItem(getter_AddRefs(currentItem));
    3905               0 :   NS_ENSURE_SUCCESS(result, result);
    3906                 : 
    3907               0 :   nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    3908               0 :   NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    3909                 : 
    3910               0 :   result = range->GetStartContainer(outStartNode);
    3911               0 :   NS_ENSURE_SUCCESS(result, result);
    3912                 : 
    3913               0 :   result = range->GetStartOffset(outStartOffset);
    3914               0 :   NS_ENSURE_SUCCESS(result, result);
    3915                 : 
    3916               0 :   return NS_OK;
    3917                 : }
    3918                 : 
    3919                 : 
    3920                 : ///////////////////////////////////////////////////////////////////////////
    3921                 : // GetEndNodeAndOffset: returns whatever the end parent & offset is of 
    3922                 : //                        the first range in the selection.
    3923                 : nsresult 
    3924               0 : nsEditor::GetEndNodeAndOffset(nsISelection *aSelection,
    3925                 :                                        nsIDOMNode **outEndNode,
    3926                 :                                        PRInt32 *outEndOffset)
    3927                 : {
    3928               0 :   NS_ENSURE_TRUE(outEndNode && outEndOffset, NS_ERROR_NULL_POINTER);
    3929                 : 
    3930               0 :   *outEndNode = nsnull;
    3931                 :     
    3932               0 :   nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
    3933               0 :   nsCOMPtr<nsIEnumerator> enumerator;
    3934               0 :   nsresult result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
    3935               0 :   if (NS_FAILED(result) || !enumerator)
    3936               0 :     return NS_ERROR_FAILURE;
    3937                 :     
    3938               0 :   enumerator->First(); 
    3939               0 :   nsCOMPtr<nsISupports> currentItem;
    3940               0 :   if (NS_FAILED(enumerator->CurrentItem(getter_AddRefs(currentItem))))
    3941               0 :     return NS_ERROR_FAILURE;
    3942                 : 
    3943               0 :   nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    3944               0 :   NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    3945                 :     
    3946               0 :   if (NS_FAILED(range->GetEndContainer(outEndNode)))
    3947               0 :     return NS_ERROR_FAILURE;
    3948                 :     
    3949               0 :   if (NS_FAILED(range->GetEndOffset(outEndOffset)))
    3950               0 :     return NS_ERROR_FAILURE;
    3951                 :     
    3952               0 :   return NS_OK;
    3953                 : }
    3954                 : 
    3955                 : 
    3956                 : ///////////////////////////////////////////////////////////////////////////
    3957                 : // IsPreformatted: checks the style info for the node for the preformatted
    3958                 : //                 text style.
    3959                 : nsresult 
    3960               0 : nsEditor::IsPreformatted(nsIDOMNode *aNode, bool *aResult)
    3961                 : {
    3962               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
    3963                 :   
    3964               0 :   NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER);
    3965                 :   
    3966               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    3967               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    3968                 : 
    3969                 :   // Look at the node (and its parent if it's not an element), and grab its style context
    3970               0 :   nsRefPtr<nsStyleContext> elementStyle;
    3971               0 :   if (!content->IsElement()) {
    3972               0 :     content = content->GetParent();
    3973                 :   }
    3974               0 :   if (content && content->IsElement()) {
    3975               0 :     elementStyle = nsComputedDOMStyle::GetStyleContextForElement(content->AsElement(),
    3976                 :                                                                  nsnull,
    3977               0 :                                                                  ps);
    3978                 :   }
    3979                 : 
    3980               0 :   if (!elementStyle)
    3981                 :   {
    3982                 :     // Consider nodes without a style context to be NOT preformatted:
    3983                 :     // For instance, this is true of JS tags inside the body (which show
    3984                 :     // up as #text nodes but have no style context).
    3985               0 :     *aResult = false;
    3986               0 :     return NS_OK;
    3987                 :   }
    3988                 : 
    3989               0 :   const nsStyleText* styleText = elementStyle->GetStyleText();
    3990                 : 
    3991               0 :   *aResult = styleText->WhiteSpaceIsSignificant();
    3992               0 :   return NS_OK;
    3993                 : }
    3994                 : 
    3995                 : 
    3996                 : ///////////////////////////////////////////////////////////////////////////
    3997                 : // SplitNodeDeep: this splits a node "deeply", splitting children as 
    3998                 : //                appropriate.  The place to split is represented by
    3999                 : //                a dom point at {splitPointParent, splitPointOffset}.
    4000                 : //                That dom point must be inside aNode, which is the node to 
    4001                 : //                split.  outOffset is set to the offset in the parent of aNode where
    4002                 : //                the split terminates - where you would want to insert 
    4003                 : //                a new element, for instance, if that's why you were splitting 
    4004                 : //                the node.
    4005                 : //
    4006                 : nsresult
    4007               0 : nsEditor::SplitNodeDeep(nsIDOMNode *aNode, 
    4008                 :                         nsIDOMNode *aSplitPointParent, 
    4009                 :                         PRInt32 aSplitPointOffset,
    4010                 :                         PRInt32 *outOffset,
    4011                 :                         bool    aNoEmptyContainers,
    4012                 :                         nsCOMPtr<nsIDOMNode> *outLeftNode,
    4013                 :                         nsCOMPtr<nsIDOMNode> *outRightNode)
    4014                 : {
    4015               0 :   NS_ENSURE_TRUE(aNode && aSplitPointParent && outOffset, NS_ERROR_NULL_POINTER);
    4016               0 :   nsCOMPtr<nsIDOMNode> tempNode, parentNode;  
    4017               0 :   PRInt32 offset = aSplitPointOffset;
    4018                 :   nsresult res;
    4019                 :   
    4020               0 :   if (outLeftNode)  *outLeftNode  = nsnull;
    4021               0 :   if (outRightNode) *outRightNode = nsnull;
    4022                 :   
    4023               0 :   nsCOMPtr<nsIDOMNode> nodeToSplit = do_QueryInterface(aSplitPointParent);
    4024               0 :   while (nodeToSplit)
    4025                 :   {
    4026                 :     // need to insert rules code call here to do things like
    4027                 :     // not split a list if you are after the last <li> or before the first, etc.
    4028                 :     // for now we just have some smarts about unneccessarily splitting
    4029                 :     // textnodes, which should be universal enough to put straight in
    4030                 :     // this nsEditor routine.
    4031                 :     
    4032               0 :     nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(nodeToSplit);
    4033                 :     PRUint32 len;
    4034               0 :     bool bDoSplit = false;
    4035               0 :     res = GetLengthOfDOMNode(nodeToSplit, len);
    4036               0 :     NS_ENSURE_SUCCESS(res, res);
    4037                 :     
    4038               0 :     if (!(aNoEmptyContainers || nodeAsText) || (offset && (offset != (PRInt32)len)))
    4039                 :     {
    4040               0 :       bDoSplit = true;
    4041               0 :       res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
    4042               0 :       NS_ENSURE_SUCCESS(res, res);
    4043               0 :       if (outRightNode) *outRightNode = nodeToSplit;
    4044               0 :       if (outLeftNode)  *outLeftNode  = tempNode;
    4045                 :     }
    4046                 : 
    4047               0 :     res = nodeToSplit->GetParentNode(getter_AddRefs(parentNode));
    4048               0 :     NS_ENSURE_SUCCESS(res, res);
    4049               0 :     NS_ENSURE_TRUE(parentNode, NS_ERROR_FAILURE);
    4050                 : 
    4051               0 :     if (!bDoSplit && offset)  // must be "end of text node" case, we didn't split it, just move past it
    4052                 :     {
    4053               0 :       offset = GetIndexOf(parentNode, nodeToSplit) +1;
    4054               0 :       if (outLeftNode)  *outLeftNode  = nodeToSplit;
    4055                 :     }
    4056                 :     else
    4057                 :     {
    4058               0 :       offset = GetIndexOf(parentNode, nodeToSplit);
    4059               0 :       if (outRightNode) *outRightNode = nodeToSplit;
    4060                 :     }
    4061                 :     
    4062               0 :     if (nodeToSplit.get() == aNode)  // we split all the way up to (and including) aNode; we're done
    4063                 :       break;
    4064                 :       
    4065               0 :     nodeToSplit = parentNode;
    4066                 :   }
    4067                 :   
    4068               0 :   if (!nodeToSplit)
    4069                 :   {
    4070               0 :     NS_NOTREACHED("null node obtained in nsEditor::SplitNodeDeep()");
    4071               0 :     return NS_ERROR_FAILURE;
    4072                 :   }
    4073                 :   
    4074               0 :   *outOffset = offset;
    4075                 :   
    4076               0 :   return NS_OK;
    4077                 : }
    4078                 : 
    4079                 : 
    4080                 : ///////////////////////////////////////////////////////////////////////////
    4081                 : // JoinNodeDeep:  this joins two like nodes "deeply", joining children as 
    4082                 : //                appropriate.  
    4083                 : nsresult
    4084               0 : nsEditor::JoinNodeDeep(nsIDOMNode *aLeftNode, 
    4085                 :                        nsIDOMNode *aRightNode,
    4086                 :                        nsCOMPtr<nsIDOMNode> *aOutJoinNode, 
    4087                 :                        PRInt32 *outOffset)
    4088                 : {
    4089               0 :   NS_ENSURE_TRUE(aLeftNode && aRightNode && aOutJoinNode && outOffset, NS_ERROR_NULL_POINTER);
    4090                 : 
    4091                 :   // while the rightmost children and their descendants of the left node 
    4092                 :   // match the leftmost children and their descendants of the right node
    4093                 :   // join them up.  Can you say that three times fast?
    4094                 :   
    4095               0 :   nsCOMPtr<nsIDOMNode> leftNodeToJoin = do_QueryInterface(aLeftNode);
    4096               0 :   nsCOMPtr<nsIDOMNode> rightNodeToJoin = do_QueryInterface(aRightNode);
    4097               0 :   nsCOMPtr<nsIDOMNode> parentNode,tmp;
    4098               0 :   nsresult res = NS_OK;
    4099                 :   
    4100               0 :   rightNodeToJoin->GetParentNode(getter_AddRefs(parentNode));
    4101                 :   
    4102               0 :   while (leftNodeToJoin && rightNodeToJoin && parentNode &&
    4103               0 :           NodesSameType(leftNodeToJoin, rightNodeToJoin))
    4104                 :   {
    4105                 :     // adjust out params
    4106                 :     PRUint32 length;
    4107               0 :     if (IsTextNode(leftNodeToJoin))
    4108                 :     {
    4109               0 :       nsCOMPtr<nsIDOMCharacterData>nodeAsText;
    4110               0 :       nodeAsText = do_QueryInterface(leftNodeToJoin);
    4111               0 :       nodeAsText->GetLength(&length);
    4112                 :     }
    4113                 :     else
    4114                 :     {
    4115               0 :       res = GetLengthOfDOMNode(leftNodeToJoin, length);
    4116               0 :       NS_ENSURE_SUCCESS(res, res);
    4117                 :     }
    4118                 :     
    4119               0 :     *aOutJoinNode = rightNodeToJoin;
    4120               0 :     *outOffset = length;
    4121                 :     
    4122                 :     // do the join
    4123               0 :     res = JoinNodes(leftNodeToJoin, rightNodeToJoin, parentNode);
    4124               0 :     NS_ENSURE_SUCCESS(res, res);
    4125                 :     
    4126               0 :     if (IsTextNode(parentNode)) // we've joined all the way down to text nodes, we're done!
    4127               0 :       return NS_OK;
    4128                 : 
    4129                 :     else
    4130                 :     {
    4131                 :       // get new left and right nodes, and begin anew
    4132               0 :       parentNode = rightNodeToJoin;
    4133               0 :       leftNodeToJoin = GetChildAt(parentNode, length-1);
    4134               0 :       rightNodeToJoin = GetChildAt(parentNode, length);
    4135                 : 
    4136                 :       // skip over non-editable nodes
    4137               0 :       while (leftNodeToJoin && !IsEditable(leftNodeToJoin))
    4138                 :       {
    4139               0 :         leftNodeToJoin->GetPreviousSibling(getter_AddRefs(tmp));
    4140               0 :         leftNodeToJoin = tmp;
    4141                 :       }
    4142               0 :       if (!leftNodeToJoin) break;
    4143                 :     
    4144               0 :       while (rightNodeToJoin && !IsEditable(rightNodeToJoin))
    4145                 :       {
    4146               0 :         rightNodeToJoin->GetNextSibling(getter_AddRefs(tmp));
    4147               0 :         rightNodeToJoin = tmp;
    4148                 :       }
    4149               0 :       if (!rightNodeToJoin) break;
    4150                 :     }
    4151                 :   }
    4152                 :   
    4153               0 :   return res;
    4154                 : }
    4155                 : 
    4156               0 : nsresult nsEditor::BeginUpdateViewBatch()
    4157                 : {
    4158               0 :   NS_PRECONDITION(mUpdateCount >= 0, "bad state");
    4159                 : 
    4160                 : 
    4161               0 :   if (0 == mUpdateCount)
    4162                 :   {
    4163                 :     // Turn off selection updates and notifications.
    4164                 : 
    4165               0 :     nsCOMPtr<nsISelection> selection;
    4166               0 :     GetSelection(getter_AddRefs(selection));
    4167                 : 
    4168               0 :     if (selection) 
    4169                 :     {
    4170               0 :       nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
    4171               0 :       selPrivate->StartBatchChanges();
    4172                 :     }
    4173                 :   }
    4174                 : 
    4175               0 :   mUpdateCount++;
    4176                 : 
    4177               0 :   return NS_OK;
    4178                 : }
    4179                 : 
    4180                 : 
    4181               0 : nsresult nsEditor::EndUpdateViewBatch()
    4182                 : {
    4183               0 :   NS_PRECONDITION(mUpdateCount > 0, "bad state");
    4184                 :   
    4185               0 :   if (mUpdateCount <= 0)
    4186                 :   {
    4187               0 :     mUpdateCount = 0;
    4188               0 :     return NS_ERROR_FAILURE;
    4189                 :   }
    4190                 : 
    4191               0 :   mUpdateCount--;
    4192                 : 
    4193               0 :   if (0 == mUpdateCount)
    4194                 :   {
    4195                 :     // Hide the caret with an StCaretHider. By the time it goes out
    4196                 :     // of scope and tries to show the caret, reflow and selection changed
    4197                 :     // notifications should've happened so the caret should have enough info
    4198                 :     // to draw at the correct position.
    4199                 : 
    4200               0 :     nsRefPtr<nsCaret> caret;
    4201               0 :     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
    4202                 : 
    4203               0 :     if (presShell)
    4204               0 :       caret = presShell->GetCaret();
    4205                 : 
    4206               0 :     StCaretHider caretHider(caret);
    4207                 : 
    4208                 :     // Turn selection updating and notifications back on.
    4209                 : 
    4210               0 :     nsCOMPtr<nsISelection>selection;
    4211               0 :     GetSelection(getter_AddRefs(selection));
    4212                 : 
    4213               0 :     if (selection) {
    4214               0 :       nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
    4215               0 :       selPrivate->EndBatchChanges();
    4216                 :     }
    4217                 :   }
    4218                 : 
    4219               0 :   return NS_OK;
    4220                 : }
    4221                 : 
    4222                 : bool 
    4223               0 : nsEditor::GetShouldTxnSetSelection()
    4224                 : {
    4225               0 :   return mShouldTxnSetSelection;
    4226                 : }
    4227                 : 
    4228                 : 
    4229                 : NS_IMETHODIMP 
    4230               0 : nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
    4231                 : {
    4232               0 :   nsCOMPtr<nsISelection>selection;
    4233               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    4234               0 :   NS_ENSURE_SUCCESS(res, res);
    4235               0 :   nsRefPtr<EditAggregateTxn> txn;
    4236               0 :   nsCOMPtr<nsIDOMNode> deleteNode;
    4237               0 :   PRInt32 deleteCharOffset = 0, deleteCharLength = 0;
    4238                 :   res = CreateTxnForDeleteSelection(aAction, getter_AddRefs(txn),
    4239               0 :                                     getter_AddRefs(deleteNode),
    4240               0 :                                     &deleteCharOffset, &deleteCharLength);
    4241               0 :   nsCOMPtr<nsIDOMCharacterData> deleteCharData(do_QueryInterface(deleteNode));
    4242                 : 
    4243               0 :   if (NS_SUCCEEDED(res))  
    4244                 :   {
    4245               0 :     nsAutoRules beginRulesSniffing(this, kOpDeleteSelection, aAction);
    4246                 :     PRInt32 i;
    4247                 :     // Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
    4248               0 :     if (!deleteNode)
    4249               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4250               0 :         mActionListeners[i]->WillDeleteSelection(selection);
    4251               0 :     else if (deleteCharData)
    4252               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4253               0 :         mActionListeners[i]->WillDeleteText(deleteCharData, deleteCharOffset, 1);
    4254                 :     else
    4255               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4256               0 :         mActionListeners[i]->WillDeleteNode(deleteNode);
    4257                 : 
    4258                 :     // Delete the specified amount
    4259               0 :     res = DoTransaction(txn);  
    4260                 : 
    4261                 :     // Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
    4262               0 :     if (!deleteNode)
    4263               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4264               0 :         mActionListeners[i]->DidDeleteSelection(selection);
    4265               0 :     else if (deleteCharData)
    4266               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4267               0 :         mActionListeners[i]->DidDeleteText(deleteCharData, deleteCharOffset, 1, res);
    4268                 :     else
    4269               0 :       for (i = 0; i < mActionListeners.Count(); i++)
    4270               0 :         mActionListeners[i]->DidDeleteNode(deleteNode, res);
    4271                 :   }
    4272                 : 
    4273               0 :   return res;
    4274                 : }
    4275                 : 
    4276                 : // XXX: error handling in this routine needs to be cleaned up!
    4277                 : NS_IMETHODIMP
    4278               0 : nsEditor::DeleteSelectionAndCreateNode(const nsAString& aTag,
    4279                 :                                            nsIDOMNode ** aNewNode)
    4280                 : {
    4281               0 :   nsCOMPtr<nsIDOMNode> parentSelectedNode;
    4282                 :   PRInt32 offsetOfNewNode;
    4283                 :   nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
    4284               0 :                                                           offsetOfNewNode);
    4285               0 :   NS_ENSURE_SUCCESS(result, result);
    4286                 : 
    4287               0 :   nsCOMPtr<nsIDOMNode> newNode;
    4288                 :   result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
    4289               0 :                       getter_AddRefs(newNode));
    4290                 :   // XXX: ERROR_HANDLING  check result, and make sure aNewNode is set correctly in success/failure cases
    4291               0 :   *aNewNode = newNode;
    4292               0 :   NS_IF_ADDREF(*aNewNode);
    4293                 : 
    4294                 :   // we want the selection to be just after the new node
    4295               0 :   nsCOMPtr<nsISelection> selection;
    4296               0 :   result = GetSelection(getter_AddRefs(selection));
    4297               0 :   NS_ENSURE_SUCCESS(result, result);
    4298               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    4299               0 :   return selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
    4300                 : }
    4301                 : 
    4302                 : 
    4303                 : /* Non-interface, protected methods */
    4304                 : 
    4305                 : nsresult
    4306               0 : nsEditor::GetIMEBufferLength(PRInt32* length)
    4307                 : {
    4308               0 :   *length = mIMEBufferLength;
    4309               0 :   return NS_OK;
    4310                 : }
    4311                 : 
    4312                 : void
    4313               0 : nsEditor::SetIsIMEComposing(){  
    4314                 :   // We set mIsIMEComposing according to mIMETextRangeList.
    4315               0 :   nsCOMPtr<nsIPrivateTextRange> rangePtr;
    4316                 :   PRUint16 listlen, type;
    4317                 : 
    4318               0 :   mIsIMEComposing = false;
    4319               0 :   listlen = mIMETextRangeList->GetLength();
    4320                 : 
    4321               0 :   for (PRUint16 i = 0; i < listlen; i++)
    4322                 :   {
    4323               0 :       rangePtr = mIMETextRangeList->Item(i);
    4324               0 :       if (!rangePtr) continue;
    4325               0 :       nsresult result = rangePtr->GetRangeType(&type);
    4326               0 :       if (NS_FAILED(result)) continue;
    4327               0 :       if ( type == nsIPrivateTextRange::TEXTRANGE_RAWINPUT ||
    4328                 :            type == nsIPrivateTextRange::TEXTRANGE_CONVERTEDTEXT ||
    4329                 :            type == nsIPrivateTextRange::TEXTRANGE_SELECTEDRAWTEXT ||
    4330                 :            type == nsIPrivateTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT )
    4331                 :       {
    4332               0 :         mIsIMEComposing = true;
    4333                 : #ifdef DEBUG_IME
    4334                 :         printf("nsEditor::mIsIMEComposing = true\n");
    4335                 : #endif
    4336               0 :         break;
    4337                 :       }
    4338                 :   }
    4339                 :   return;
    4340                 : }
    4341                 : 
    4342                 : bool
    4343               0 : nsEditor::IsIMEComposing() {
    4344               0 :   return mIsIMEComposing;
    4345                 : }
    4346                 : 
    4347                 : NS_IMETHODIMP
    4348               0 : nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
    4349                 : {
    4350               0 :   nsresult result=NS_ERROR_NOT_INITIALIZED;
    4351               0 :   nsCOMPtr<nsISelection> selection;
    4352               0 :   result = GetSelection(getter_AddRefs(selection));
    4353               0 :   NS_ENSURE_SUCCESS(result, result);
    4354               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    4355                 : 
    4356                 :   bool collapsed;
    4357               0 :   result = selection->GetIsCollapsed(&collapsed);
    4358               0 :   if (NS_SUCCEEDED(result) && !collapsed) 
    4359                 :   {
    4360               0 :     result = DeleteSelection(nsIEditor::eNone);
    4361               0 :     if (NS_FAILED(result)) {
    4362               0 :       return result;
    4363                 :     }
    4364                 :     // get the new selection
    4365               0 :     result = GetSelection(getter_AddRefs(selection));
    4366               0 :     if (NS_FAILED(result)) {
    4367               0 :       return result;
    4368                 :     }
    4369                 : 
    4370               0 :     nsCOMPtr<nsIDOMNode> selectedNode;
    4371               0 :     selection->GetAnchorNode(getter_AddRefs(selectedNode));
    4372                 :     // no selection is ok.
    4373                 :     // if there is a selection, it must be collapsed
    4374               0 :     if (selectedNode)
    4375                 :     {
    4376               0 :       bool testCollapsed = false;
    4377               0 :       selection->GetIsCollapsed(&testCollapsed);
    4378               0 :       if (!testCollapsed) {
    4379               0 :         result = selection->CollapseToEnd();
    4380               0 :         NS_ENSURE_SUCCESS(result, result);
    4381                 :       }
    4382                 :     }
    4383                 :   }
    4384                 :   // split the selected node
    4385                 :   PRInt32 offsetOfSelectedNode;
    4386               0 :   result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
    4387               0 :   if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
    4388                 :   {
    4389               0 :     nsCOMPtr<nsIDOMNode> selectedNode;
    4390               0 :     PRUint32 selectedNodeContentCount=0;
    4391               0 :     nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
    4392               0 :     selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
    4393                 : 
    4394               0 :     offsetOfNewNode = offsetOfSelectedNode;
    4395                 :     
    4396                 :     /* if the selection is a text node, split the text node if necessary
    4397                 :        and compute where to put the new node
    4398                 :     */
    4399               0 :     if (selectedParentNodeAsText) 
    4400                 :     { 
    4401                 :       PRInt32 indexOfTextNodeInParent;
    4402               0 :       selectedNode = do_QueryInterface(parentSelectedNode);
    4403               0 :       selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
    4404               0 :       selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
    4405               0 :       GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
    4406                 : 
    4407               0 :       if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
    4408                 :       {
    4409               0 :         nsCOMPtr<nsIDOMNode> newSiblingNode;
    4410               0 :         result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
    4411                 :         // now get the node's offset in its parent, and insert the new tag there
    4412               0 :         if (NS_SUCCEEDED(result)) {
    4413               0 :           result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
    4414               0 :         }
    4415                 :       }
    4416                 :       else 
    4417                 :       { // determine where to insert the new node
    4418               0 :         if (0==offsetOfSelectedNode) {
    4419               0 :           offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
    4420                 :         }
    4421                 :         else {                 // insert new node as last child
    4422               0 :           GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
    4423               0 :           offsetOfNewNode++;    // offsets are 0-based, and we need the index of the new node
    4424                 :         }
    4425                 :       }
    4426                 :     }
    4427                 :     // Here's where the new node was inserted
    4428                 :   }
    4429                 : #ifdef DEBUG
    4430                 :   else {
    4431               0 :     printf("InsertLineBreak into an empty document is not yet supported\n");
    4432                 :   }
    4433                 : #endif
    4434               0 :   return result;
    4435                 : }
    4436                 : 
    4437                 : 
    4438                 : 
    4439                 : NS_IMETHODIMP 
    4440               0 : nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
    4441                 : {
    4442               0 :   nsresult rv = NS_OK;
    4443                 :   
    4444                 :   bool    isTransientTransaction;
    4445               0 :   rv = aTxn->GetIsTransient(&isTransientTransaction);
    4446               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4447                 :   
    4448               0 :   if (!isTransientTransaction)
    4449                 :   {
    4450                 :     // we need to deal here with the case where the user saved after some
    4451                 :     // edits, then undid one or more times. Then, the undo count is -ve,
    4452                 :     // but we can't let a do take it back to zero. So we flip it up to
    4453                 :     // a +ve number.
    4454                 :     PRInt32 modCount;
    4455               0 :     GetModificationCount(&modCount);
    4456               0 :     if (modCount < 0)
    4457               0 :       modCount = -modCount;
    4458                 :         
    4459               0 :     rv = IncrementModificationCount(1);    // don't count transient transactions
    4460                 :   }
    4461                 :   
    4462               0 :   return rv;
    4463                 : }
    4464                 : 
    4465                 : 
    4466                 : NS_IMETHODIMP 
    4467               0 : nsEditor::DoAfterUndoTransaction()
    4468                 : {
    4469               0 :   nsresult rv = NS_OK;
    4470                 : 
    4471               0 :   rv = IncrementModificationCount(-1);    // all undoable transactions are non-transient
    4472                 : 
    4473               0 :   return rv;
    4474                 : }
    4475                 : 
    4476                 : NS_IMETHODIMP 
    4477               0 : nsEditor::DoAfterRedoTransaction()
    4478                 : {
    4479               0 :   return IncrementModificationCount(1);    // all redoable transactions are non-transient
    4480                 : }
    4481                 : 
    4482                 : NS_IMETHODIMP 
    4483               0 : nsEditor::CreateTxnForSetAttribute(nsIDOMElement *aElement, 
    4484                 :                                    const nsAString& aAttribute, 
    4485                 :                                    const nsAString& aValue,
    4486                 :                                    ChangeAttributeTxn ** aTxn)
    4487                 : {
    4488               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    4489                 : 
    4490               0 :   nsRefPtr<ChangeAttributeTxn> txn = new ChangeAttributeTxn();
    4491                 : 
    4492               0 :   nsresult rv = txn->Init(this, aElement, aAttribute, aValue, false);
    4493               0 :   if (NS_SUCCEEDED(rv))
    4494                 :   {
    4495               0 :     txn.forget(aTxn);
    4496                 :   }
    4497                 : 
    4498               0 :   return rv;
    4499                 : }
    4500                 : 
    4501                 : 
    4502                 : NS_IMETHODIMP 
    4503               0 : nsEditor::CreateTxnForRemoveAttribute(nsIDOMElement *aElement, 
    4504                 :                                       const nsAString& aAttribute,
    4505                 :                                       ChangeAttributeTxn ** aTxn)
    4506                 : {
    4507               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    4508                 : 
    4509               0 :   nsRefPtr<ChangeAttributeTxn> txn = new ChangeAttributeTxn();
    4510                 : 
    4511               0 :   nsresult rv = txn->Init(this, aElement, aAttribute, EmptyString(), true);
    4512               0 :   if (NS_SUCCEEDED(rv))
    4513                 :   {
    4514               0 :     txn.forget(aTxn);
    4515                 :   }
    4516                 : 
    4517               0 :   return rv;
    4518                 : }
    4519                 : 
    4520                 : 
    4521               0 : NS_IMETHODIMP nsEditor::CreateTxnForCreateElement(const nsAString& aTag,
    4522                 :                                                   nsIDOMNode     *aParent,
    4523                 :                                                   PRInt32         aPosition,
    4524                 :                                                   CreateElementTxn ** aTxn)
    4525                 : {
    4526               0 :   NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
    4527                 : 
    4528               0 :   nsRefPtr<CreateElementTxn> txn = new CreateElementTxn();
    4529                 : 
    4530               0 :   nsresult rv = txn->Init(this, aTag, aParent, aPosition);
    4531               0 :   if (NS_SUCCEEDED(rv))
    4532                 :   {
    4533               0 :     txn.forget(aTxn);
    4534                 :   }
    4535                 : 
    4536               0 :   return rv;
    4537                 : }
    4538                 : 
    4539                 : 
    4540               0 : NS_IMETHODIMP nsEditor::CreateTxnForInsertElement(nsIDOMNode * aNode,
    4541                 :                                                   nsIDOMNode * aParent,
    4542                 :                                                   PRInt32      aPosition,
    4543                 :                                                   InsertElementTxn ** aTxn)
    4544                 : {
    4545               0 :   NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
    4546                 : 
    4547               0 :   nsRefPtr<InsertElementTxn> txn = new InsertElementTxn();
    4548                 : 
    4549               0 :   nsresult rv = txn->Init(aNode, aParent, aPosition, this);
    4550               0 :   if (NS_SUCCEEDED(rv))
    4551                 :   {
    4552               0 :     txn.forget(aTxn);
    4553                 :   }
    4554                 : 
    4555               0 :   return rv;
    4556                 : }
    4557                 : 
    4558               0 : NS_IMETHODIMP nsEditor::CreateTxnForDeleteElement(nsIDOMNode * aElement,
    4559                 :                                              DeleteElementTxn ** aTxn)
    4560                 : {
    4561               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    4562                 : 
    4563               0 :   nsRefPtr<DeleteElementTxn> txn = new DeleteElementTxn();
    4564                 : 
    4565               0 :   nsresult rv = txn->Init(this, aElement, &mRangeUpdater);
    4566               0 :   if (NS_SUCCEEDED(rv))
    4567                 :   {
    4568               0 :     txn.forget(aTxn);
    4569                 :   }
    4570                 : 
    4571               0 :   return rv;
    4572                 : }
    4573                 : 
    4574                 : NS_IMETHODIMP 
    4575               0 : nsEditor::CreateTxnForIMEText(const nsAString& aStringToInsert,
    4576                 :                               IMETextTxn ** aTxn)
    4577                 : {
    4578               0 :   NS_ASSERTION(aTxn, "illegal value- null ptr- aTxn");
    4579                 :      
    4580               0 :   nsRefPtr<IMETextTxn> txn = new IMETextTxn();
    4581                 : 
    4582               0 :   nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, mIMEBufferLength,
    4583               0 :                           mIMETextRangeList, aStringToInsert, this);
    4584               0 :   if (NS_SUCCEEDED(rv))
    4585                 :   {
    4586               0 :     txn.forget(aTxn);
    4587                 :   }
    4588                 : 
    4589               0 :   return rv;
    4590                 : }
    4591                 : 
    4592                 : 
    4593                 : NS_IMETHODIMP 
    4594               0 : nsEditor::CreateTxnForAddStyleSheet(nsCSSStyleSheet* aSheet, AddStyleSheetTxn* *aTxn)
    4595                 : {
    4596               0 :   nsRefPtr<AddStyleSheetTxn> txn = new AddStyleSheetTxn();
    4597                 : 
    4598               0 :   nsresult rv = txn->Init(this, aSheet);
    4599               0 :   if (NS_SUCCEEDED(rv))
    4600                 :   {
    4601               0 :     txn.forget(aTxn);
    4602                 :   }
    4603                 : 
    4604               0 :   return rv;
    4605                 : }
    4606                 : 
    4607                 : 
    4608                 : 
    4609                 : NS_IMETHODIMP 
    4610               0 : nsEditor::CreateTxnForRemoveStyleSheet(nsCSSStyleSheet* aSheet, RemoveStyleSheetTxn* *aTxn)
    4611                 : {
    4612               0 :   nsRefPtr<RemoveStyleSheetTxn> txn = new RemoveStyleSheetTxn();
    4613                 : 
    4614               0 :   nsresult rv = txn->Init(this, aSheet);
    4615               0 :   if (NS_SUCCEEDED(rv))
    4616                 :   {
    4617               0 :     txn.forget(aTxn);
    4618                 :   }
    4619                 : 
    4620               0 :   return rv;
    4621                 : }
    4622                 : 
    4623                 : 
    4624                 : NS_IMETHODIMP
    4625               0 : nsEditor::CreateTxnForDeleteSelection(nsIEditor::EDirection aAction,
    4626                 :                                       EditAggregateTxn ** aTxn,
    4627                 :                                       nsIDOMNode ** aNode,
    4628                 :                                       PRInt32 *aOffset,
    4629                 :                                       PRInt32 *aLength)
    4630                 : {
    4631               0 :   NS_ENSURE_TRUE(aTxn, NS_ERROR_NULL_POINTER);
    4632               0 :   *aTxn = nsnull;
    4633                 : 
    4634               0 :   nsRefPtr<EditAggregateTxn> aggTxn;
    4635               0 :   nsCOMPtr<nsISelectionController> selCon;
    4636               0 :   GetSelectionController(getter_AddRefs(selCon));
    4637               0 :   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
    4638               0 :   nsCOMPtr<nsISelection> selection;
    4639               0 :   nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    4640               0 :                                          getter_AddRefs(selection));
    4641               0 :   if ((NS_SUCCEEDED(result)) && selection)
    4642                 :   {
    4643                 :     // Check whether the selection is collapsed and we should do nothing:
    4644                 :     bool isCollapsed;
    4645               0 :     result = (selection->GetIsCollapsed(&isCollapsed));
    4646               0 :     if (NS_SUCCEEDED(result) && isCollapsed && aAction == eNone)
    4647               0 :       return NS_OK;
    4648                 : 
    4649                 :     // allocate the out-param transaction
    4650               0 :     aggTxn = new EditAggregateTxn();
    4651                 : 
    4652               0 :     nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
    4653               0 :     nsCOMPtr<nsIEnumerator> enumerator;
    4654               0 :     result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
    4655               0 :     if (NS_SUCCEEDED(result) && enumerator)
    4656                 :     {
    4657               0 :       for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
    4658                 :       {
    4659               0 :         nsCOMPtr<nsISupports> currentItem;
    4660               0 :         result = enumerator->CurrentItem(getter_AddRefs(currentItem));
    4661               0 :         if ((NS_SUCCEEDED(result)) && (currentItem))
    4662                 :         {
    4663               0 :           nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    4664               0 :           range->GetCollapsed(&isCollapsed);
    4665               0 :           if (!isCollapsed)
    4666                 :           {
    4667               0 :             nsRefPtr<DeleteRangeTxn> txn = new DeleteRangeTxn();
    4668               0 :             if (txn)
    4669                 :             {
    4670               0 :               txn->Init(this, range, &mRangeUpdater);
    4671               0 :               aggTxn->AppendChild(txn);
    4672                 :             }
    4673                 :             else
    4674               0 :               result = NS_ERROR_OUT_OF_MEMORY;
    4675                 :           }
    4676                 :           // Same with range as with selection; if it is collapsed and action
    4677                 :           // is eNone, do nothing.
    4678               0 :           else if (aAction != eNone)
    4679                 :           { // we have an insertion point.  delete the thing in front of it or behind it, depending on aAction
    4680               0 :             result = CreateTxnForDeleteInsertionPoint(range, aAction, aggTxn, aNode, aOffset, aLength);
    4681                 :           }
    4682                 :         }
    4683                 :       }
    4684                 :     }
    4685                 :   }
    4686                 : 
    4687                 :   // Only set the outparam if building the txn was a success, otherwise
    4688                 :   // we let the aggregation txn be destroyed when the refptr goes out of scope
    4689               0 :   if (NS_SUCCEEDED(result))
    4690                 :   {
    4691               0 :     aggTxn.forget(aTxn);
    4692                 :   }
    4693                 : 
    4694               0 :   return result;
    4695                 : }
    4696                 : 
    4697                 : nsresult
    4698               0 : nsEditor::CreateTxnForDeleteCharacter(nsIDOMCharacterData  *aData,
    4699                 :                                       PRUint32              aOffset,
    4700                 :                                       nsIEditor::EDirection aDirection,
    4701                 :                                       DeleteTextTxn       **aTxn)
    4702                 : {
    4703               0 :   NS_ASSERTION(aDirection == eNext || aDirection == ePrevious,
    4704                 :                "invalid direction");
    4705               0 :   nsAutoString data;
    4706               0 :   aData->GetData(data);
    4707               0 :   PRUint32 segOffset = aOffset, segLength = 1;
    4708               0 :   if (aDirection == eNext) {
    4709               0 :     if (segOffset + 1 < data.Length() &&
    4710               0 :         NS_IS_HIGH_SURROGATE(data[segOffset]) &&
    4711               0 :         NS_IS_LOW_SURROGATE(data[segOffset+1])) {
    4712                 :       // delete both halves of the surrogate pair
    4713               0 :       ++segLength;
    4714                 :     }
    4715               0 :   } else if (aOffset > 0) {
    4716               0 :     --segOffset;
    4717               0 :     if (segOffset > 0 &&
    4718               0 :       NS_IS_LOW_SURROGATE(data[segOffset]) &&
    4719               0 :       NS_IS_HIGH_SURROGATE(data[segOffset-1])) {
    4720               0 :       ++segLength;
    4721               0 :       --segOffset;
    4722                 :     }
    4723                 :   } else {
    4724               0 :     return NS_ERROR_FAILURE;
    4725                 :   }
    4726               0 :   return CreateTxnForDeleteText(aData, segOffset, segLength, aTxn);
    4727                 : }
    4728                 : 
    4729                 : //XXX: currently, this doesn't handle edge conditions because GetNext/GetPrior are not implemented
    4730                 : NS_IMETHODIMP
    4731               0 : nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange          *aRange, 
    4732                 :                                            nsIEditor::EDirection aAction,
    4733                 :                                            EditAggregateTxn     *aTxn,
    4734                 :                                            nsIDOMNode          **aNode,
    4735                 :                                            PRInt32              *aOffset,
    4736                 :                                            PRInt32              *aLength)
    4737                 : {
    4738               0 :   NS_ASSERTION(aAction != eNone, "invalid action");
    4739                 : 
    4740                 :   // get the node and offset of the insertion point
    4741               0 :   nsCOMPtr<nsIDOMNode> node;
    4742               0 :   nsresult result = aRange->GetStartContainer(getter_AddRefs(node));
    4743               0 :   NS_ENSURE_SUCCESS(result, result);
    4744                 : 
    4745                 :   PRInt32 offset;
    4746               0 :   result = aRange->GetStartOffset(&offset);
    4747               0 :   NS_ENSURE_SUCCESS(result, result);
    4748                 : 
    4749                 :   // determine if the insertion point is at the beginning, middle, or end of the node
    4750               0 :   nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(node);
    4751                 : 
    4752               0 :   PRUint32 count=0;
    4753                 : 
    4754               0 :   if (nodeAsText)
    4755               0 :     nodeAsText->GetLength(&count);
    4756                 :   else
    4757                 :   { 
    4758                 :     // get the child list and count
    4759               0 :     nsCOMPtr<nsIDOMNodeList>childList;
    4760               0 :     result = node->GetChildNodes(getter_AddRefs(childList));
    4761               0 :     if ((NS_SUCCEEDED(result)) && childList)
    4762               0 :       childList->GetLength(&count);
    4763                 :   }
    4764                 : 
    4765               0 :   bool isFirst = (0 == offset);
    4766               0 :   bool isLast  = (count == (PRUint32)offset);
    4767                 : 
    4768                 :   // XXX: if isFirst && isLast, then we'll need to delete the node 
    4769                 :   //      as well as the 1 child
    4770                 : 
    4771                 :   // build a transaction for deleting the appropriate data
    4772                 :   // XXX: this has to come from rule section
    4773               0 :   if ((ePrevious==aAction) && (true==isFirst))
    4774                 :   { // we're backspacing from the beginning of the node.  Delete the first thing to our left
    4775               0 :     nsCOMPtr<nsIDOMNode> priorNode;
    4776               0 :     result = GetPriorNode(node, true, address_of(priorNode));
    4777               0 :     if ((NS_SUCCEEDED(result)) && priorNode)
    4778                 :     { // there is a priorNode, so delete its last child (if text content, delete the last char.)
    4779                 :       // if it has no children, delete it
    4780               0 :       nsCOMPtr<nsIDOMCharacterData> priorNodeAsText = do_QueryInterface(priorNode);
    4781               0 :       if (priorNodeAsText)
    4782                 :       {
    4783               0 :         PRUint32 length=0;
    4784               0 :         priorNodeAsText->GetLength(&length);
    4785               0 :         if (0<length)
    4786                 :         {
    4787               0 :           nsRefPtr<DeleteTextTxn> txn;
    4788                 :           result = CreateTxnForDeleteCharacter(priorNodeAsText, length,
    4789               0 :                                                ePrevious, getter_AddRefs(txn));
    4790               0 :           if (NS_SUCCEEDED(result)) {
    4791               0 :             aTxn->AppendChild(txn);
    4792               0 :             NS_ADDREF(*aNode = priorNode);
    4793               0 :             *aOffset = txn->GetOffset();
    4794               0 :             *aLength = txn->GetNumCharsToDelete();
    4795                 :           }
    4796                 :         }
    4797                 :         else
    4798                 :         { // XXX: can you have an empty text node?  If so, what do you do?
    4799               0 :           printf("ERROR: found a text node with 0 characters\n");
    4800               0 :           result = NS_ERROR_UNEXPECTED;
    4801                 :         }
    4802                 :       }
    4803                 :       else
    4804                 :       { // priorNode is not text, so tell it's parent to delete it
    4805               0 :         nsRefPtr<DeleteElementTxn> txn;
    4806               0 :         result = CreateTxnForDeleteElement(priorNode, getter_AddRefs(txn));
    4807               0 :         if (NS_SUCCEEDED(result)) {
    4808               0 :           aTxn->AppendChild(txn);
    4809               0 :           NS_ADDREF(*aNode = priorNode);
    4810                 :         }
    4811                 :       }
    4812               0 :     }
    4813                 :   }
    4814               0 :   else if ((nsIEditor::eNext==aAction) && (true==isLast))
    4815                 :   { // we're deleting from the end of the node.  Delete the first thing to our right
    4816               0 :     nsCOMPtr<nsIDOMNode> nextNode;
    4817               0 :     result = GetNextNode(node, true, address_of(nextNode));
    4818               0 :     if ((NS_SUCCEEDED(result)) && nextNode)
    4819                 :     { // there is a nextNode, so delete it's first child (if text content, delete the first char.)
    4820                 :       // if it has no children, delete it
    4821               0 :       nsCOMPtr<nsIDOMCharacterData> nextNodeAsText = do_QueryInterface(nextNode);
    4822               0 :       if (nextNodeAsText)
    4823                 :       {
    4824               0 :         PRUint32 length=0;
    4825               0 :         nextNodeAsText->GetLength(&length);
    4826               0 :         if (0<length)
    4827                 :         {
    4828               0 :           nsRefPtr<DeleteTextTxn> txn;
    4829                 :           result = CreateTxnForDeleteCharacter(nextNodeAsText, 0, eNext,
    4830               0 :                                                getter_AddRefs(txn));
    4831               0 :           if (NS_SUCCEEDED(result)) {
    4832               0 :             aTxn->AppendChild(txn);
    4833               0 :             NS_ADDREF(*aNode = nextNode);
    4834               0 :             *aOffset = txn->GetOffset();
    4835               0 :             *aLength = txn->GetNumCharsToDelete();
    4836                 :           }
    4837                 :         }
    4838                 :         else
    4839                 :         { // XXX: can you have an empty text node?  If so, what do you do?
    4840               0 :           printf("ERROR: found a text node with 0 characters\n");
    4841               0 :           result = NS_ERROR_UNEXPECTED;
    4842                 :         }
    4843                 :       }
    4844                 :       else
    4845                 :       { // nextNode is not text, so tell its parent to delete it
    4846               0 :         nsRefPtr<DeleteElementTxn> txn;
    4847               0 :         result = CreateTxnForDeleteElement(nextNode, getter_AddRefs(txn));
    4848               0 :         if (NS_SUCCEEDED(result)) {
    4849               0 :           aTxn->AppendChild(txn);
    4850               0 :           NS_ADDREF(*aNode = nextNode);
    4851                 :         }
    4852                 :       }
    4853               0 :     }
    4854                 :   }
    4855                 :   else
    4856                 :   {
    4857               0 :     if (nodeAsText)
    4858                 :     { // we have text, so delete a char at the proper offset
    4859               0 :       nsRefPtr<DeleteTextTxn> txn;
    4860                 :       result = CreateTxnForDeleteCharacter(nodeAsText, offset, aAction,
    4861               0 :                                            getter_AddRefs(txn));
    4862               0 :       if (NS_SUCCEEDED(result)) {
    4863               0 :         aTxn->AppendChild(txn);
    4864               0 :         NS_ADDREF(*aNode = node);
    4865               0 :         *aOffset = txn->GetOffset();
    4866               0 :         *aLength = txn->GetNumCharsToDelete();
    4867                 :       }
    4868                 :     }
    4869                 :     else
    4870                 :     { // we're either deleting a node or some text, need to dig into the next/prev node to find out
    4871               0 :       nsCOMPtr<nsIDOMNode> selectedNode;
    4872               0 :       if (ePrevious==aAction)
    4873                 :       {
    4874               0 :         result = GetPriorNode(node, offset, true, address_of(selectedNode));
    4875                 :       }
    4876               0 :       else if (eNext==aAction)
    4877                 :       {
    4878               0 :         result = GetNextNode(node, offset, true, address_of(selectedNode));
    4879                 :       }
    4880               0 :       if (NS_FAILED(result)) { return result; }
    4881               0 :       if (selectedNode) 
    4882                 :       {
    4883                 :         nsCOMPtr<nsIDOMCharacterData> selectedNodeAsText =
    4884               0 :                                              do_QueryInterface(selectedNode);
    4885               0 :         if (selectedNodeAsText)
    4886                 :         { // we are deleting from a text node, so do a text deletion
    4887               0 :           PRUint32 position = 0;    // default for forward delete
    4888               0 :           if (ePrevious==aAction)
    4889                 :           {
    4890               0 :             selectedNodeAsText->GetLength(&position);
    4891                 :           }
    4892               0 :           nsRefPtr<DeleteTextTxn> delTextTxn;
    4893                 :           result = CreateTxnForDeleteCharacter(selectedNodeAsText, position,
    4894                 :                                                aAction,
    4895               0 :                                                getter_AddRefs(delTextTxn));
    4896               0 :           if (NS_FAILED(result))  { return result; }
    4897               0 :           if (!delTextTxn) { return NS_ERROR_NULL_POINTER; }
    4898               0 :           aTxn->AppendChild(delTextTxn);
    4899               0 :           NS_ADDREF(*aNode = selectedNode);
    4900               0 :           *aOffset = delTextTxn->GetOffset();
    4901               0 :           *aLength = delTextTxn->GetNumCharsToDelete();
    4902                 :         }
    4903                 :         else
    4904                 :         {
    4905               0 :           nsRefPtr<DeleteElementTxn> delElementTxn;
    4906                 :           result = CreateTxnForDeleteElement(selectedNode,
    4907               0 :                                              getter_AddRefs(delElementTxn));
    4908               0 :           if (NS_FAILED(result))  { return result; }
    4909               0 :           if (!delElementTxn) { return NS_ERROR_NULL_POINTER; }
    4910               0 :           aTxn->AppendChild(delElementTxn);
    4911               0 :           NS_ADDREF(*aNode = selectedNode);
    4912                 :         }
    4913                 :       }
    4914                 :     }
    4915                 :   }
    4916               0 :   return result;
    4917                 : }
    4918                 : 
    4919                 : nsresult 
    4920               0 : nsEditor::CreateRange(nsIDOMNode *aStartParent, PRInt32 aStartOffset,
    4921                 :                       nsIDOMNode *aEndParent, PRInt32 aEndOffset,
    4922                 :                       nsIDOMRange **aRange)
    4923                 : {
    4924                 :   return nsRange::CreateRange(aStartParent, aStartOffset, aEndParent,
    4925               0 :                               aEndOffset, aRange);
    4926                 : }
    4927                 : 
    4928                 : nsresult 
    4929               0 : nsEditor::AppendNodeToSelectionAsRange(nsIDOMNode *aNode)
    4930                 : {
    4931               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    4932               0 :   nsCOMPtr<nsISelection> selection;
    4933               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    4934               0 :   NS_ENSURE_SUCCESS(res, res);
    4935               0 :   if(!selection) return NS_ERROR_FAILURE;
    4936                 : 
    4937               0 :   nsCOMPtr<nsIDOMNode> parentNode;
    4938               0 :   res = aNode->GetParentNode(getter_AddRefs(parentNode));
    4939               0 :   NS_ENSURE_SUCCESS(res, res);
    4940               0 :   NS_ENSURE_TRUE(parentNode, NS_ERROR_NULL_POINTER);
    4941                 :   
    4942                 :   PRInt32 offset;
    4943               0 :   res = GetChildOffset(aNode, parentNode, offset);
    4944               0 :   NS_ENSURE_SUCCESS(res, res);
    4945                 :   
    4946               0 :   nsCOMPtr<nsIDOMRange> range;
    4947               0 :   res = CreateRange(parentNode, offset, parentNode, offset+1, getter_AddRefs(range));
    4948               0 :   NS_ENSURE_SUCCESS(res, res);
    4949               0 :   NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
    4950                 : 
    4951               0 :   return selection->AddRange(range);
    4952                 : }
    4953                 : 
    4954               0 : nsresult nsEditor::ClearSelection()
    4955                 : {
    4956               0 :   nsCOMPtr<nsISelection> selection;
    4957               0 :   nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
    4958               0 :   NS_ENSURE_SUCCESS(res, res);
    4959               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    4960               0 :   return selection->RemoveAllRanges();  
    4961                 : }
    4962                 : 
    4963                 : nsresult
    4964               0 : nsEditor::CreateHTMLContent(const nsAString& aTag, nsIContent** aContent)
    4965                 : {
    4966               0 :   nsCOMPtr<nsIDOMDocument> tempDoc;
    4967               0 :   GetDocument(getter_AddRefs(tempDoc));
    4968                 : 
    4969               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(tempDoc);
    4970               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    4971                 : 
    4972                 :   // XXX Wallpaper over editor bug (editor tries to create elements with an
    4973                 :   //     empty nodename).
    4974               0 :   if (aTag.IsEmpty()) {
    4975                 :     NS_ERROR("Don't pass an empty tag to nsEditor::CreateHTMLContent, "
    4976               0 :              "check caller.");
    4977               0 :     return NS_ERROR_FAILURE;
    4978                 :   }
    4979                 : 
    4980               0 :   return doc->CreateElem(aTag, nsnull, kNameSpaceID_XHTML, aContent);
    4981                 : }
    4982                 : 
    4983                 : nsresult
    4984               0 : nsEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
    4985                 :                                    const nsAString & aAttribute,
    4986                 :                                    const nsAString & aValue,
    4987                 :                                    bool aSuppressTransaction)
    4988                 : {
    4989               0 :   return SetAttribute(aElement, aAttribute, aValue);
    4990                 : }
    4991                 : 
    4992                 : nsresult
    4993               0 : nsEditor::RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
    4994                 :                                       const nsAString & aAttribute,
    4995                 :                                       bool aSuppressTransaction)
    4996                 : {
    4997               0 :   return RemoveAttribute(aElement, aAttribute);
    4998                 : }
    4999                 : 
    5000                 : nsresult
    5001               0 : nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
    5002                 : {
    5003                 :   // NOTE: When you change this method, you should also change:
    5004                 :   //   * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
    5005                 :   //   * editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
    5006                 :   //
    5007                 :   // And also when you add new key handling, you need to change the subclass's
    5008                 :   // HandleKeyPressEvent()'s switch statement.
    5009                 : 
    5010               0 :   nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
    5011               0 :   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
    5012               0 :   NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
    5013                 :                "HandleKeyPressEvent gets non-keypress event");
    5014                 : 
    5015                 :   // if we are readonly or disabled, then do nothing.
    5016               0 :   if (IsReadonly() || IsDisabled()) {
    5017                 :     // consume backspace for disabled and readonly textfields, to prevent
    5018                 :     // back in history, which could be confusing to users
    5019               0 :     if (nativeKeyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE) {
    5020               0 :       aKeyEvent->PreventDefault();
    5021                 :     }
    5022               0 :     return NS_OK;
    5023                 :   }
    5024                 : 
    5025               0 :   switch (nativeKeyEvent->keyCode) {
    5026                 :     case nsIDOMKeyEvent::DOM_VK_META:
    5027                 :     case nsIDOMKeyEvent::DOM_VK_SHIFT:
    5028                 :     case nsIDOMKeyEvent::DOM_VK_CONTROL:
    5029                 :     case nsIDOMKeyEvent::DOM_VK_ALT:
    5030               0 :       aKeyEvent->PreventDefault(); // consumed
    5031               0 :       return NS_OK;
    5032                 :     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
    5033               0 :       if (nativeKeyEvent->isControl || nativeKeyEvent->isAlt ||
    5034                 :           nativeKeyEvent->isMeta) {
    5035               0 :         return NS_OK;
    5036                 :       }
    5037               0 :       DeleteSelection(nsIEditor::ePrevious);
    5038               0 :       aKeyEvent->PreventDefault(); // consumed
    5039               0 :       return NS_OK;
    5040                 :     case nsIDOMKeyEvent::DOM_VK_DELETE:
    5041                 :       // on certain platforms (such as windows) the shift key
    5042                 :       // modifies what delete does (cmd_cut in this case).
    5043                 :       // bailing here to allow the keybindings to do the cut.
    5044               0 :       if (nativeKeyEvent->isShift || nativeKeyEvent->isControl ||
    5045                 :           nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
    5046               0 :         return NS_OK;
    5047                 :       }
    5048               0 :       DeleteSelection(nsIEditor::eNext);
    5049               0 :       aKeyEvent->PreventDefault(); // consumed
    5050               0 :       return NS_OK; 
    5051                 :   }
    5052               0 :   return NS_OK;
    5053                 : }
    5054                 : 
    5055                 : nsresult
    5056               0 : nsEditor::HandleInlineSpellCheck(PRInt32 action,
    5057                 :                                    nsISelection *aSelection,
    5058                 :                                    nsIDOMNode *previousSelectedNode,
    5059                 :                                    PRInt32 previousSelectedOffset,
    5060                 :                                    nsIDOMNode *aStartNode,
    5061                 :                                    PRInt32 aStartOffset,
    5062                 :                                    nsIDOMNode *aEndNode,
    5063                 :                                    PRInt32 aEndOffset)
    5064                 : {
    5065               0 :   return mInlineSpellChecker ? mInlineSpellChecker->SpellCheckAfterEditorChange(action,
    5066                 :                                                        aSelection,
    5067                 :                                                        previousSelectedNode,
    5068                 :                                                        previousSelectedOffset,
    5069                 :                                                        aStartNode,
    5070                 :                                                        aStartOffset,
    5071                 :                                                        aEndNode,
    5072               0 :                                                        aEndOffset) : NS_OK;
    5073                 : }
    5074                 : 
    5075                 : already_AddRefed<nsIContent>
    5076               0 : nsEditor::FindSelectionRoot(nsINode *aNode)
    5077                 : {
    5078               0 :   nsCOMPtr<nsIContent> rootContent = GetRoot();
    5079               0 :   return rootContent.forget();
    5080                 : }
    5081                 : 
    5082                 : nsresult
    5083               0 : nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
    5084                 : {
    5085               0 :   nsCOMPtr<nsINode> targetNode = do_QueryInterface(aFocusEventTarget);
    5086               0 :   NS_ENSURE_TRUE(targetNode, NS_ERROR_INVALID_ARG);
    5087               0 :   nsCOMPtr<nsIContent> selectionRootContent = FindSelectionRoot(targetNode);
    5088               0 :   if (!selectionRootContent) {
    5089               0 :     return NS_OK;
    5090                 :   }
    5091                 : 
    5092                 :   bool isTargetDoc =
    5093               0 :     targetNode->NodeType() == nsIDOMNode::DOCUMENT_NODE &&
    5094               0 :     targetNode->HasFlag(NODE_IS_EDITABLE);
    5095                 : 
    5096               0 :   nsCOMPtr<nsISelection> selection;
    5097               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
    5098               0 :   NS_ENSURE_SUCCESS(rv, rv);
    5099                 : 
    5100               0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
    5101               0 :   NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED);
    5102                 : 
    5103               0 :   nsCOMPtr<nsISelectionController> selCon;
    5104               0 :   rv = GetSelectionController(getter_AddRefs(selCon));
    5105               0 :   NS_ENSURE_SUCCESS(rv, rv);
    5106                 : 
    5107                 :   nsCOMPtr<nsISelectionPrivate> selectionPrivate =
    5108               0 :     do_QueryInterface(selection);
    5109               0 :   NS_ENSURE_TRUE(selectionPrivate, NS_ERROR_UNEXPECTED);
    5110                 : 
    5111                 :   // Init the caret
    5112               0 :   nsRefPtr<nsCaret> caret = presShell->GetCaret();
    5113               0 :   NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED);
    5114               0 :   caret->SetIgnoreUserModify(false);
    5115               0 :   caret->SetCaretDOMSelection(selection);
    5116               0 :   selCon->SetCaretReadOnly(IsReadonly());
    5117               0 :   selCon->SetCaretEnabled(true);
    5118                 : 
    5119                 :   // Init selection
    5120               0 :   selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
    5121               0 :   selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);
    5122               0 :   selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
    5123                 :   // If the computed selection root isn't root content, we should set it
    5124                 :   // as selection ancestor limit.  However, if that is root element, it means
    5125                 :   // there is not limitation of the selection, then, we must set NULL.
    5126                 :   // NOTE: If we set a root element to the ancestor limit, some selection
    5127                 :   // methods don't work fine.
    5128               0 :   if (selectionRootContent->GetParent()) {
    5129               0 :     selectionPrivate->SetAncestorLimiter(selectionRootContent);
    5130                 :   } else {
    5131               0 :     selectionPrivate->SetAncestorLimiter(nsnull);
    5132                 :   }
    5133                 : 
    5134                 :   // XXX What case needs this?
    5135               0 :   if (isTargetDoc) {
    5136                 :     PRInt32 rangeCount;
    5137               0 :     selection->GetRangeCount(&rangeCount);
    5138               0 :     if (rangeCount == 0) {
    5139               0 :       BeginningOfDocument();
    5140                 :     }
    5141                 :   }
    5142                 : 
    5143               0 :   return NS_OK;
    5144                 : }
    5145                 : 
    5146                 : dom::Element *
    5147               0 : nsEditor::GetRoot()
    5148                 : {
    5149               0 :   if (!mRootElement)
    5150                 :   {
    5151               0 :     nsCOMPtr<nsIDOMElement> root;
    5152                 : 
    5153                 :     // Let GetRootElement() do the work
    5154               0 :     GetRootElement(getter_AddRefs(root));
    5155                 :   }
    5156                 : 
    5157               0 :   return mRootElement;
    5158                 : }
    5159                 : 
    5160                 : nsresult
    5161               0 : nsEditor::DetermineCurrentDirection()
    5162                 : {
    5163                 :   // Get the current root direction from its frame
    5164               0 :   dom::Element *rootElement = GetRoot();
    5165                 : 
    5166                 :   // If we don't have an explicit direction, determine our direction
    5167                 :   // from the content's direction
    5168               0 :   if (!(mFlags & (nsIPlaintextEditor::eEditorLeftToRight |
    5169               0 :                   nsIPlaintextEditor::eEditorRightToLeft))) {
    5170                 : 
    5171               0 :     nsIFrame* frame = rootElement->GetPrimaryFrame();
    5172               0 :     NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
    5173                 : 
    5174                 :     // Set the flag here, to enable us to use the same code path below.
    5175                 :     // It will be flipped before returning from the function.
    5176               0 :     if (frame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
    5177               0 :       mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
    5178                 :     } else {
    5179               0 :       mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
    5180                 :     }
    5181                 :   }
    5182                 : 
    5183               0 :   return NS_OK;
    5184                 : }
    5185                 : 
    5186                 : NS_IMETHODIMP
    5187               0 : nsEditor::SwitchTextDirection()
    5188                 : {
    5189                 :   // Get the current root direction from its frame
    5190               0 :   dom::Element *rootElement = GetRoot();
    5191               0 :   nsresult rv = DetermineCurrentDirection();
    5192               0 :   NS_ENSURE_SUCCESS(rv, rv);
    5193                 : 
    5194                 :   // Apply the opposite direction
    5195               0 :   if (mFlags & nsIPlaintextEditor::eEditorRightToLeft) {
    5196               0 :     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
    5197                 :                  "Unexpected mutually exclusive flag");
    5198               0 :     mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
    5199               0 :     mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
    5200               0 :     rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
    5201               0 :   } else if (mFlags & nsIPlaintextEditor::eEditorLeftToRight) {
    5202               0 :     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
    5203                 :                  "Unexpected mutually exclusive flag");
    5204               0 :     mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
    5205               0 :     mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
    5206               0 :     rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), true);
    5207                 :   }
    5208                 : 
    5209               0 :   return rv;
    5210                 : }
    5211                 : 
    5212                 : void
    5213               0 : nsEditor::SwitchTextDirectionTo(PRUint32 aDirection)
    5214                 : {
    5215                 :   // Get the current root direction from its frame
    5216               0 :   dom::Element *rootElement = GetRoot();
    5217               0 :   nsresult rv = DetermineCurrentDirection();
    5218               0 :   NS_ENSURE_SUCCESS(rv, );
    5219                 : 
    5220                 :   // Apply the requested direction
    5221               0 :   if (aDirection == nsIPlaintextEditor::eEditorLeftToRight &&
    5222                 :       (mFlags & nsIPlaintextEditor::eEditorRightToLeft)) {
    5223               0 :     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
    5224                 :                  "Unexpected mutually exclusive flag");
    5225               0 :     mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
    5226               0 :     mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
    5227               0 :     rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
    5228               0 :   } else if (aDirection == nsIPlaintextEditor::eEditorRightToLeft &&
    5229                 :              (mFlags & nsIPlaintextEditor::eEditorLeftToRight)) {
    5230               0 :     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
    5231                 :                  "Unexpected mutually exclusive flag");
    5232               0 :     mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
    5233               0 :     mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
    5234               0 :     rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), true);
    5235                 :   }
    5236                 : }
    5237                 : 
    5238                 : #if DEBUG_JOE
    5239                 : void
    5240                 : nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
    5241                 : {
    5242                 :   PRInt32 i;
    5243                 :   for (i=0; i<indent; i++)
    5244                 :     printf("  ");
    5245                 :   
    5246                 :   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
    5247                 :   nsCOMPtr<nsIDOMDocumentFragment> docfrag = do_QueryInterface(aNode);
    5248                 :   
    5249                 :   if (element || docfrag)
    5250                 :   { 
    5251                 :     if (element)
    5252                 :     {
    5253                 :       nsAutoString tag;
    5254                 :       element->GetTagName(tag);
    5255                 :       printf("<%s>\n", NS_LossyConvertUTF16toASCII(tag).get());
    5256                 :     }
    5257                 :     else
    5258                 :     {
    5259                 :       printf("<document fragment>\n");
    5260                 :     }
    5261                 :     nsCOMPtr<nsIDOMNodeList> childList;
    5262                 :     aNode->GetChildNodes(getter_AddRefs(childList));
    5263                 :     NS_ENSURE_TRUE(childList, NS_ERROR_NULL_POINTER);
    5264                 :     PRUint32 numChildren;
    5265                 :     childList->GetLength(&numChildren);
    5266                 :     nsCOMPtr<nsIDOMNode> child, tmp;
    5267                 :     aNode->GetFirstChild(getter_AddRefs(child));
    5268                 :     for (i=0; i<numChildren; i++)
    5269                 :     {
    5270                 :       DumpNode(child, indent+1);
    5271                 :       child->GetNextSibling(getter_AddRefs(tmp));
    5272                 :       child = tmp;
    5273                 :     }
    5274                 :   }
    5275                 :   else if (IsTextNode(aNode))
    5276                 :   {
    5277                 :     nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aNode);
    5278                 :     nsAutoString str;
    5279                 :     textNode->GetData(str);
    5280                 :     nsCAutoString cstr;
    5281                 :     LossyCopyUTF16toASCII(str, cstr);
    5282                 :     cstr.ReplaceChar('\n', ' ');
    5283                 :     printf("<textnode> %s\n", cstr.get());
    5284                 :   }
    5285                 : }
    5286                 : #endif
    5287                 : 
    5288                 : bool
    5289               0 : nsEditor::IsModifiableNode(nsIDOMNode *aNode)
    5290                 : {
    5291               0 :   return true;
    5292                 : }
    5293                 : 
    5294                 : bool
    5295               0 : nsEditor::IsModifiableNode(nsINode *aNode)
    5296                 : {
    5297               0 :   return true;
    5298                 : }
    5299                 : 
    5300                 : nsKeyEvent*
    5301               0 : nsEditor::GetNativeKeyEvent(nsIDOMKeyEvent* aDOMKeyEvent)
    5302                 : {
    5303               0 :   nsCOMPtr<nsIPrivateDOMEvent> privDOMEvent = do_QueryInterface(aDOMKeyEvent);
    5304               0 :   NS_ENSURE_TRUE(privDOMEvent, nsnull);
    5305               0 :   nsEvent* nativeEvent = privDOMEvent->GetInternalNSEvent();
    5306               0 :   NS_ENSURE_TRUE(nativeEvent, nsnull);
    5307               0 :   NS_ENSURE_TRUE(nativeEvent->eventStructType == NS_KEY_EVENT, nsnull);
    5308               0 :   return static_cast<nsKeyEvent*>(nativeEvent);
    5309                 : }
    5310                 : 
    5311                 : already_AddRefed<nsIContent>
    5312               0 : nsEditor::GetFocusedContent()
    5313                 : {
    5314               0 :   nsCOMPtr<nsIDOMEventTarget> piTarget = GetDOMEventTarget();
    5315               0 :   if (!piTarget) {
    5316               0 :     return nsnull;
    5317                 :   }
    5318                 : 
    5319               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5320               0 :   NS_ENSURE_TRUE(fm, nsnull);
    5321                 : 
    5322               0 :   nsCOMPtr<nsIContent> content = fm->GetFocusedContent();
    5323               0 :   return SameCOMIdentity(content, piTarget) ? content.forget() : nsnull;
    5324                 : }
    5325                 : 
    5326                 : bool
    5327               0 : nsEditor::IsActiveInDOMWindow()
    5328                 : {
    5329               0 :   nsCOMPtr<nsIDOMEventTarget> piTarget = GetDOMEventTarget();
    5330               0 :   if (!piTarget) {
    5331               0 :     return false;
    5332                 :   }
    5333                 : 
    5334               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5335               0 :   NS_ENSURE_TRUE(fm, false);
    5336                 : 
    5337               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5338               0 :   nsPIDOMWindow* ourWindow = doc->GetWindow();
    5339               0 :   nsCOMPtr<nsPIDOMWindow> win;
    5340                 :   nsIContent* content =
    5341                 :     nsFocusManager::GetFocusedDescendant(ourWindow, false,
    5342               0 :                                          getter_AddRefs(win));
    5343               0 :   return SameCOMIdentity(content, piTarget);
    5344                 : }
    5345                 : 
    5346                 : bool
    5347               0 : nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
    5348                 : {
    5349                 :   // If the event is trusted, the event should always cause input.
    5350               0 :   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aEvent);
    5351               0 :   NS_ENSURE_TRUE(NSEvent, false);
    5352                 : 
    5353                 :   // If this is mouse event but this editor doesn't have focus, we shouldn't
    5354                 :   // handle it.
    5355               0 :   nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
    5356               0 :   if (mouseEvent) {
    5357               0 :     nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
    5358               0 :     if (!focusedContent) {
    5359               0 :       return false;
    5360                 :     }
    5361                 :   }
    5362                 : 
    5363                 :   bool isTrusted;
    5364               0 :   nsresult rv = NSEvent->GetIsTrusted(&isTrusted);
    5365               0 :   NS_ENSURE_SUCCESS(rv, false);
    5366               0 :   if (isTrusted) {
    5367               0 :     return true;
    5368                 :   }
    5369                 : 
    5370                 :   // Ignore untrusted mouse event.
    5371                 :   // XXX Why are we handling other untrusted input events?
    5372               0 :   if (mouseEvent) {
    5373               0 :     return false;
    5374                 :   }
    5375                 : 
    5376                 :   // Otherwise, we shouldn't handle any input events when we're not an active
    5377                 :   // element of the DOM window.
    5378               0 :   return IsActiveInDOMWindow();
    5379                 : }
    5380                 : 
    5381                 : NS_IMETHODIMP
    5382               0 : nsEditor::GetLastKeypressEventTrusted(bool *aWasTrusted)
    5383                 : {
    5384               0 :   NS_ENSURE_ARG_POINTER(aWasTrusted);
    5385                 : 
    5386               0 :   if (mLastKeypressEventWasTrusted == eTriUnset) {
    5387               0 :     return NS_ERROR_UNEXPECTED;
    5388                 :   }
    5389                 : 
    5390               0 :   *aWasTrusted = (mLastKeypressEventWasTrusted == eTriTrue);
    5391               0 :   return NS_OK;
    5392                 : }
    5393                 : 
    5394                 : void
    5395               0 : nsEditor::BeginKeypressHandling(nsIDOMNSEvent* aEvent)
    5396                 : {
    5397               0 :   NS_ASSERTION(mLastKeypressEventWasTrusted == eTriUnset, "How come our status is not clear?");
    5398                 : 
    5399               0 :   if (aEvent) {
    5400               0 :     bool isTrusted = false;
    5401               0 :     aEvent->GetIsTrusted(&isTrusted);
    5402               0 :     mLastKeypressEventWasTrusted = isTrusted ? eTriTrue : eTriFalse;
    5403                 :   }
    5404               0 : }
    5405                 : 
    5406                 : void
    5407               0 : nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
    5408                 : {
    5409               0 :   InitializeSelection(aFocusEventTarget);
    5410               0 :   if (mInlineSpellChecker) {
    5411               0 :     mInlineSpellChecker->UpdateCurrentDictionary();
    5412                 :   }
    5413            4392 : }

Generated by: LCOV version 1.7