LCOV - code coverage report
Current view: directory - content/html/content/src - nsTextEditorState.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 865 56 6.5 %
Date: 2012-06-02 Functions: 105 15 14.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set sw=2 ts=2 et tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.org client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Ehsan Akhgari <ehsan@mozilla.com> (Original Author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsTextEditorState.h"
      40                 : 
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsIPresShell.h"
      43                 : #include "nsIView.h"
      44                 : #include "nsCaret.h"
      45                 : #include "nsEditorCID.h"
      46                 : #include "nsLayoutCID.h"
      47                 : #include "nsITextControlFrame.h" 
      48                 : #include "nsIPlaintextEditor.h"
      49                 : #include "nsIDOMDocument.h"
      50                 : #include "nsContentCreatorFunctions.h"
      51                 : #include "nsTextControlFrame.h"
      52                 : #include "nsIControllers.h"
      53                 : #include "nsIDOMHTMLInputElement.h"
      54                 : #include "nsIDOMHTMLTextAreaElement.h"
      55                 : #include "nsITransactionManager.h"
      56                 : #include "nsIControllerContext.h"
      57                 : #include "nsAttrValue.h"
      58                 : #include "nsGenericHTMLElement.h"
      59                 : #include "nsIDOMEventListener.h"
      60                 : #include "nsIEditorObserver.h"
      61                 : #include "nsINativeKeyBindings.h"
      62                 : #include "nsIDocumentEncoder.h"
      63                 : #include "nsISelectionPrivate.h"
      64                 : #include "nsPIDOMWindow.h"
      65                 : #include "nsServiceManagerUtils.h"
      66                 : #include "nsIEditor.h"
      67                 : #include "nsTextEditRules.h"
      68                 : #include "nsEventListenerManager.h"
      69                 : #include "nsContentUtils.h"
      70                 : 
      71                 : using namespace mozilla::dom;
      72                 : 
      73                 : static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
      74                 : 
      75                 : static nsINativeKeyBindings *sNativeInputBindings = nsnull;
      76                 : static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
      77                 : 
      78               0 : class RestoreSelectionState : public nsRunnable {
      79                 : public:
      80               0 :   RestoreSelectionState(nsTextEditorState *aState, nsTextControlFrame *aFrame)
      81                 :     : mFrame(aFrame),
      82               0 :       mTextEditorState(aState)
      83                 :   {
      84               0 :   }
      85                 : 
      86               0 :   NS_IMETHOD Run() {
      87               0 :     if (mFrame) {
      88                 :       // SetSelectionRange leads to Selection::AddRange which flushes Layout -
      89                 :       // need to block script to avoid nested PrepareEditor calls (bug 642800).
      90               0 :       nsAutoScriptBlocker scriptBlocker;
      91                 :        nsTextEditorState::SelectionProperties& properties =
      92               0 :          mTextEditorState->GetSelectionProperties();
      93                 :        mFrame->SetSelectionRange(properties.mStart,
      94                 :                                  properties.mEnd,
      95               0 :                                  properties.mDirection);
      96               0 :       if (!mTextEditorState->mSelectionRestoreEagerInit) {
      97               0 :         mTextEditorState->HideSelectionIfBlurred();
      98                 :       }
      99               0 :       mTextEditorState->mSelectionRestoreEagerInit = false;
     100                 :     }
     101               0 :     mTextEditorState->FinishedRestoringSelection();
     102               0 :     return NS_OK;
     103                 :   }
     104                 : 
     105                 :   // Let the text editor tell us we're no longer relevant - avoids use of nsWeakFrame
     106               0 :   void Revoke() {
     107               0 :     mFrame = nsnull;
     108               0 :   }
     109                 : 
     110                 : private:
     111                 :   nsTextControlFrame* mFrame;
     112                 :   nsTextEditorState* mTextEditorState;
     113                 : };
     114                 : 
     115                 : /*static*/
     116                 : bool
     117               0 : nsITextControlElement::GetWrapPropertyEnum(nsIContent* aContent,
     118                 :   nsITextControlElement::nsHTMLTextWrap& aWrapProp)
     119                 : {
     120                 :   // soft is the default; "physical" defaults to soft as well because all other
     121                 :   // browsers treat it that way and there is no real reason to maintain physical
     122                 :   // and virtual as separate entities if no one else does.  Only hard and off
     123                 :   // do anything different.
     124               0 :   aWrapProp = eHTMLTextWrap_Soft; // the default
     125                 : 
     126               0 :   nsAutoString wrap;
     127               0 :   if (aContent->IsHTML()) {
     128                 :     static nsIContent::AttrValuesArray strings[] =
     129                 :       {&nsGkAtoms::HARD, &nsGkAtoms::OFF, nsnull};
     130                 : 
     131               0 :     switch (aContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::wrap,
     132               0 :                                       strings, eIgnoreCase)) {
     133               0 :       case 0: aWrapProp = eHTMLTextWrap_Hard; break;
     134               0 :       case 1: aWrapProp = eHTMLTextWrap_Off; break;
     135                 :     }
     136                 : 
     137               0 :     return true;
     138                 :   }
     139                 : 
     140               0 :   return false;
     141                 : }
     142                 : 
     143                 : static bool
     144               0 : SuppressEventHandlers(nsPresContext* aPresContext)
     145                 : {
     146               0 :   bool suppressHandlers = false;
     147                 : 
     148               0 :   if (aPresContext)
     149                 :   {
     150                 :     // Right now we only suppress event handlers and controller manipulation
     151                 :     // when in a print preview or print context!
     152                 : 
     153                 :     // In the current implementation, we only paginate when
     154                 :     // printing or in print preview.
     155                 : 
     156               0 :     suppressHandlers = aPresContext->IsPaginated();
     157                 :   }
     158                 : 
     159               0 :   return suppressHandlers;
     160                 : }
     161                 : 
     162                 : class nsAnonDivObserver MOZ_FINAL : public nsStubMutationObserver
     163                 : {
     164                 : public:
     165               0 :   nsAnonDivObserver(nsTextEditorState* aTextEditorState)
     166               0 :   : mTextEditorState(aTextEditorState) {}
     167                 :   NS_DECL_ISUPPORTS
     168                 :   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
     169                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     170                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     171                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     172                 : 
     173                 : private:
     174                 :   nsTextEditorState* mTextEditorState;
     175                 : };
     176                 : 
     177                 : class nsTextInputSelectionImpl MOZ_FINAL : public nsSupportsWeakReference
     178                 :                                          , public nsISelectionController
     179                 : {
     180                 : public:
     181               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     182            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTextInputSelectionImpl, nsISelectionController)
     183                 : 
     184                 :   nsTextInputSelectionImpl(nsFrameSelection *aSel, nsIPresShell *aShell, nsIContent *aLimiter);
     185               0 :   ~nsTextInputSelectionImpl(){}
     186                 : 
     187                 :   void SetScrollableFrame(nsIScrollableFrame *aScrollableFrame);
     188               0 :   nsFrameSelection* GetConstFrameSelection()
     189               0 :     { return mFrameSelection; }
     190                 : 
     191                 :   //NSISELECTIONCONTROLLER INTERFACES
     192                 :   NS_IMETHOD SetDisplaySelection(PRInt16 toggle);
     193                 :   NS_IMETHOD GetDisplaySelection(PRInt16 *_retval);
     194                 :   NS_IMETHOD SetSelectionFlags(PRInt16 aInEnable);
     195                 :   NS_IMETHOD GetSelectionFlags(PRInt16 *aOutEnable);
     196                 :   NS_IMETHOD GetSelection(PRInt16 type, nsISelection **_retval);
     197                 :   NS_IMETHOD ScrollSelectionIntoView(PRInt16 aType, PRInt16 aRegion, PRInt16 aFlags);
     198                 :   NS_IMETHOD RepaintSelection(PRInt16 type);
     199                 :   NS_IMETHOD RepaintSelection(nsPresContext* aPresContext, SelectionType aSelectionType);
     200                 :   NS_IMETHOD SetCaretEnabled(bool enabled);
     201                 :   NS_IMETHOD SetCaretReadOnly(bool aReadOnly);
     202                 :   NS_IMETHOD GetCaretEnabled(bool *_retval);
     203                 :   NS_IMETHOD GetCaretVisible(bool *_retval);
     204                 :   NS_IMETHOD SetCaretVisibilityDuringSelection(bool aVisibility);
     205                 :   NS_IMETHOD CharacterMove(bool aForward, bool aExtend);
     206                 :   NS_IMETHOD CharacterExtendForDelete();
     207                 :   NS_IMETHOD CharacterExtendForBackspace();
     208                 :   NS_IMETHOD WordMove(bool aForward, bool aExtend);
     209                 :   NS_IMETHOD WordExtendForDelete(bool aForward);
     210                 :   NS_IMETHOD LineMove(bool aForward, bool aExtend);
     211                 :   NS_IMETHOD IntraLineMove(bool aForward, bool aExtend);
     212                 :   NS_IMETHOD PageMove(bool aForward, bool aExtend);
     213                 :   NS_IMETHOD CompleteScroll(bool aForward);
     214                 :   NS_IMETHOD CompleteMove(bool aForward, bool aExtend);
     215                 :   NS_IMETHOD ScrollPage(bool aForward);
     216                 :   NS_IMETHOD ScrollLine(bool aForward);
     217                 :   NS_IMETHOD ScrollCharacter(bool aRight);
     218                 :   NS_IMETHOD SelectAll(void);
     219                 :   NS_IMETHOD CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, bool *_retval);
     220                 :   virtual nsresult CheckVisibilityContent(nsIContent* aNode, PRInt16 aStartOffset, PRInt16 aEndOffset, bool* aRetval);
     221                 : 
     222                 : private:
     223                 :   nsRefPtr<nsFrameSelection> mFrameSelection;
     224                 :   nsCOMPtr<nsIContent>       mLimiter;
     225                 :   nsIScrollableFrame        *mScrollFrame;
     226                 :   nsWeakPtr mPresShellWeak;
     227                 : };
     228                 : 
     229               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTextInputSelectionImpl)
     230               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTextInputSelectionImpl)
     231               0 : NS_INTERFACE_TABLE_HEAD(nsTextInputSelectionImpl)
     232               0 :   NS_INTERFACE_TABLE3(nsTextInputSelectionImpl,
     233                 :                       nsISelectionController,
     234                 :                       nsISelectionDisplay,
     235                 :                       nsISupportsWeakReference)
     236               0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsTextInputSelectionImpl)
     237               0 : NS_INTERFACE_MAP_END
     238                 : 
     239            1464 : NS_IMPL_CYCLE_COLLECTION_2(nsTextInputSelectionImpl, mFrameSelection, mLimiter)
     240                 : 
     241                 : 
     242                 : // BEGIN nsTextInputSelectionImpl
     243                 : 
     244               0 : nsTextInputSelectionImpl::nsTextInputSelectionImpl(nsFrameSelection *aSel,
     245                 :                                                    nsIPresShell *aShell,
     246                 :                                                    nsIContent *aLimiter)
     247               0 :   : mScrollFrame(nsnull)
     248                 : {
     249               0 :   if (aSel && aShell)
     250                 :   {
     251               0 :     mFrameSelection = aSel;//we are the owner now!
     252               0 :     mLimiter = aLimiter;
     253               0 :     mFrameSelection->Init(aShell, mLimiter);
     254               0 :     mPresShellWeak = do_GetWeakReference(aShell);
     255                 :   }
     256               0 : }
     257                 : 
     258                 : void
     259               0 : nsTextInputSelectionImpl::SetScrollableFrame(nsIScrollableFrame *aScrollableFrame)
     260                 : {
     261               0 :   mScrollFrame = aScrollableFrame;
     262               0 :   if (!mScrollFrame && mFrameSelection) {
     263               0 :     mFrameSelection->DisconnectFromPresShell();
     264               0 :     mFrameSelection = nsnull;
     265                 :   }
     266               0 : }
     267                 : 
     268                 : NS_IMETHODIMP
     269               0 : nsTextInputSelectionImpl::SetDisplaySelection(PRInt16 aToggle)
     270                 : {
     271               0 :   if (!mFrameSelection)
     272               0 :     return NS_ERROR_NULL_POINTER;
     273                 :   
     274               0 :   mFrameSelection->SetDisplaySelection(aToggle);
     275               0 :   return NS_OK;
     276                 : }
     277                 : 
     278                 : NS_IMETHODIMP
     279               0 : nsTextInputSelectionImpl::GetDisplaySelection(PRInt16 *aToggle)
     280                 : {
     281               0 :   if (!mFrameSelection)
     282               0 :     return NS_ERROR_NULL_POINTER;
     283                 : 
     284               0 :   *aToggle = mFrameSelection->GetDisplaySelection();
     285               0 :   return NS_OK;
     286                 : }
     287                 : 
     288                 : NS_IMETHODIMP
     289               0 : nsTextInputSelectionImpl::SetSelectionFlags(PRInt16 aToggle)
     290                 : {
     291               0 :   return NS_OK;//stub this out. not used in input
     292                 : }
     293                 : 
     294                 : NS_IMETHODIMP
     295               0 : nsTextInputSelectionImpl::GetSelectionFlags(PRInt16 *aOutEnable)
     296                 : {
     297               0 :   *aOutEnable = nsISelectionDisplay::DISPLAY_TEXT;
     298               0 :   return NS_OK; 
     299                 : }
     300                 : 
     301                 : NS_IMETHODIMP
     302               0 : nsTextInputSelectionImpl::GetSelection(PRInt16 type, nsISelection **_retval)
     303                 : {
     304               0 :   if (!mFrameSelection)
     305               0 :     return NS_ERROR_NULL_POINTER;
     306                 :     
     307               0 :   *_retval = mFrameSelection->GetSelection(type);
     308                 :   
     309               0 :   if (!(*_retval))
     310               0 :     return NS_ERROR_FAILURE;
     311                 : 
     312               0 :   NS_ADDREF(*_retval);
     313               0 :   return NS_OK;
     314                 : }
     315                 : 
     316                 : NS_IMETHODIMP
     317               0 : nsTextInputSelectionImpl::ScrollSelectionIntoView(PRInt16 aType, PRInt16 aRegion, PRInt16 aFlags)
     318                 : {
     319               0 :   if (!mFrameSelection) 
     320               0 :     return NS_ERROR_FAILURE; 
     321                 : 
     322               0 :   return mFrameSelection->ScrollSelectionIntoView(aType, aRegion, aFlags);
     323                 : }
     324                 : 
     325                 : NS_IMETHODIMP
     326               0 : nsTextInputSelectionImpl::RepaintSelection(PRInt16 type)
     327                 : {
     328               0 :   if (!mFrameSelection)
     329               0 :     return NS_ERROR_FAILURE;
     330                 : 
     331               0 :   return mFrameSelection->RepaintSelection(type);
     332                 : }
     333                 : 
     334                 : NS_IMETHODIMP
     335               0 : nsTextInputSelectionImpl::RepaintSelection(nsPresContext* aPresContext, SelectionType aSelectionType)
     336                 : {
     337               0 :   if (!mFrameSelection)
     338               0 :     return NS_ERROR_FAILURE;
     339                 : 
     340               0 :   return mFrameSelection->RepaintSelection(aSelectionType);
     341                 : }
     342                 : 
     343                 : NS_IMETHODIMP
     344               0 : nsTextInputSelectionImpl::SetCaretEnabled(bool enabled)
     345                 : {
     346               0 :   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
     347                 : 
     348               0 :   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak);
     349               0 :   if (!shell) return NS_ERROR_FAILURE;
     350                 : 
     351                 :   // tell the pres shell to enable the caret, rather than settings its visibility directly.
     352                 :   // this way the presShell's idea of caret visibility is maintained.
     353               0 :   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
     354               0 :   if (!selCon) return NS_ERROR_NO_INTERFACE;
     355               0 :   selCon->SetCaretEnabled(enabled);
     356                 : 
     357               0 :   return NS_OK;
     358                 : }
     359                 : 
     360                 : NS_IMETHODIMP
     361               0 : nsTextInputSelectionImpl::SetCaretReadOnly(bool aReadOnly)
     362                 : {
     363               0 :   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
     364                 :   nsresult result;
     365               0 :   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
     366               0 :   if (shell)
     367                 :   {
     368               0 :     nsRefPtr<nsCaret> caret = shell->GetCaret();
     369               0 :     if (caret) {
     370                 :       nsISelection* domSel = mFrameSelection->
     371               0 :         GetSelection(nsISelectionController::SELECTION_NORMAL);
     372               0 :       if (domSel)
     373               0 :         caret->SetCaretReadOnly(aReadOnly);
     374               0 :       return NS_OK;
     375                 :     }
     376                 :   }
     377               0 :   return NS_ERROR_FAILURE;
     378                 : }
     379                 : 
     380                 : NS_IMETHODIMP
     381               0 : nsTextInputSelectionImpl::GetCaretEnabled(bool *_retval)
     382                 : {
     383               0 :   return GetCaretVisible(_retval);
     384                 : }
     385                 : 
     386                 : NS_IMETHODIMP
     387               0 : nsTextInputSelectionImpl::GetCaretVisible(bool *_retval)
     388                 : {
     389               0 :   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
     390                 :   nsresult result;
     391               0 :   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
     392               0 :   if (shell)
     393                 :   {
     394               0 :     nsRefPtr<nsCaret> caret = shell->GetCaret();
     395               0 :     if (caret) {
     396                 :       nsISelection* domSel = mFrameSelection->
     397               0 :         GetSelection(nsISelectionController::SELECTION_NORMAL);
     398               0 :       if (domSel)
     399               0 :         return caret->GetCaretVisible(_retval);
     400                 :     }
     401                 :   }
     402               0 :   return NS_ERROR_FAILURE;
     403                 : }
     404                 : 
     405                 : NS_IMETHODIMP
     406               0 : nsTextInputSelectionImpl::SetCaretVisibilityDuringSelection(bool aVisibility)
     407                 : {
     408               0 :   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
     409                 :   nsresult result;
     410               0 :   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
     411               0 :   if (shell)
     412                 :   {
     413               0 :     nsRefPtr<nsCaret> caret = shell->GetCaret();
     414               0 :     if (caret) {
     415                 :       nsISelection* domSel = mFrameSelection->
     416               0 :         GetSelection(nsISelectionController::SELECTION_NORMAL);
     417               0 :       if (domSel)
     418               0 :         caret->SetVisibilityDuringSelection(aVisibility);
     419               0 :       return NS_OK;
     420                 :     }
     421                 :   }
     422               0 :   return NS_ERROR_FAILURE;
     423                 : }
     424                 : 
     425                 : NS_IMETHODIMP
     426               0 : nsTextInputSelectionImpl::CharacterMove(bool aForward, bool aExtend)
     427                 : {
     428               0 :   if (mFrameSelection)
     429               0 :     return mFrameSelection->CharacterMove(aForward, aExtend);
     430               0 :   return NS_ERROR_NULL_POINTER;
     431                 : }
     432                 : 
     433                 : NS_IMETHODIMP
     434               0 : nsTextInputSelectionImpl::CharacterExtendForDelete()
     435                 : {
     436               0 :   if (mFrameSelection)
     437               0 :     return mFrameSelection->CharacterExtendForDelete();
     438               0 :   return NS_ERROR_NULL_POINTER;
     439                 : }
     440                 : 
     441                 : NS_IMETHODIMP
     442               0 : nsTextInputSelectionImpl::CharacterExtendForBackspace()
     443                 : {
     444               0 :   if (mFrameSelection)
     445               0 :     return mFrameSelection->CharacterExtendForBackspace();
     446               0 :   return NS_ERROR_NULL_POINTER;
     447                 : }
     448                 : 
     449                 : NS_IMETHODIMP
     450               0 : nsTextInputSelectionImpl::WordMove(bool aForward, bool aExtend)
     451                 : {
     452               0 :   if (mFrameSelection)
     453               0 :     return mFrameSelection->WordMove(aForward, aExtend);
     454               0 :   return NS_ERROR_NULL_POINTER;
     455                 : }
     456                 : 
     457                 : NS_IMETHODIMP
     458               0 : nsTextInputSelectionImpl::WordExtendForDelete(bool aForward)
     459                 : {
     460               0 :   if (mFrameSelection)
     461               0 :     return mFrameSelection->WordExtendForDelete(aForward);
     462               0 :   return NS_ERROR_NULL_POINTER;
     463                 : }
     464                 : 
     465                 : NS_IMETHODIMP
     466               0 : nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend)
     467                 : {
     468               0 :   if (mFrameSelection)
     469                 :   {
     470               0 :     nsresult result = mFrameSelection->LineMove(aForward, aExtend);
     471               0 :     if (NS_FAILED(result))
     472               0 :       result = CompleteMove(aForward,aExtend);
     473               0 :     return result;
     474                 :   }
     475               0 :   return NS_ERROR_NULL_POINTER;
     476                 : }
     477                 : 
     478                 : 
     479                 : NS_IMETHODIMP
     480               0 : nsTextInputSelectionImpl::IntraLineMove(bool aForward, bool aExtend)
     481                 : {
     482               0 :   if (mFrameSelection)
     483               0 :     return mFrameSelection->IntraLineMove(aForward, aExtend);
     484               0 :   return NS_ERROR_NULL_POINTER;
     485                 : }
     486                 : 
     487                 : 
     488                 : NS_IMETHODIMP
     489               0 : nsTextInputSelectionImpl::PageMove(bool aForward, bool aExtend)
     490                 : {
     491                 :   // expected behavior for PageMove is to scroll AND move the caret
     492                 :   // and to remain relative position of the caret in view. see Bug 4302.
     493               0 :   if (mScrollFrame)
     494                 :   {
     495               0 :     mFrameSelection->CommonPageMove(aForward, aExtend, mScrollFrame);
     496                 :   }
     497                 :   // After ScrollSelectionIntoView(), the pending notifications might be
     498                 :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
     499                 :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION,
     500               0 :                                  nsISelectionController::SCROLL_SYNCHRONOUS);
     501                 : }
     502                 : 
     503                 : NS_IMETHODIMP
     504               0 : nsTextInputSelectionImpl::CompleteScroll(bool aForward)
     505                 : {
     506               0 :   if (!mScrollFrame)
     507               0 :     return NS_ERROR_NOT_INITIALIZED;
     508                 : 
     509                 :   mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
     510                 :                          nsIScrollableFrame::WHOLE,
     511               0 :                          nsIScrollableFrame::INSTANT);
     512               0 :   return NS_OK;
     513                 : }
     514                 : 
     515                 : NS_IMETHODIMP
     516               0 : nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend)
     517                 : {
     518                 :   // grab the parent / root DIV for this text widget
     519               0 :   nsIContent* parentDIV = mFrameSelection->GetLimiter();
     520               0 :   if (!parentDIV)
     521               0 :     return NS_ERROR_UNEXPECTED;
     522                 : 
     523                 :   // make the caret be either at the very beginning (0) or the very end
     524               0 :   PRInt32 offset = 0;
     525               0 :   nsFrameSelection::HINT hint = nsFrameSelection::HINTLEFT;
     526               0 :   if (aForward)
     527                 :   {
     528               0 :     offset = parentDIV->GetChildCount();
     529                 : 
     530                 :     // Prevent the caret from being placed after the last
     531                 :     // BR node in the content tree!
     532                 : 
     533               0 :     if (offset > 0)
     534                 :     {
     535               0 :       nsIContent *child = parentDIV->GetLastChild();
     536                 : 
     537               0 :       if (child->Tag() == nsGkAtoms::br)
     538                 :       {
     539               0 :         --offset;
     540               0 :         hint = nsFrameSelection::HINTRIGHT; // for Bug 106855
     541                 :       }
     542                 :     }
     543                 :   }
     544                 : 
     545                 :   mFrameSelection->HandleClick(parentDIV, offset, offset, aExtend,
     546               0 :                                false, hint);
     547                 : 
     548                 :   // if we got this far, attempt to scroll no matter what the above result is
     549               0 :   return CompleteScroll(aForward);
     550                 : }
     551                 : 
     552                 : NS_IMETHODIMP
     553               0 : nsTextInputSelectionImpl::ScrollPage(bool aForward)
     554                 : {
     555               0 :   if (!mScrollFrame)
     556               0 :     return NS_ERROR_NOT_INITIALIZED;
     557                 : 
     558                 :   mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
     559                 :                          nsIScrollableFrame::PAGES,
     560               0 :                          nsIScrollableFrame::SMOOTH);
     561               0 :   return NS_OK;
     562                 : }
     563                 : 
     564                 : NS_IMETHODIMP
     565               0 : nsTextInputSelectionImpl::ScrollLine(bool aForward)
     566                 : {
     567               0 :   if (!mScrollFrame)
     568               0 :     return NS_ERROR_NOT_INITIALIZED;
     569                 : 
     570                 :   mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
     571                 :                          nsIScrollableFrame::LINES,
     572               0 :                          nsIScrollableFrame::SMOOTH);
     573               0 :   return NS_OK;
     574                 : }
     575                 : 
     576                 : NS_IMETHODIMP
     577               0 : nsTextInputSelectionImpl::ScrollCharacter(bool aRight)
     578                 : {
     579               0 :   if (!mScrollFrame)
     580               0 :     return NS_ERROR_NOT_INITIALIZED;
     581                 : 
     582                 :   mScrollFrame->ScrollBy(nsIntPoint(aRight ? 1 : -1, 0),
     583                 :                          nsIScrollableFrame::LINES,
     584               0 :                          nsIScrollableFrame::SMOOTH);
     585               0 :   return NS_OK;
     586                 : }
     587                 : 
     588                 : NS_IMETHODIMP
     589               0 : nsTextInputSelectionImpl::SelectAll()
     590                 : {
     591               0 :   if (mFrameSelection)
     592               0 :     return mFrameSelection->SelectAll();
     593               0 :   return NS_ERROR_NULL_POINTER;
     594                 : }
     595                 : 
     596                 : NS_IMETHODIMP
     597               0 : nsTextInputSelectionImpl::CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, bool *_retval)
     598                 : {
     599               0 :   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
     600                 :   nsresult result;
     601               0 :   nsCOMPtr<nsISelectionController> shell = do_QueryReferent(mPresShellWeak, &result);
     602               0 :   if (shell)
     603                 :   {
     604               0 :     return shell->CheckVisibility(node,startOffset,EndOffset, _retval);
     605                 :   }
     606               0 :   return NS_ERROR_FAILURE;
     607                 : 
     608                 : }
     609                 : 
     610                 : nsresult
     611               0 : nsTextInputSelectionImpl::CheckVisibilityContent(nsIContent* aNode,
     612                 :                                                  PRInt16 aStartOffset,
     613                 :                                                  PRInt16 aEndOffset,
     614                 :                                                  bool* aRetval)
     615                 : {
     616               0 :   if (!mPresShellWeak) {
     617               0 :     return NS_ERROR_NOT_INITIALIZED;
     618                 :   }
     619                 : 
     620               0 :   nsCOMPtr<nsISelectionController> shell = do_QueryReferent(mPresShellWeak);
     621               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
     622                 : 
     623               0 :   return shell->CheckVisibilityContent(aNode, aStartOffset, aEndOffset, aRetval);
     624                 : }
     625                 : 
     626                 : class nsTextInputListener : public nsISelectionListener,
     627                 :                             public nsIDOMEventListener,
     628                 :                             public nsIEditorObserver,
     629                 :                             public nsSupportsWeakReference
     630                 : {
     631                 : public:
     632                 :   /** the default constructor
     633                 :    */ 
     634                 :   explicit nsTextInputListener(nsITextControlElement* aTxtCtrlElement);
     635                 :   /** the default destructor. virtual due to the possibility of derivation.
     636                 :    */
     637                 :   virtual ~nsTextInputListener();
     638                 : 
     639                 :   /** SetEditor gives an address to the editor that will be accessed
     640                 :    *  @param aEditor the editor this listener calls for editing operations
     641                 :    */
     642               0 :   void SetFrame(nsTextControlFrame *aFrame){mFrame = aFrame;}
     643                 : 
     644               0 :   void SettingValue(bool aValue) { mSettingValue = aValue; }
     645                 : 
     646                 :   NS_DECL_ISUPPORTS
     647                 : 
     648                 :   NS_DECL_NSISELECTIONLISTENER
     649                 : 
     650                 :   NS_DECL_NSIDOMEVENTLISTENER
     651                 : 
     652                 :   NS_DECL_NSIEDITOROBSERVER
     653                 : 
     654                 : protected:
     655                 : 
     656                 :   nsresult  UpdateTextInputCommands(const nsAString& commandsToUpdate);
     657                 : 
     658                 :   NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
     659                 : 
     660                 : protected:
     661                 : 
     662                 :   nsIFrame* mFrame;
     663                 : 
     664                 :   nsITextControlElement* const mTxtCtrlElement;
     665                 : 
     666                 :   bool            mSelectionWasCollapsed;
     667                 :   /**
     668                 :    * Whether we had undo items or not the last time we got EditAction()
     669                 :    * notification (when this state changes we update undo and redo menus)
     670                 :    */
     671                 :   bool            mHadUndoItems;
     672                 :   /**
     673                 :    * Whether we had redo items or not the last time we got EditAction()
     674                 :    * notification (when this state changes we update undo and redo menus)
     675                 :    */
     676                 :   bool            mHadRedoItems;
     677                 :   /**
     678                 :    * Whether we're in the process of a SetValue call, and should therefore
     679                 :    * refrain from calling OnValueChanged.
     680                 :    */
     681                 :   bool mSettingValue;
     682                 : };
     683                 : 
     684                 : 
     685                 : /*
     686                 :  * nsTextInputListener implementation
     687                 :  */
     688                 : 
     689               0 : nsTextInputListener::nsTextInputListener(nsITextControlElement* aTxtCtrlElement)
     690                 : : mFrame(nsnull)
     691                 : , mTxtCtrlElement(aTxtCtrlElement)
     692                 : , mSelectionWasCollapsed(true)
     693                 : , mHadUndoItems(false)
     694                 : , mHadRedoItems(false)
     695               0 : , mSettingValue(false)
     696                 : {
     697               0 : }
     698                 : 
     699               0 : nsTextInputListener::~nsTextInputListener() 
     700                 : {
     701               0 : }
     702                 : 
     703               0 : NS_IMPL_ISUPPORTS4(nsTextInputListener,
     704                 :                    nsISelectionListener,
     705                 :                    nsIEditorObserver,
     706                 :                    nsISupportsWeakReference,
     707                 :                    nsIDOMEventListener)
     708                 : 
     709                 : // BEGIN nsIDOMSelectionListener
     710                 : 
     711                 : NS_IMETHODIMP
     712               0 : nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel, PRInt16 aReason)
     713                 : {
     714                 :   bool collapsed;
     715               0 :   nsWeakFrame weakFrame = mFrame;
     716                 : 
     717               0 :   if (!aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
     718               0 :     return NS_OK;
     719                 : 
     720                 :   // Fire the select event
     721                 :   // The specs don't exactly say when we should fire the select event.
     722                 :   // IE: Whenever you add/remove a character to/from the selection. Also
     723                 :   //     each time for select all. Also if you get to the end of the text 
     724                 :   //     field you will get new event for each keypress or a continuous 
     725                 :   //     stream of events if you use the mouse. IE will fire select event 
     726                 :   //     when the selection collapses to nothing if you are holding down
     727                 :   //     the shift or mouse button.
     728                 :   // Mozilla: If we have non-empty selection we will fire a new event for each
     729                 :   //          keypress (or mouseup) if the selection changed. Mozilla will also
     730                 :   //          create the event each time select all is called, even if everything
     731                 :   //          was previously selected, becase technically select all will first collapse
     732                 :   //          and then extend. Mozilla will never create an event if the selection 
     733                 :   //          collapses to nothing.
     734               0 :   if (!collapsed && (aReason & (nsISelectionListener::MOUSEUP_REASON | 
     735                 :                                 nsISelectionListener::KEYPRESS_REASON |
     736                 :                                 nsISelectionListener::SELECTALL_REASON)))
     737                 :   {
     738               0 :     nsIContent* content = mFrame->GetContent();
     739               0 :     if (content) 
     740                 :     {
     741               0 :       nsCOMPtr<nsIDocument> doc = content->GetDocument();
     742               0 :       if (doc) 
     743                 :       {
     744               0 :         nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
     745               0 :         if (presShell) 
     746                 :         {
     747               0 :           nsEventStatus status = nsEventStatus_eIgnore;
     748               0 :           nsEvent event(true, NS_FORM_SELECTED);
     749                 : 
     750               0 :           presShell->HandleEventWithTarget(&event, mFrame, content, &status);
     751                 :         }
     752                 :       }
     753                 :     }
     754                 :   }
     755                 : 
     756                 :   // if the collapsed state did not change, don't fire notifications
     757               0 :   if (collapsed == mSelectionWasCollapsed)
     758               0 :     return NS_OK;
     759                 :   
     760               0 :   mSelectionWasCollapsed = collapsed;
     761                 : 
     762               0 :   if (!weakFrame.IsAlive() || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
     763               0 :     return NS_OK;
     764                 : 
     765               0 :   return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
     766                 : }
     767                 : 
     768                 : // END nsIDOMSelectionListener
     769                 : 
     770                 : static void
     771               0 : DoCommandCallback(const char *aCommand, void *aData)
     772                 : {
     773               0 :   nsTextControlFrame *frame = static_cast<nsTextControlFrame*>(aData);
     774               0 :   nsIContent *content = frame->GetContent();
     775                 : 
     776               0 :   nsCOMPtr<nsIControllers> controllers;
     777               0 :   nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(content);
     778               0 :   if (input) {
     779               0 :     input->GetControllers(getter_AddRefs(controllers));
     780                 :   } else {
     781                 :     nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea =
     782               0 :       do_QueryInterface(content);
     783                 : 
     784               0 :     if (textArea) {
     785               0 :       textArea->GetControllers(getter_AddRefs(controllers));
     786                 :     }
     787                 :   }
     788                 : 
     789               0 :   if (!controllers) {
     790               0 :     NS_WARNING("Could not get controllers");
     791                 :     return;
     792                 :   }
     793                 : 
     794               0 :   nsCOMPtr<nsIController> controller;
     795               0 :   controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
     796               0 :   if (controller) {
     797               0 :     controller->DoCommand(aCommand);
     798                 :   }
     799                 : }
     800                 : 
     801                 : NS_IMETHODIMP
     802               0 : nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent)
     803                 : {
     804               0 :   nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
     805               0 :   NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
     806                 : 
     807               0 :   nsAutoString eventType;
     808               0 :   aEvent->GetType(eventType);
     809                 : 
     810                 :   nsNativeKeyEvent nativeEvent;
     811               0 :   nsINativeKeyBindings *bindings = GetKeyBindings();
     812               0 :   if (bindings &&
     813               0 :       nsContentUtils::DOMEventToNativeKeyEvent(keyEvent, &nativeEvent, false)) {
     814                 : 
     815               0 :     bool handled = false;
     816               0 :     if (eventType.EqualsLiteral("keydown")) {
     817               0 :       handled = bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame);
     818                 :     }
     819               0 :     else if (eventType.EqualsLiteral("keyup")) {
     820               0 :       handled = bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame);
     821                 :     }
     822               0 :     else if (eventType.EqualsLiteral("keypress")) {
     823               0 :       handled = bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame);
     824                 :     }
     825                 :     else {
     826               0 :       NS_ABORT();
     827                 :     }
     828               0 :     if (handled) {
     829               0 :       aEvent->PreventDefault();
     830                 :     }
     831                 :   }
     832                 : 
     833               0 :   return NS_OK;
     834                 : }
     835                 : 
     836                 : // BEGIN nsIEditorObserver
     837                 : 
     838                 : NS_IMETHODIMP
     839               0 : nsTextInputListener::EditAction()
     840                 : {
     841               0 :   nsWeakFrame weakFrame = mFrame;
     842                 : 
     843               0 :   nsITextControlFrame* frameBase = do_QueryFrame(mFrame);
     844               0 :   nsTextControlFrame* frame = static_cast<nsTextControlFrame*> (frameBase);
     845               0 :   NS_ASSERTION(frame, "Where is our frame?");
     846                 :   //
     847                 :   // Update the undo / redo menus
     848                 :   //
     849               0 :   nsCOMPtr<nsIEditor> editor;
     850               0 :   frame->GetEditor(getter_AddRefs(editor));
     851                 : 
     852                 :   // Get the number of undo / redo items
     853               0 :   PRInt32 numUndoItems = 0;
     854               0 :   PRInt32 numRedoItems = 0;
     855               0 :   editor->GetNumberOfUndoItems(&numUndoItems);
     856               0 :   editor->GetNumberOfRedoItems(&numRedoItems);
     857               0 :   if ((numUndoItems && !mHadUndoItems) || (!numUndoItems && mHadUndoItems) ||
     858               0 :       (numRedoItems && !mHadRedoItems) || (!numRedoItems && mHadRedoItems)) {
     859                 :     // Modify the menu if undo or redo items are different
     860               0 :     UpdateTextInputCommands(NS_LITERAL_STRING("undo"));
     861                 : 
     862               0 :     mHadUndoItems = numUndoItems != 0;
     863               0 :     mHadRedoItems = numRedoItems != 0;
     864                 :   }
     865                 : 
     866               0 :   if (!weakFrame.IsAlive()) {
     867               0 :     return NS_OK;
     868                 :   }
     869                 : 
     870                 :   // Make sure we know we were changed (do NOT set this to false if there are
     871                 :   // no undo items; JS could change the value and we'd still need to save it)
     872               0 :   frame->SetValueChanged(true);
     873                 : 
     874               0 :   if (!mSettingValue) {
     875               0 :     mTxtCtrlElement->OnValueChanged(true);
     876                 :   }
     877                 : 
     878                 :   // Fire input event
     879               0 :   bool trusted = false;
     880               0 :   editor->GetLastKeypressEventTrusted(&trusted);
     881               0 :   frame->FireOnInput(trusted);
     882                 : 
     883                 :   // mFrame may be dead after this, but we don't need to check for it, because
     884                 :   // we are not uisng it in this function any more.
     885                 : 
     886               0 :   return NS_OK;
     887                 : }
     888                 : 
     889                 : // END nsIEditorObserver
     890                 : 
     891                 : 
     892                 : nsresult
     893               0 : nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
     894                 : {
     895               0 :   nsIContent* content = mFrame->GetContent();
     896               0 :   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
     897                 :   
     898               0 :   nsCOMPtr<nsIDocument> doc = content->GetDocument();
     899               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
     900                 : 
     901               0 :   nsPIDOMWindow *domWindow = doc->GetWindow();
     902               0 :   NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
     903                 : 
     904               0 :   return domWindow->UpdateCommands(commandsToUpdate);
     905                 : }
     906                 : 
     907                 : nsINativeKeyBindings*
     908               0 : nsTextInputListener::GetKeyBindings()
     909                 : {
     910               0 :   if (mTxtCtrlElement->IsTextArea()) {
     911                 :     static bool sNoTextAreaBindings = false;
     912                 : 
     913               0 :     if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
     914                 :       CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
     915               0 :                      &sNativeTextAreaBindings);
     916                 : 
     917               0 :       if (!sNativeTextAreaBindings) {
     918               0 :         sNoTextAreaBindings = true;
     919                 :       }
     920                 :     }
     921                 : 
     922               0 :     return sNativeTextAreaBindings;
     923                 :   }
     924                 : 
     925                 :   static bool sNoInputBindings = false;
     926               0 :   if (!sNativeInputBindings && !sNoInputBindings) {
     927                 :     CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
     928               0 :                    &sNativeInputBindings);
     929                 : 
     930               0 :     if (!sNativeInputBindings) {
     931               0 :       sNoInputBindings = true;
     932                 :     }
     933                 :   }
     934                 : 
     935               0 :   return sNativeInputBindings;
     936                 : }
     937                 : 
     938                 : // END nsTextInputListener
     939                 : 
     940                 : // nsTextEditorState
     941                 : 
     942               1 : nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
     943                 :   : mTextCtrlElement(aOwningElement),
     944                 :     mRestoringSelection(nsnull),
     945                 :     mBoundFrame(nsnull),
     946                 :     mTextListener(nsnull),
     947                 :     mEverInited(false),
     948                 :     mEditorInitialized(false),
     949                 :     mInitializing(false),
     950                 :     mValueTransferInProgress(false),
     951                 :     mSelectionCached(true),
     952               1 :     mSelectionRestoreEagerInit(false)
     953                 : {
     954               1 :   MOZ_COUNT_CTOR(nsTextEditorState);
     955               1 : }
     956                 : 
     957               2 : nsTextEditorState::~nsTextEditorState()
     958                 : {
     959               1 :   MOZ_COUNT_DTOR(nsTextEditorState);
     960               1 :   Clear();
     961               1 : }
     962                 : 
     963                 : void
     964               2 : nsTextEditorState::Clear()
     965                 : {
     966               2 :   if (mBoundFrame) {
     967                 :     // Oops, we still have a frame!
     968                 :     // This should happen when the type of a text input control is being changed
     969                 :     // to something which is not a text control.  In this case, we should pretend
     970                 :     // that a frame is being destroyed, and clean up after ourselves properly.
     971               0 :     UnbindFromFrame(mBoundFrame);
     972               0 :     mEditor = nsnull;
     973                 :   } else {
     974                 :     // If we have a bound frame around, UnbindFromFrame will call DestroyEditor
     975                 :     // for us.
     976               2 :     DestroyEditor();
     977                 :   }
     978               2 :   NS_IF_RELEASE(mTextListener);
     979               2 : }
     980                 : 
     981            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsTextEditorState)
     982               1 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTextEditorState, AddRef)
     983               1 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTextEditorState, Release)
     984               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsTextEditorState)
     985               1 :   tmp->Clear();
     986               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSelCon)
     987               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEditor)
     988               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRootNode)
     989               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPlaceholderDiv)
     990               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     991               1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTextEditorState)
     992               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mSelCon, nsISelectionController)
     993               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEditor)
     994               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRootNode)
     995               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPlaceholderDiv)
     996               1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     997                 : 
     998                 : nsFrameSelection*
     999               0 : nsTextEditorState::GetConstFrameSelection() {
    1000               0 :   if (mSelCon)
    1001               0 :     return mSelCon->GetConstFrameSelection();
    1002               0 :   return nsnull;
    1003                 : }
    1004                 : 
    1005                 : nsIEditor*
    1006               0 : nsTextEditorState::GetEditor()
    1007                 : {
    1008               0 :   if (!mEditor) {
    1009               0 :     nsresult rv = PrepareEditor();
    1010               0 :     NS_ENSURE_SUCCESS(rv, nsnull);
    1011                 :   }
    1012               0 :   return mEditor;
    1013                 : }
    1014                 : 
    1015                 : nsISelectionController*
    1016               0 : nsTextEditorState::GetSelectionController() const
    1017                 : {
    1018               0 :   return mSelCon;
    1019                 : }
    1020                 : 
    1021                 : // Helper class, used below in BindToFrame().
    1022               0 : class PrepareEditorEvent : public nsRunnable {
    1023                 : public:
    1024               0 :   PrepareEditorEvent(nsTextEditorState &aState,
    1025                 :                      nsIContent *aOwnerContent,
    1026                 :                      const nsAString &aCurrentValue)
    1027                 :     : mState(aState)
    1028                 :     , mOwnerContent(aOwnerContent)
    1029               0 :     , mCurrentValue(aCurrentValue)
    1030                 :   {
    1031               0 :     mState.mValueTransferInProgress = true;
    1032               0 :   }
    1033                 : 
    1034               0 :   NS_IMETHOD Run() {
    1035                 :     // Transfer the saved value to the editor if we have one
    1036               0 :     const nsAString *value = nsnull;
    1037               0 :     if (!mCurrentValue.IsEmpty()) {
    1038               0 :       value = &mCurrentValue;
    1039                 :     }
    1040                 : 
    1041               0 :     mState.PrepareEditor(value);
    1042                 : 
    1043               0 :     mState.mValueTransferInProgress = false;
    1044                 : 
    1045               0 :     return NS_OK;
    1046                 :   }
    1047                 : 
    1048                 : private:
    1049                 :   nsTextEditorState &mState;
    1050                 :   nsCOMPtr<nsIContent> mOwnerContent; // strong reference
    1051                 :   nsAutoString mCurrentValue;
    1052                 : };
    1053                 : 
    1054                 : nsresult
    1055               0 : nsTextEditorState::BindToFrame(nsTextControlFrame* aFrame)
    1056                 : {
    1057               0 :   NS_ASSERTION(aFrame, "The frame to bind to should be valid");
    1058               0 :   NS_ENSURE_ARG_POINTER(aFrame);
    1059                 : 
    1060               0 :   NS_ASSERTION(!mBoundFrame, "Cannot bind twice, need to unbind first");
    1061               0 :   NS_ENSURE_TRUE(!mBoundFrame, NS_ERROR_FAILURE);
    1062                 : 
    1063                 :   // If we'll need to transfer our current value to the editor, save it before
    1064                 :   // binding to the frame.
    1065               0 :   nsAutoString currentValue;
    1066               0 :   if (mEditor) {
    1067               0 :     GetValue(currentValue, true);
    1068                 :   }
    1069                 : 
    1070               0 :   mBoundFrame = aFrame;
    1071                 : 
    1072               0 :   nsIContent *rootNode = GetRootNode();
    1073                 : 
    1074               0 :   nsresult rv = InitializeRootNode();
    1075               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1076                 : 
    1077               0 :   nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
    1078               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
    1079                 : 
    1080                 :   // Create selection
    1081               0 :   nsRefPtr<nsFrameSelection> frameSel = new nsFrameSelection();
    1082                 : 
    1083                 :   // Create a SelectionController
    1084               0 :   mSelCon = new nsTextInputSelectionImpl(frameSel, shell, rootNode);
    1085               0 :   NS_ENSURE_TRUE(mSelCon, NS_ERROR_OUT_OF_MEMORY);
    1086               0 :   mTextListener = new nsTextInputListener(mTextCtrlElement);
    1087               0 :   NS_ENSURE_TRUE(mTextListener, NS_ERROR_OUT_OF_MEMORY);
    1088               0 :   NS_ADDREF(mTextListener);
    1089                 : 
    1090               0 :   mTextListener->SetFrame(mBoundFrame);
    1091               0 :   mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
    1092                 : 
    1093                 :   // Get the caret and make it a selection listener.
    1094               0 :   nsRefPtr<nsISelection> domSelection;
    1095               0 :   if (NS_SUCCEEDED(mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    1096                 :                                          getter_AddRefs(domSelection))) &&
    1097               0 :       domSelection) {
    1098               0 :     nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(domSelection));
    1099               0 :     nsRefPtr<nsCaret> caret = shell->GetCaret();
    1100               0 :     nsCOMPtr<nsISelectionListener> listener;
    1101               0 :     if (caret) {
    1102               0 :       listener = do_QueryInterface(caret);
    1103               0 :       if (listener) {
    1104               0 :         selPriv->AddSelectionListener(listener);
    1105                 :       }
    1106                 :     }
    1107                 : 
    1108               0 :     selPriv->AddSelectionListener(static_cast<nsISelectionListener*>
    1109               0 :                                              (mTextListener));
    1110                 :   }
    1111                 : 
    1112                 :   // If an editor exists from before, prepare it for usage
    1113               0 :   if (mEditor) {
    1114               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1115               0 :     NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
    1116                 : 
    1117                 :     // Set the correct direction on the newly created root node
    1118                 :     PRUint32 flags;
    1119               0 :     nsresult rv = mEditor->GetFlags(&flags);
    1120               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1121               0 :     if (flags & nsIPlaintextEditor::eEditorRightToLeft) {
    1122               0 :       rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), false);
    1123               0 :     } else if (flags & nsIPlaintextEditor::eEditorLeftToRight) {
    1124               0 :       rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), false);
    1125                 :     } else {
    1126                 :       // otherwise, inherit the content node's direction
    1127                 :     }
    1128                 : 
    1129               0 :     if (!nsContentUtils::AddScriptRunner(
    1130               0 :           new PrepareEditorEvent(*this, content, currentValue)))
    1131               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1132                 :   }
    1133                 : 
    1134               0 :   return NS_OK;
    1135                 : }
    1136                 : 
    1137                 : nsresult
    1138               0 : nsTextEditorState::PrepareEditor(const nsAString *aValue)
    1139                 : {
    1140               0 :   if (!mBoundFrame) {
    1141                 :     // Cannot create an editor without a bound frame.
    1142                 :     // Don't return a failure code, because js callers can't handle that.
    1143               0 :     return NS_OK;
    1144                 :   }
    1145                 : 
    1146               0 :   if (mEditorInitialized) {
    1147                 :     // Do not initialize the editor multiple times.
    1148               0 :     return NS_OK;
    1149                 :   }
    1150                 : 
    1151                 :   // Don't attempt to initialize recursively!
    1152               0 :   InitializationGuard guard(*this);
    1153               0 :   if (guard.IsInitializingRecursively()) {
    1154               0 :     return NS_ERROR_NOT_INITIALIZED;
    1155                 :   }
    1156                 : 
    1157                 :   // Note that we don't check mEditor here, because we might already have one
    1158                 :   // around, in which case we don't create a new one, and we'll just tie the
    1159                 :   // required machinery to it.
    1160                 : 
    1161               0 :   nsPresContext *presContext = mBoundFrame->PresContext();
    1162               0 :   nsIPresShell *shell = presContext->GetPresShell();
    1163                 : 
    1164                 :   // Setup the editor flags
    1165               0 :   PRUint32 editorFlags = 0;
    1166               0 :   if (IsPlainTextControl())
    1167               0 :     editorFlags |= nsIPlaintextEditor::eEditorPlaintextMask;
    1168               0 :   if (IsSingleLineTextControl())
    1169               0 :     editorFlags |= nsIPlaintextEditor::eEditorSingleLineMask;
    1170               0 :   if (IsPasswordTextControl())
    1171               0 :     editorFlags |= nsIPlaintextEditor::eEditorPasswordMask;
    1172                 : 
    1173                 :   // All nsTextControlFrames are widgets
    1174               0 :   editorFlags |= nsIPlaintextEditor::eEditorWidgetMask;
    1175                 : 
    1176                 :   // Spell check is diabled at creation time. It is enabled once
    1177                 :   // the editor comes into focus.
    1178               0 :   editorFlags |= nsIPlaintextEditor::eEditorSkipSpellCheck;
    1179                 : 
    1180               0 :   bool shouldInitializeEditor = false;
    1181               0 :   nsCOMPtr<nsIEditor> newEditor; // the editor that we might create
    1182               0 :   nsresult rv = NS_OK;
    1183               0 :   if (!mEditor) {
    1184               0 :     shouldInitializeEditor = true;
    1185                 : 
    1186                 :     // Create an editor
    1187               0 :     newEditor = do_CreateInstance(kTextEditorCID, &rv);
    1188               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1189                 : 
    1190                 :     // Make sure we clear out the non-breaking space before we initialize the editor
    1191               0 :     rv = mBoundFrame->UpdateValueDisplay(false, true);
    1192               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1193                 :   } else {
    1194               0 :     if (aValue || !mEditorInitialized) {
    1195                 :       // Set the correct value in the root node
    1196               0 :       rv = mBoundFrame->UpdateValueDisplay(true, !mEditorInitialized, aValue);
    1197               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1198                 :     }
    1199                 : 
    1200               0 :     newEditor = mEditor; // just pretend that we have a new editor!
    1201                 :   }
    1202                 : 
    1203               0 :   if (!mEditorInitialized) {
    1204                 :     // Now initialize the editor.
    1205                 :     //
    1206                 :     // NOTE: Conversion of '\n' to <BR> happens inside the
    1207                 :     //       editor's Init() call.
    1208                 : 
    1209                 :     // Get the DOM document
    1210               0 :     nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(shell->GetDocument());
    1211               0 :     if (!domdoc)
    1212               0 :       return NS_ERROR_FAILURE;
    1213                 : 
    1214                 :     // What follows is a bit of a hack.  The editor uses the public DOM APIs
    1215                 :     // for its content manipulations, and it causes it to fail some security
    1216                 :     // checks deep inside when initializing.  So we push a null JSContext
    1217                 :     // on the JS stack here to make it clear that we're native code.
    1218                 :     // Note that any script that's directly trying to access our value
    1219                 :     // has to be going through some scriptable object to do that and that
    1220                 :     // already does the relevant security checks.
    1221               0 :     nsCxPusher pusher;
    1222               0 :     pusher.PushNull();
    1223                 : 
    1224               0 :     rv = newEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags);
    1225               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1226                 :   }
    1227                 : 
    1228                 :   // Initialize the controller for the editor
    1229                 : 
    1230               0 :   if (!SuppressEventHandlers(presContext)) {
    1231               0 :     nsCOMPtr<nsIControllers> controllers;
    1232                 :     nsCOMPtr<nsIDOMHTMLInputElement> inputElement =
    1233               0 :       do_QueryInterface(mTextCtrlElement);
    1234               0 :     if (inputElement) {
    1235               0 :       rv = inputElement->GetControllers(getter_AddRefs(controllers));
    1236                 :     } else {
    1237                 :       nsCOMPtr<nsIDOMHTMLTextAreaElement> textAreaElement =
    1238               0 :         do_QueryInterface(mTextCtrlElement);
    1239                 : 
    1240               0 :       if (!textAreaElement)
    1241               0 :         return NS_ERROR_FAILURE;
    1242                 : 
    1243               0 :       rv = textAreaElement->GetControllers(getter_AddRefs(controllers));
    1244                 :     }
    1245                 : 
    1246               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1247                 : 
    1248               0 :     if (controllers) {
    1249                 :       PRUint32 numControllers;
    1250               0 :       bool found = false;
    1251               0 :       rv = controllers->GetControllerCount(&numControllers);
    1252               0 :       for (PRUint32 i = 0; i < numControllers; i ++) {
    1253               0 :         nsCOMPtr<nsIController> controller;
    1254               0 :         rv = controllers->GetControllerAt(i, getter_AddRefs(controller));
    1255               0 :         if (NS_SUCCEEDED(rv) && controller) {
    1256                 :           nsCOMPtr<nsIControllerContext> editController =
    1257               0 :             do_QueryInterface(controller);
    1258               0 :           if (editController) {
    1259               0 :             editController->SetCommandContext(newEditor);
    1260               0 :             found = true;
    1261                 :           }
    1262                 :         }
    1263                 :       }
    1264               0 :       if (!found)
    1265               0 :         rv = NS_ERROR_FAILURE;
    1266                 :     }
    1267                 :   }
    1268                 : 
    1269               0 :   if (shouldInitializeEditor) {
    1270                 :     // Initialize the plaintext editor
    1271               0 :     nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(newEditor));
    1272               0 :     if (textEditor) {
    1273                 :       // Set up wrapping
    1274               0 :       textEditor->SetWrapColumn(GetWrapCols());
    1275                 : 
    1276                 :       // Set max text field length
    1277                 :       PRInt32 maxLength;
    1278               0 :       if (GetMaxLength(&maxLength)) { 
    1279               0 :         textEditor->SetMaxTextLength(maxLength);
    1280                 :       }
    1281                 :     }
    1282                 :   }
    1283                 : 
    1284               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1285               0 :   if (content) {
    1286               0 :     rv = newEditor->GetFlags(&editorFlags);
    1287               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1288                 : 
    1289                 :     // Check if the readonly attribute is set.
    1290               0 :     if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly))
    1291               0 :       editorFlags |= nsIPlaintextEditor::eEditorReadonlyMask;
    1292                 : 
    1293                 :     // Check if the disabled attribute is set.
    1294                 :     // TODO: call IsDisabled() here!
    1295               0 :     if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) 
    1296               0 :       editorFlags |= nsIPlaintextEditor::eEditorDisabledMask;
    1297                 : 
    1298                 :     // Disable the selection if necessary.
    1299               0 :     if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
    1300               0 :       mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
    1301                 : 
    1302               0 :     newEditor->SetFlags(editorFlags);
    1303                 :   }
    1304                 : 
    1305                 :   // Get the current value of the textfield from the content.
    1306                 :   // Note that if we've created a new editor, mEditor is null at this stage,
    1307                 :   // so we will get the real value from the content.
    1308               0 :   nsAutoString defaultValue;
    1309               0 :   if (aValue) {
    1310               0 :     defaultValue = *aValue;
    1311                 :   } else {
    1312               0 :     GetValue(defaultValue, true);
    1313                 :   }
    1314                 : 
    1315               0 :   if (shouldInitializeEditor) {
    1316                 :     // Hold on to the newly created editor
    1317               0 :     mEditor = newEditor;
    1318                 :   }
    1319                 : 
    1320                 :   // If we have a default value, insert it under the div we created
    1321                 :   // above, but be sure to use the editor so that '*' characters get
    1322                 :   // displayed for password fields, etc. SetValue() will call the
    1323                 :   // editor for us.
    1324                 : 
    1325               0 :   if (!defaultValue.IsEmpty()) {
    1326               0 :     rv = newEditor->SetFlags(editorFlags);
    1327               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1328                 : 
    1329                 :     // Now call SetValue() which will make the necessary editor calls to set
    1330                 :     // the default value.  Make sure to turn off undo before setting the default
    1331                 :     // value, and turn it back on afterwards. This will make sure we can't undo
    1332                 :     // past the default value.
    1333                 : 
    1334               0 :     rv = newEditor->EnableUndo(false);
    1335               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1336                 : 
    1337               0 :     SetValue(defaultValue, false);
    1338                 : 
    1339               0 :     rv = newEditor->EnableUndo(true);
    1340               0 :     NS_ASSERTION(NS_SUCCEEDED(rv),"Transaction Manager must have failed");
    1341                 : 
    1342                 :     // Now restore the original editor flags.
    1343               0 :     rv = newEditor->SetFlags(editorFlags);
    1344               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1345                 :   }
    1346                 : 
    1347               0 :   nsCOMPtr<nsITransactionManager> transMgr;
    1348               0 :   newEditor->GetTransactionManager(getter_AddRefs(transMgr));
    1349               0 :   NS_ENSURE_TRUE(transMgr, NS_ERROR_FAILURE);
    1350                 : 
    1351               0 :   transMgr->SetMaxTransactionCount(nsITextControlElement::DEFAULT_UNDO_CAP);
    1352                 : 
    1353               0 :   if (IsPasswordTextControl()) {
    1354                 :     // Disable undo for password textfields.  Note that we want to do this at
    1355                 :     // the very end of InitEditor, so the calls to EnableUndo when setting the
    1356                 :     // default value don't screw us up.
    1357                 :     // Since changing the control type does a reframe, we don't have to worry
    1358                 :     // about dynamic type changes here.
    1359               0 :     newEditor->EnableUndo(false);
    1360                 :   }
    1361                 : 
    1362               0 :   if (!mEditorInitialized) {
    1363               0 :     newEditor->PostCreate();
    1364               0 :     mEverInited = true;
    1365               0 :     mEditorInitialized = true;
    1366                 :   }
    1367                 : 
    1368               0 :   if (mTextListener)
    1369               0 :     newEditor->AddEditorObserver(mTextListener);
    1370                 : 
    1371                 :   // Restore our selection after being bound to a new frame
    1372               0 :   if (mSelectionCached) {
    1373               0 :     if (mRestoringSelection) // paranoia
    1374               0 :       mRestoringSelection->Revoke();
    1375               0 :     mRestoringSelection = new RestoreSelectionState(this, mBoundFrame);
    1376               0 :     if (mRestoringSelection) {
    1377               0 :       nsContentUtils::AddScriptRunner(mRestoringSelection);
    1378                 :     }
    1379                 :   }
    1380                 : 
    1381                 :   // The selection cache is no longer going to be valid
    1382               0 :   mSelectionCached = false;
    1383                 : 
    1384               0 :   return rv;
    1385                 : }
    1386                 : 
    1387                 : void
    1388               2 : nsTextEditorState::DestroyEditor()
    1389                 : {
    1390                 :   // notify the editor that we are going away
    1391               2 :   if (mEditorInitialized) {
    1392               0 :     if (mTextListener)
    1393               0 :       mEditor->RemoveEditorObserver(mTextListener);
    1394                 : 
    1395               0 :     mEditor->PreDestroy(true);
    1396               0 :     mEditorInitialized = false;
    1397                 :   }
    1398               2 : }
    1399                 : 
    1400                 : void
    1401               0 : nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
    1402                 : {
    1403               0 :   NS_ENSURE_TRUE(mBoundFrame, );
    1404                 : 
    1405                 :   // If it was, however, it should be unbounded from the same frame.
    1406               0 :   NS_ASSERTION(!aFrame || aFrame == mBoundFrame, "Unbinding from the wrong frame");
    1407               0 :   NS_ENSURE_TRUE(!aFrame || aFrame == mBoundFrame, );
    1408                 : 
    1409                 :   // We need to start storing the value outside of the editor if we're not
    1410                 :   // going to use it anymore, so retrieve it for now.
    1411               0 :   nsAutoString value;
    1412               0 :   GetValue(value, true);
    1413                 : 
    1414               0 :   if (mRestoringSelection) {
    1415               0 :     mRestoringSelection->Revoke();
    1416               0 :     mRestoringSelection = nsnull;
    1417                 :   }
    1418                 : 
    1419                 :   // Save our selection state if needed.
    1420                 :   // Note that nsTextControlFrame::GetSelectionRange attempts to initialize the
    1421                 :   // editor before grabbing the range, and because this is not an acceptable
    1422                 :   // side effect for unbinding from a text control frame, we need to call
    1423                 :   // GetSelectionRange before calling DestroyEditor, and only if
    1424                 :   // mEditorInitialized indicates that we actually have an editor available.
    1425               0 :   if (mEditorInitialized) {
    1426                 :     mBoundFrame->GetSelectionRange(&mSelectionProperties.mStart,
    1427                 :                                    &mSelectionProperties.mEnd,
    1428               0 :                                    &mSelectionProperties.mDirection);
    1429               0 :     mSelectionCached = true;
    1430                 :   }
    1431                 : 
    1432                 :   // Destroy our editor
    1433               0 :   DestroyEditor();
    1434                 : 
    1435                 :   // Clean up the controller
    1436               0 :   if (!SuppressEventHandlers(mBoundFrame->PresContext()))
    1437                 :   {
    1438               0 :     nsCOMPtr<nsIControllers> controllers;
    1439                 :     nsCOMPtr<nsIDOMHTMLInputElement> inputElement =
    1440               0 :       do_QueryInterface(mTextCtrlElement);
    1441               0 :     if (inputElement)
    1442               0 :       inputElement->GetControllers(getter_AddRefs(controllers));
    1443                 :     else
    1444                 :     {
    1445                 :       nsCOMPtr<nsIDOMHTMLTextAreaElement> textAreaElement =
    1446               0 :         do_QueryInterface(mTextCtrlElement);
    1447               0 :       if (textAreaElement) {
    1448               0 :         textAreaElement->GetControllers(getter_AddRefs(controllers));
    1449                 :       }
    1450                 :     }
    1451                 : 
    1452               0 :     if (controllers)
    1453                 :     {
    1454                 :       PRUint32 numControllers;
    1455               0 :       nsresult rv = controllers->GetControllerCount(&numControllers);
    1456               0 :       NS_ASSERTION((NS_SUCCEEDED(rv)), "bad result in gfx text control destructor");
    1457               0 :       for (PRUint32 i = 0; i < numControllers; i ++)
    1458                 :       {
    1459               0 :         nsCOMPtr<nsIController> controller;
    1460               0 :         rv = controllers->GetControllerAt(i, getter_AddRefs(controller));
    1461               0 :         if (NS_SUCCEEDED(rv) && controller)
    1462                 :         {
    1463               0 :           nsCOMPtr<nsIControllerContext> editController = do_QueryInterface(controller);
    1464               0 :           if (editController)
    1465                 :           {
    1466               0 :             editController->SetCommandContext(nsnull);
    1467                 :           }
    1468                 :         }
    1469                 :       }
    1470                 :     }
    1471                 :   }
    1472                 : 
    1473               0 :   if (mSelCon) {
    1474               0 :     if (mTextListener) {
    1475               0 :       nsRefPtr<nsISelection> domSelection;
    1476               0 :       if (NS_SUCCEEDED(mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    1477                 :                                              getter_AddRefs(domSelection))) &&
    1478               0 :           domSelection) {
    1479               0 :         nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(domSelection));
    1480                 : 
    1481               0 :         selPriv->RemoveSelectionListener(static_cast<nsISelectionListener*>
    1482               0 :                                          (mTextListener));
    1483                 :       }
    1484                 :     }
    1485                 : 
    1486               0 :     mSelCon->SetScrollableFrame(nsnull);
    1487               0 :     mSelCon = nsnull;
    1488                 :   }
    1489                 : 
    1490               0 :   if (mTextListener)
    1491                 :   {
    1492               0 :     mTextListener->SetFrame(nsnull);
    1493                 : 
    1494               0 :     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTextCtrlElement);
    1495                 :     nsEventListenerManager* manager =
    1496               0 :       target->GetListenerManager(false);
    1497               0 :     if (manager) {
    1498                 :       manager->RemoveEventListenerByType(mTextListener,
    1499               0 :                                          NS_LITERAL_STRING("keydown"),
    1500                 :                                          NS_EVENT_FLAG_BUBBLE |
    1501               0 :                                          NS_EVENT_FLAG_SYSTEM_EVENT);
    1502                 :       manager->RemoveEventListenerByType(mTextListener,
    1503               0 :                                          NS_LITERAL_STRING("keypress"),
    1504                 :                                          NS_EVENT_FLAG_BUBBLE |
    1505               0 :                                          NS_EVENT_FLAG_SYSTEM_EVENT);
    1506                 :       manager->RemoveEventListenerByType(mTextListener,
    1507               0 :                                          NS_LITERAL_STRING("keyup"),
    1508                 :                                          NS_EVENT_FLAG_BUBBLE |
    1509               0 :                                          NS_EVENT_FLAG_SYSTEM_EVENT);
    1510                 :     }
    1511                 : 
    1512               0 :     NS_RELEASE(mTextListener);
    1513               0 :     mTextListener = nsnull;
    1514                 :   }
    1515                 : 
    1516               0 :   mBoundFrame = nsnull;
    1517                 : 
    1518                 :   // Now that we don't have a frame any more, store the value in the text buffer.
    1519                 :   // The only case where we don't do this is if a value transfer is in progress.
    1520               0 :   if (!mValueTransferInProgress) {
    1521               0 :     SetValue(value, false);
    1522                 :   }
    1523                 : 
    1524               0 :   if (mRootNode && mMutationObserver) {
    1525               0 :     mRootNode->RemoveMutationObserver(mMutationObserver);
    1526               0 :     mMutationObserver = nsnull;
    1527                 :   }
    1528                 : 
    1529                 :   // Unbind the anonymous content from the tree.
    1530                 :   // We actually hold a reference to the content nodes so that
    1531                 :   // they're not actually destroyed.
    1532               0 :   nsContentUtils::DestroyAnonymousContent(&mRootNode);
    1533               0 :   nsContentUtils::DestroyAnonymousContent(&mPlaceholderDiv);
    1534                 : }
    1535                 : 
    1536                 : nsresult
    1537               0 : nsTextEditorState::CreateRootNode()
    1538                 : {
    1539               0 :   NS_ENSURE_TRUE(!mRootNode, NS_ERROR_UNEXPECTED);
    1540               0 :   NS_ENSURE_ARG_POINTER(mBoundFrame);
    1541                 : 
    1542               0 :   nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
    1543               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
    1544                 : 
    1545               0 :   nsIDocument *doc = shell->GetDocument();
    1546               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    1547                 : 
    1548                 :   // Now create a DIV and add it to the anonymous content child list.
    1549               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
    1550                 :   nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nsnull,
    1551                 :                                                  kNameSpaceID_XHTML,
    1552               0 :                                                  nsIDOMNode::ELEMENT_NODE);
    1553               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    1554                 : 
    1555               0 :   nsresult rv = NS_NewHTMLElement(getter_AddRefs(mRootNode), nodeInfo.forget(),
    1556               0 :                                   NOT_FROM_PARSER);
    1557               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1558                 : 
    1559               0 :   if (!IsSingleLineTextControl()) {
    1560               0 :     mMutationObserver = new nsAnonDivObserver(this);
    1561               0 :     mRootNode->AddMutationObserver(mMutationObserver);
    1562                 :   }
    1563                 : 
    1564               0 :   return rv;
    1565                 : }
    1566                 : 
    1567                 : nsresult
    1568               0 : nsTextEditorState::InitializeRootNode()
    1569                 : {
    1570                 :   // Set the necessary classes on the text control. We use class values
    1571                 :   // instead of a 'style' attribute so that the style comes from a user-agent
    1572                 :   // style sheet and is still applied even if author styles are disabled.
    1573               0 :   nsAutoString classValue;
    1574               0 :   classValue.AppendLiteral("anonymous-div");
    1575               0 :   PRInt32 wrapCols = GetWrapCols();
    1576               0 :   if (wrapCols >= 0) {
    1577               0 :     classValue.AppendLiteral(" wrap");
    1578                 :   }
    1579               0 :   if (!IsSingleLineTextControl()) {
    1580                 :     // We can't just inherit the overflow because setting visible overflow will
    1581                 :     // crash when the number of lines exceeds the height of the textarea and
    1582                 :     // setting -moz-hidden-unscrollable overflow (NS_STYLE_OVERFLOW_CLIP)
    1583                 :     // doesn't paint the caret for some reason.
    1584               0 :     const nsStyleDisplay* disp = mBoundFrame->GetStyleDisplay();
    1585               0 :     if (disp->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
    1586                 :         disp->mOverflowX != NS_STYLE_OVERFLOW_CLIP) {
    1587               0 :       classValue.AppendLiteral(" inherit-overflow");
    1588                 :     }
    1589                 :   }
    1590                 :   nsresult rv = mRootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
    1591               0 :                                    classValue, false);
    1592               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1593                 : 
    1594               0 :   return mBoundFrame->UpdateValueDisplay(false);
    1595                 : }
    1596                 : 
    1597                 : nsresult
    1598               0 : nsTextEditorState::CreatePlaceholderNode()
    1599                 : {
    1600                 : #ifdef DEBUG
    1601                 :   {
    1602               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1603               0 :     if (content) {
    1604               0 :       nsAutoString placeholderTxt;
    1605               0 :       content->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder,
    1606               0 :                        placeholderTxt);
    1607               0 :       nsContentUtils::RemoveNewlines(placeholderTxt);
    1608               0 :       NS_ASSERTION(!placeholderTxt.IsEmpty(), "CreatePlaceholderNode() shouldn't \
    1609                 : be called if @placeholder is the empty string when trimmed from line breaks");
    1610                 :     }
    1611                 :   }
    1612                 : #endif // DEBUG
    1613                 : 
    1614               0 :   NS_ENSURE_TRUE(!mPlaceholderDiv, NS_ERROR_UNEXPECTED);
    1615               0 :   NS_ENSURE_ARG_POINTER(mBoundFrame);
    1616                 : 
    1617               0 :   nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
    1618               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
    1619                 : 
    1620               0 :   nsIDocument *doc = shell->GetDocument();
    1621               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    1622                 : 
    1623               0 :   nsNodeInfoManager* pNodeInfoManager = doc->NodeInfoManager();
    1624               0 :   NS_ENSURE_TRUE(pNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
    1625                 : 
    1626                 :   nsresult rv;
    1627               0 :   nsCOMPtr<nsIContent> placeholderText;
    1628                 : 
    1629                 :   // Create a DIV for the placeholder
    1630                 :   // and add it to the anonymous content child list
    1631               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
    1632                 :   nodeInfo = pNodeInfoManager->GetNodeInfo(nsGkAtoms::div, nsnull,
    1633                 :                                            kNameSpaceID_XHTML,
    1634               0 :                                            nsIDOMNode::ELEMENT_NODE);
    1635               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    1636                 : 
    1637               0 :   rv = NS_NewHTMLElement(getter_AddRefs(mPlaceholderDiv), nodeInfo.forget(),
    1638               0 :                          NOT_FROM_PARSER);
    1639               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1640                 : 
    1641                 :   // Create the text node for the placeholder text before doing anything else
    1642               0 :   rv = NS_NewTextNode(getter_AddRefs(placeholderText), pNodeInfoManager);
    1643               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1644                 : 
    1645               0 :   rv = mPlaceholderDiv->AppendChildTo(placeholderText, false);
    1646               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1647                 : 
    1648                 :   // initialize the text
    1649               0 :   UpdatePlaceholderText(false);
    1650                 : 
    1651               0 :   return NS_OK;
    1652                 : }
    1653                 : 
    1654                 : bool
    1655               0 : nsTextEditorState::GetMaxLength(PRInt32* aMaxLength)
    1656                 : {
    1657               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1658               0 :   NS_ENSURE_TRUE(content, false);
    1659               0 :   nsGenericHTMLElement* element = nsGenericHTMLElement::FromContent(content);
    1660               0 :   NS_ENSURE_TRUE(element, false);
    1661                 : 
    1662               0 :   const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::maxlength);
    1663               0 :   if (attr && attr->Type() == nsAttrValue::eInteger) {
    1664               0 :     *aMaxLength = attr->GetIntegerValue();
    1665                 : 
    1666               0 :     return true;
    1667                 :   }
    1668                 : 
    1669               0 :   return false;
    1670                 : }
    1671                 : 
    1672                 : void
    1673               1 : nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
    1674                 : {
    1675               1 :   if (mEditor && mBoundFrame && (mEditorInitialized || !IsSingleLineTextControl())) {
    1676               0 :     bool canCache = aIgnoreWrap && !IsSingleLineTextControl();
    1677               0 :     if (canCache && !mCachedValue.IsEmpty()) {
    1678               0 :       aValue = mCachedValue;
    1679               0 :       return;
    1680                 :     }
    1681                 : 
    1682               0 :     aValue.Truncate(); // initialize out param
    1683                 : 
    1684                 :     PRUint32 flags = (nsIDocumentEncoder::OutputLFLineBreak |
    1685                 :                       nsIDocumentEncoder::OutputPreformatted |
    1686               0 :                       nsIDocumentEncoder::OutputPersistNBSP);
    1687                 : 
    1688               0 :     if (IsPlainTextControl())
    1689                 :     {
    1690               0 :       flags |= nsIDocumentEncoder::OutputBodyOnly;
    1691                 :     }
    1692                 : 
    1693               0 :     if (!aIgnoreWrap) {
    1694                 :       nsITextControlElement::nsHTMLTextWrap wrapProp;
    1695               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1696               0 :       if (content &&
    1697               0 :           nsITextControlElement::GetWrapPropertyEnum(content, wrapProp) &&
    1698                 :           wrapProp == nsITextControlElement::eHTMLTextWrap_Hard) {
    1699               0 :         flags |= nsIDocumentEncoder::OutputWrap;
    1700                 :       }
    1701                 :     }
    1702                 : 
    1703                 :     // What follows is a bit of a hack.  The problem is that we could be in
    1704                 :     // this method because we're being destroyed for whatever reason while
    1705                 :     // script is executing.  If that happens, editor will run with the
    1706                 :     // privileges of the executing script, which means it may not be able to
    1707                 :     // access its own DOM nodes!  Let's try to deal with that by pushing a null
    1708                 :     // JSContext on the JSContext stack to make it clear that we're native
    1709                 :     // code.  Note that any script that's directly trying to access our value
    1710                 :     // has to be going through some scriptable object to do that and that
    1711                 :     // already does the relevant security checks.
    1712                 :     // XXXbz if we could just get the textContent of our anonymous content (eg
    1713                 :     // if plaintext editor didn't create <br> nodes all over), we wouldn't need
    1714                 :     // this.
    1715                 :     { /* Scope for context pusher */
    1716               0 :       nsCxPusher pusher;
    1717               0 :       pusher.PushNull();
    1718                 : 
    1719               0 :       mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags,
    1720               0 :                               aValue);
    1721                 :     }
    1722               0 :     if (canCache) {
    1723               0 :       mCachedValue = aValue;
    1724                 :     } else {
    1725               0 :       mCachedValue.Truncate();
    1726                 :     }
    1727                 :   } else {
    1728               1 :     if (!mTextCtrlElement->ValueChanged() || !mValue) {
    1729               1 :       mTextCtrlElement->GetDefaultValueFromContent(aValue);
    1730                 :     } else {
    1731               0 :       aValue = NS_ConvertUTF8toUTF16(*mValue);
    1732                 :     }
    1733                 :   }
    1734                 : }
    1735                 : 
    1736                 : void
    1737               1 : nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput)
    1738                 : {
    1739               1 :   if (mEditor && mBoundFrame) {
    1740                 :     // The InsertText call below might flush pending notifications, which
    1741                 :     // could lead into a scheduled PrepareEditor to be called.  That will
    1742                 :     // lead to crashes (or worse) because we'd be initializing the editor
    1743                 :     // before InsertText returns.  This script blocker makes sure that
    1744                 :     // PrepareEditor cannot be called prematurely.
    1745               0 :     nsAutoScriptBlocker scriptBlocker;
    1746                 : 
    1747               0 :     bool fireChangeEvent = mBoundFrame->GetFireChangeEventState();
    1748               0 :     if (aUserInput) {
    1749               0 :       mBoundFrame->SetFireChangeEventState(true);
    1750                 :     }
    1751                 : 
    1752                 : #ifdef DEBUG
    1753               0 :     if (IsSingleLineTextControl()) {
    1754               0 :       NS_ASSERTION(mEditorInitialized || mInitializing,
    1755                 :                    "We should never try to use the editor if we're not initialized unless we're being initialized");
    1756                 :     }
    1757                 : #endif
    1758                 : 
    1759               0 :     nsAutoString currentValue;
    1760               0 :     if (!mEditorInitialized && IsSingleLineTextControl()) {
    1761                 :       // Grab the current value directly from the text node to make sure that we
    1762                 :       // deal with stale data correctly.
    1763               0 :       NS_ASSERTION(mRootNode, "We should have a root node here");
    1764               0 :       nsIContent *textContent = mRootNode->GetFirstChild();
    1765               0 :       nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(textContent);
    1766               0 :       if (textNode) {
    1767               0 :         textNode->GetData(currentValue);
    1768                 :       }
    1769                 :     } else {
    1770               0 :       mBoundFrame->GetText(currentValue);
    1771                 :     }
    1772                 : 
    1773               0 :     nsWeakFrame weakFrame(mBoundFrame);
    1774                 : 
    1775                 :     // this is necessary to avoid infinite recursion
    1776               0 :     if (!currentValue.Equals(aValue))
    1777                 :     {
    1778                 :       nsTextControlFrame::ValueSetter valueSetter(mBoundFrame,
    1779               0 :                                                   mBoundFrame->mFocusedValue.Equals(currentValue));
    1780                 : 
    1781                 :       // \r is an illegal character in the dom, but people use them,
    1782                 :       // so convert windows and mac platform linebreaks to \n:
    1783                 :       // Unfortunately aValue is declared const, so we have to copy
    1784                 :       // in order to do this substitution.
    1785               0 :       nsString newValue(aValue);
    1786               0 :       if (aValue.FindChar(PRUnichar('\r')) != -1) {
    1787               0 :         nsContentUtils::PlatformToDOMLineBreaks(newValue);
    1788                 :       }
    1789                 : 
    1790               0 :       nsCOMPtr<nsIDOMDocument> domDoc;
    1791               0 :       mEditor->GetDocument(getter_AddRefs(domDoc));
    1792               0 :       if (!domDoc) {
    1793               0 :         NS_WARNING("Why don't we have a document?");
    1794                 :         return;
    1795                 :       }
    1796                 : 
    1797                 :       // Time to mess with our security context... See comments in GetValue()
    1798                 :       // for why this is needed.  Note that we have to do this up here, because
    1799                 :       // otherwise SelectAll() will fail.
    1800                 :       { /* Scope for context pusher */
    1801               0 :         nsCxPusher pusher;
    1802               0 :         pusher.PushNull();
    1803                 : 
    1804               0 :         nsCOMPtr<nsISelection> domSel;
    1805               0 :         nsCOMPtr<nsISelectionPrivate> selPriv;
    1806               0 :         mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    1807               0 :                               getter_AddRefs(domSel));
    1808               0 :         if (domSel)
    1809                 :         {
    1810               0 :           selPriv = do_QueryInterface(domSel);
    1811               0 :           if (selPriv)
    1812               0 :             selPriv->StartBatchChanges();
    1813                 :         }
    1814                 : 
    1815               0 :         nsCOMPtr<nsISelectionController> kungFuDeathGrip = mSelCon.get();
    1816               0 :         PRUint32 currentLength = currentValue.Length();
    1817               0 :         PRUint32 newlength = newValue.Length();
    1818               0 :         if (!currentLength ||
    1819               0 :             !StringBeginsWith(newValue, currentValue)) {
    1820                 :           // Replace the whole text.
    1821               0 :           currentLength = 0;
    1822               0 :           mSelCon->SelectAll();
    1823                 :         } else {
    1824                 :           // Collapse selection to the end so that we can append data.
    1825               0 :           mBoundFrame->SelectAllOrCollapseToEndOfText(false);
    1826                 :         }
    1827                 :         const nsAString& insertValue =
    1828               0 :           StringTail(newValue, newlength - currentLength);
    1829               0 :         nsCOMPtr<nsIPlaintextEditor> plaintextEditor = do_QueryInterface(mEditor);
    1830               0 :         if (!plaintextEditor || !weakFrame.IsAlive()) {
    1831               0 :           NS_WARNING("Somehow not a plaintext editor?");
    1832                 :           return;
    1833                 :         }
    1834                 : 
    1835               0 :         valueSetter.Init();
    1836                 : 
    1837                 :         // get the flags, remove readonly and disabled, set the value,
    1838                 :         // restore flags
    1839                 :         PRUint32 flags, savedFlags;
    1840               0 :         mEditor->GetFlags(&savedFlags);
    1841               0 :         flags = savedFlags;
    1842               0 :         flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
    1843               0 :         flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
    1844               0 :         flags |= nsIPlaintextEditor::eEditorDontEchoPassword;
    1845               0 :         mEditor->SetFlags(flags);
    1846                 : 
    1847               0 :         mTextListener->SettingValue(true);
    1848                 : 
    1849                 :         // Also don't enforce max-length here
    1850                 :         PRInt32 savedMaxLength;
    1851               0 :         plaintextEditor->GetMaxTextLength(&savedMaxLength);
    1852               0 :         plaintextEditor->SetMaxTextLength(-1);
    1853                 : 
    1854               0 :         if (insertValue.IsEmpty()) {
    1855               0 :           mEditor->DeleteSelection(nsIEditor::eNone);
    1856                 :         } else {
    1857               0 :           plaintextEditor->InsertText(insertValue);
    1858                 :         }
    1859                 : 
    1860               0 :         mTextListener->SettingValue(false);
    1861                 : 
    1862               0 :         if (!weakFrame.IsAlive()) {
    1863                 :           // If the frame was destroyed because of a flush somewhere inside
    1864                 :           // InsertText, mBoundFrame here will be false.  But it's also possible
    1865                 :           // for the frame to go away because of another reason (such as deleting
    1866                 :           // the existing selection -- see bug 574558), in which case we don't
    1867                 :           // need to reset the value here.
    1868               0 :           if (!mBoundFrame) {
    1869               0 :             SetValue(newValue, false);
    1870                 :           }
    1871               0 :           valueSetter.Cancel();
    1872                 :           return;
    1873                 :         }
    1874                 : 
    1875               0 :         if (!IsSingleLineTextControl()) {
    1876               0 :           mCachedValue = newValue;
    1877                 :         }
    1878                 : 
    1879               0 :         plaintextEditor->SetMaxTextLength(savedMaxLength);
    1880               0 :         mEditor->SetFlags(savedFlags);
    1881               0 :         if (selPriv)
    1882               0 :           selPriv->EndBatchChanges();
    1883                 :       }
    1884                 :     }
    1885                 : 
    1886                 :     // This second check _shouldn't_ be necessary, but let's be safe.
    1887               0 :     if (!weakFrame.IsAlive()) {
    1888                 :       return;
    1889                 :     }
    1890               0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(mBoundFrame->GetFirstPrincipalChild());
    1891               0 :     if (scrollableFrame)
    1892                 :     {
    1893                 :       // Scroll the upper left corner of the text control's
    1894                 :       // content area back into view.
    1895               0 :       scrollableFrame->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
    1896                 :     }
    1897                 : 
    1898               0 :     if (aUserInput) {
    1899               0 :       mBoundFrame->SetFireChangeEventState(fireChangeEvent);
    1900                 :     }
    1901                 :   } else {
    1902               1 :     if (!mValue) {
    1903               1 :       mValue = new nsCString;
    1904                 :     }
    1905               2 :     nsString value(aValue);
    1906               1 :     nsContentUtils::PlatformToDOMLineBreaks(value);
    1907               1 :     CopyUTF16toUTF8(value, *mValue);
    1908                 : 
    1909                 :     // Update the frame display if needed
    1910               1 :     if (mBoundFrame) {
    1911               0 :       mBoundFrame->UpdateValueDisplay(true);
    1912                 :     }
    1913                 :   }
    1914                 : 
    1915                 :   // If we've reached the point where the root node has been created, we
    1916                 :   // can assume that it's safe to notify.
    1917               1 :   ValueWasChanged(!!mRootNode);
    1918                 : 
    1919               1 :   mTextCtrlElement->OnValueChanged(!!mRootNode);
    1920                 : }
    1921                 : 
    1922                 : void
    1923               0 : nsTextEditorState::InitializeKeyboardEventListeners()
    1924                 : {
    1925                 :   //register key listeners
    1926               0 :   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTextCtrlElement);
    1927               0 :   nsEventListenerManager* manager = target->GetListenerManager(true);
    1928               0 :   if (manager) {
    1929                 :     manager->AddEventListenerByType(mTextListener,
    1930               0 :                                     NS_LITERAL_STRING("keydown"),
    1931                 :                                     NS_EVENT_FLAG_BUBBLE |
    1932               0 :                                     NS_EVENT_FLAG_SYSTEM_EVENT);
    1933                 :     manager->AddEventListenerByType(mTextListener,
    1934               0 :                                     NS_LITERAL_STRING("keypress"),
    1935                 :                                     NS_EVENT_FLAG_BUBBLE |
    1936               0 :                                     NS_EVENT_FLAG_SYSTEM_EVENT);
    1937                 :     manager->AddEventListenerByType(mTextListener,
    1938               0 :                                     NS_LITERAL_STRING("keyup"),
    1939                 :                                     NS_EVENT_FLAG_BUBBLE |
    1940               0 :                                     NS_EVENT_FLAG_SYSTEM_EVENT);
    1941                 :   }
    1942                 : 
    1943               0 :   mSelCon->SetScrollableFrame(do_QueryFrame(mBoundFrame->GetFirstPrincipalChild()));
    1944               0 : }
    1945                 : 
    1946                 : /* static */ void
    1947            1403 : nsTextEditorState::ShutDown()
    1948                 : {
    1949            1403 :   NS_IF_RELEASE(sNativeTextAreaBindings);
    1950            1403 :   NS_IF_RELEASE(sNativeInputBindings);
    1951            1403 : }
    1952                 : 
    1953                 : void
    1954               1 : nsTextEditorState::ValueWasChanged(bool aNotify)
    1955                 : {
    1956                 :   // placeholder management
    1957               1 :   if (!mPlaceholderDiv) {
    1958               1 :     return;
    1959                 :   }
    1960                 : 
    1961               0 :   bool showPlaceholder = false;
    1962               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1963               0 :   if (!nsContentUtils::IsFocusedContent(content)) {
    1964                 :     // If the content is focused, we don't care about the changes because
    1965                 :     // the placeholder is going to be hidden/shown on blur.
    1966               0 :     nsAutoString valueString;
    1967               0 :     GetValue(valueString, true);
    1968               0 :     showPlaceholder = valueString.IsEmpty();
    1969                 :   }
    1970               0 :   SetPlaceholderClass(showPlaceholder, aNotify);
    1971                 : }
    1972                 : 
    1973                 : void
    1974               0 : nsTextEditorState::UpdatePlaceholderText(bool aNotify)
    1975                 : {
    1976               0 :   NS_ASSERTION(mPlaceholderDiv, "This function should not be called if "
    1977                 :                                 "mPlaceholderDiv isn't set");
    1978                 : 
    1979                 :   // If we don't have a placeholder div, there's nothing to do.
    1980               0 :   if (!mPlaceholderDiv)
    1981               0 :     return;
    1982                 : 
    1983               0 :   nsAutoString placeholderValue;
    1984                 : 
    1985               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    1986               0 :   content->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, placeholderValue);
    1987               0 :   nsContentUtils::RemoveNewlines(placeholderValue);
    1988               0 :   NS_ASSERTION(mPlaceholderDiv->GetFirstChild(), "placeholder div has no child");
    1989               0 :   mPlaceholderDiv->GetFirstChild()->SetText(placeholderValue, aNotify);
    1990               0 :   ValueWasChanged(aNotify);
    1991                 : }
    1992                 : 
    1993                 : void
    1994               0 : nsTextEditorState::SetPlaceholderClass(bool aVisible,
    1995                 :                                        bool aNotify)
    1996                 : {
    1997               0 :   NS_ASSERTION(mPlaceholderDiv, "This function should not be called if "
    1998                 :                                 "mPlaceholderDiv isn't set");
    1999                 : 
    2000                 :   // No need to do anything if we don't have a frame yet
    2001               0 :   if (!mBoundFrame)
    2002               0 :     return;
    2003                 : 
    2004               0 :   nsAutoString classValue;
    2005                 : 
    2006               0 :   classValue.Assign(NS_LITERAL_STRING("anonymous-div placeholder"));
    2007                 : 
    2008               0 :   if (!aVisible)
    2009               0 :     classValue.AppendLiteral(" hidden");
    2010                 : 
    2011               0 :   nsIContent* placeholderDiv = GetPlaceholderNode();
    2012               0 :   NS_ENSURE_TRUE(placeholderDiv, );
    2013                 : 
    2014                 :   placeholderDiv->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
    2015               0 :                           classValue, aNotify);
    2016                 : }
    2017                 : 
    2018                 : void
    2019               0 : nsTextEditorState::HideSelectionIfBlurred()
    2020                 : {
    2021               0 :   NS_ABORT_IF_FALSE(mSelCon, "Should have a selection controller if we have a frame!");
    2022               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
    2023               0 :   if (!nsContentUtils::IsFocusedContent(content)) {
    2024               0 :     mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
    2025                 :   }
    2026               0 : }
    2027                 : 
    2028               0 : NS_IMPL_ISUPPORTS1(nsAnonDivObserver, nsIMutationObserver)
    2029                 : 
    2030                 : void
    2031               0 : nsAnonDivObserver::CharacterDataChanged(nsIDocument*             aDocument,
    2032                 :                                         nsIContent*              aContent,
    2033                 :                                         CharacterDataChangeInfo* aInfo)
    2034                 : {
    2035               0 :   mTextEditorState->ClearValueCache();
    2036               0 : }
    2037                 : 
    2038                 : void
    2039               0 : nsAnonDivObserver::ContentAppended(nsIDocument* aDocument,
    2040                 :                                    nsIContent*  aContainer,
    2041                 :                                    nsIContent*  aFirstNewContent,
    2042                 :                                    PRInt32      /* unused */)
    2043                 : {
    2044               0 :   mTextEditorState->ClearValueCache();
    2045               0 : }
    2046                 : 
    2047                 : void
    2048               0 : nsAnonDivObserver::ContentInserted(nsIDocument* aDocument,
    2049                 :                                    nsIContent*  aContainer,
    2050                 :                                    nsIContent*  aChild,
    2051                 :                                    PRInt32      /* unused */)
    2052                 : {
    2053               0 :   mTextEditorState->ClearValueCache();
    2054               0 : }
    2055                 : 
    2056                 : void
    2057               0 : nsAnonDivObserver::ContentRemoved(nsIDocument* aDocument,
    2058                 :                                   nsIContent*  aContainer,
    2059                 :                                   nsIContent*  aChild,
    2060                 :                                   PRInt32      aIndexInContainer,
    2061                 :                                   nsIContent*  aPreviousSibling)
    2062                 : {
    2063               0 :   mTextEditorState->ClearValueCache();
    2064            4392 : }

Generated by: LCOV version 1.7