LCOV - code coverage report
Current view: directory - content/events/src - nsIMEStateManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 341 0 0.0 %
Date: 2012-06-02 Functions: 39 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=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 code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Mozilla Japan.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      25                 :  *   Ningjie Chen <chenn@email.uc.edu>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsIMEStateManager.h"
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsIViewManager.h"
      44                 : #include "nsIPresShell.h"
      45                 : #include "nsISupports.h"
      46                 : #include "nsPIDOMWindow.h"
      47                 : #include "nsIInterfaceRequestorUtils.h"
      48                 : #include "nsIEditorDocShell.h"
      49                 : #include "nsIContent.h"
      50                 : #include "nsIDocument.h"
      51                 : #include "nsPresContext.h"
      52                 : #include "nsIDOMWindow.h"
      53                 : #include "nsIDOMMouseEvent.h"
      54                 : #include "nsIDOMNSEvent.h"
      55                 : #include "nsContentUtils.h"
      56                 : #include "nsINode.h"
      57                 : #include "nsIFrame.h"
      58                 : #include "nsRange.h"
      59                 : #include "nsIDOMRange.h"
      60                 : #include "nsISelection.h"
      61                 : #include "nsISelectionPrivate.h"
      62                 : #include "nsISelectionListener.h"
      63                 : #include "nsISelectionController.h"
      64                 : #include "nsIMutationObserver.h"
      65                 : #include "nsContentEventHandler.h"
      66                 : #include "nsIObserverService.h"
      67                 : #include "mozilla/Services.h"
      68                 : #include "nsIFormControl.h"
      69                 : #include "nsIForm.h"
      70                 : #include "nsHTMLFormElement.h"
      71                 : 
      72                 : using namespace mozilla::widget;
      73                 : 
      74                 : /******************************************************************/
      75                 : /* nsIMEStateManager                                              */
      76                 : /******************************************************************/
      77                 : 
      78                 : nsIContent*    nsIMEStateManager::sContent      = nsnull;
      79                 : nsPresContext* nsIMEStateManager::sPresContext  = nsnull;
      80                 : bool           nsIMEStateManager::sInstalledMenuKeyboardListener = false;
      81                 : bool           nsIMEStateManager::sInSecureInputMode = false;
      82                 : 
      83                 : nsTextStateManager* nsIMEStateManager::sTextStateObserver = nsnull;
      84                 : 
      85                 : nsresult
      86               0 : nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
      87                 : {
      88               0 :   NS_ENSURE_ARG_POINTER(aPresContext);
      89               0 :   if (aPresContext != sPresContext)
      90               0 :     return NS_OK;
      91               0 :   nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
      92               0 :   if (widget) {
      93               0 :     IMEState newState = GetNewIMEState(sPresContext, nsnull);
      94                 :     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
      95               0 :                               InputContextAction::LOST_FOCUS);
      96               0 :     SetIMEState(newState, nsnull, widget, action);
      97                 :   }
      98               0 :   sContent = nsnull;
      99               0 :   sPresContext = nsnull;
     100               0 :   OnTextStateBlur(nsnull, nsnull);
     101               0 :   return NS_OK;
     102                 : }
     103                 : 
     104                 : nsresult
     105               0 : nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
     106                 :                                    nsIContent* aContent)
     107                 : {
     108               0 :   NS_ENSURE_ARG_POINTER(aPresContext);
     109               0 :   if (!sPresContext || !sContent ||
     110                 :       aPresContext != sPresContext ||
     111                 :       aContent != sContent)
     112               0 :     return NS_OK;
     113                 : 
     114                 :   // Current IME transaction should commit
     115               0 :   nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
     116               0 :   if (widget) {
     117               0 :     nsresult rv = widget->CancelIMEComposition();
     118               0 :     if (NS_FAILED(rv))
     119               0 :       widget->ResetInputState();
     120               0 :     IMEState newState = GetNewIMEState(sPresContext, nsnull);
     121                 :     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
     122               0 :                               InputContextAction::LOST_FOCUS);
     123               0 :     SetIMEState(newState, nsnull, widget, action);
     124                 :   }
     125                 : 
     126               0 :   sContent = nsnull;
     127               0 :   sPresContext = nsnull;
     128                 : 
     129               0 :   return NS_OK;
     130                 : }
     131                 : 
     132                 : nsresult
     133               0 : nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
     134                 :                                  nsIContent* aContent,
     135                 :                                  InputContextAction::Cause aCause)
     136                 : {
     137               0 :   InputContextAction action(aCause);
     138               0 :   return OnChangeFocusInternal(aPresContext, aContent, action);
     139                 : }
     140                 : 
     141                 : nsresult
     142               0 : nsIMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
     143                 :                                          nsIContent* aContent,
     144                 :                                          InputContextAction aAction)
     145                 : {
     146               0 :   NS_ENSURE_ARG_POINTER(aPresContext);
     147                 : 
     148               0 :   nsCOMPtr<nsIWidget> widget = GetWidget(aPresContext);
     149               0 :   if (!widget) {
     150               0 :     return NS_OK;
     151                 :   }
     152                 : 
     153                 :   // Handle secure input mode for password field input.
     154               0 :   bool contentIsPassword = false;
     155               0 :   if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML) {
     156               0 :     if (aContent->Tag() == nsGkAtoms::input) {
     157               0 :       nsAutoString type;
     158               0 :       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
     159               0 :       contentIsPassword = type.LowerCaseEqualsLiteral("password");
     160                 :     }
     161                 :   }
     162               0 :   if (sInSecureInputMode) {
     163               0 :     if (!contentIsPassword) {
     164               0 :       if (NS_SUCCEEDED(widget->EndSecureKeyboardInput())) {
     165               0 :         sInSecureInputMode = false;
     166                 :       }
     167                 :     }
     168                 :   } else {
     169               0 :     if (contentIsPassword) {
     170               0 :       if (NS_SUCCEEDED(widget->BeginSecureKeyboardInput())) {
     171               0 :         sInSecureInputMode = true;
     172                 :       }
     173                 :     }
     174                 :   }
     175                 : 
     176               0 :   IMEState newState = GetNewIMEState(aPresContext, aContent);
     177               0 :   if (aPresContext == sPresContext && aContent == sContent) {
     178                 :     // actual focus isn't changing, but if IME enabled state is changing,
     179                 :     // we should do it.
     180               0 :     InputContext context = widget->GetInputContext();
     181               0 :     if (context.mIMEState.mEnabled == newState.mEnabled) {
     182                 :       // the enabled state isn't changing.
     183               0 :       return NS_OK;
     184                 :     }
     185               0 :     aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
     186               0 :   } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
     187                 :     // If aContent isn't null or aContent is null but editable, somebody gets
     188                 :     // focus.
     189               0 :     bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
     190                 :     aAction.mFocusChange =
     191               0 :       gotFocus ? InputContextAction::GOT_FOCUS : InputContextAction::LOST_FOCUS;
     192                 :   }
     193                 : 
     194                 :   // Current IME transaction should commit
     195               0 :   if (sPresContext) {
     196               0 :     nsCOMPtr<nsIWidget> oldWidget;
     197               0 :     if (sPresContext == aPresContext)
     198               0 :       oldWidget = widget;
     199                 :     else
     200               0 :       oldWidget = GetWidget(sPresContext);
     201               0 :     if (oldWidget)
     202               0 :       oldWidget->ResetInputState();
     203                 :   }
     204                 : 
     205                 :   // Update IME state for new focus widget
     206               0 :   SetIMEState(newState, aContent, widget, aAction);
     207                 : 
     208               0 :   sPresContext = aPresContext;
     209               0 :   sContent = aContent;
     210                 : 
     211               0 :   return NS_OK;
     212                 : }
     213                 : 
     214                 : void
     215               0 : nsIMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
     216                 : {
     217               0 :   sInstalledMenuKeyboardListener = aInstalling;
     218                 : 
     219                 :   InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
     220                 :     aInstalling ? InputContextAction::MENU_GOT_PSEUDO_FOCUS :
     221               0 :                   InputContextAction::MENU_LOST_PSEUDO_FOCUS);
     222               0 :   OnChangeFocusInternal(sPresContext, sContent, action);
     223               0 : }
     224                 : 
     225                 : void
     226               0 : nsIMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
     227                 :                                    nsIContent* aContent,
     228                 :                                    nsIDOMMouseEvent* aMouseEvent)
     229                 : {
     230               0 :   if (sPresContext != aPresContext || sContent != aContent) {
     231               0 :     return;
     232                 :   }
     233                 : 
     234               0 :   nsCOMPtr<nsIWidget> widget = GetWidget(aPresContext);
     235               0 :   NS_ENSURE_TRUE(widget, );
     236                 : 
     237                 :   bool isTrusted;
     238               0 :   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aMouseEvent);
     239               0 :   nsresult rv = NSEvent->GetIsTrusted(&isTrusted);
     240               0 :   NS_ENSURE_SUCCESS(rv, );
     241               0 :   if (!isTrusted) {
     242                 :     return; // ignore untrusted event.
     243                 :   }
     244                 : 
     245                 :   PRUint16 button;
     246               0 :   rv = aMouseEvent->GetButton(&button);
     247               0 :   NS_ENSURE_SUCCESS(rv, );
     248               0 :   if (button != 0) {
     249                 :     return; // not a left click event.
     250                 :   }
     251                 : 
     252                 :   PRInt32 clickCount;
     253               0 :   rv = aMouseEvent->GetDetail(&clickCount);
     254               0 :   NS_ENSURE_SUCCESS(rv, );
     255               0 :   if (clickCount != 1) {
     256                 :     return; // should notify only first click event.
     257                 :   }
     258                 : 
     259                 :   InputContextAction action(InputContextAction::CAUSE_MOUSE,
     260               0 :                             InputContextAction::FOCUS_NOT_CHANGED);
     261               0 :   IMEState newState = GetNewIMEState(aPresContext, aContent);
     262               0 :   SetIMEState(newState, aContent, widget, action);
     263                 : }
     264                 : 
     265                 : void
     266               0 : nsIMEStateManager::UpdateIMEState(const IMEState &aNewIMEState,
     267                 :                                   nsIContent* aContent)
     268                 : {
     269               0 :   if (!sPresContext) {
     270               0 :     NS_WARNING("ISM doesn't know which editor has focus");
     271               0 :     return;
     272                 :   }
     273               0 :   nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
     274               0 :   if (!widget) {
     275               0 :     NS_WARNING("focused widget is not found");
     276                 :     return;
     277                 :   }
     278                 : 
     279                 :   // Don't update IME state when enabled state isn't actually changed.
     280               0 :   InputContext context = widget->GetInputContext();
     281               0 :   if (context.mIMEState.mEnabled == aNewIMEState.mEnabled) {
     282                 :     return;
     283                 :   }
     284                 : 
     285                 :   // commit current composition
     286               0 :   widget->ResetInputState();
     287                 : 
     288                 :   InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
     289               0 :                             InputContextAction::FOCUS_NOT_CHANGED);
     290               0 :   SetIMEState(aNewIMEState, aContent, widget, action);
     291                 : }
     292                 : 
     293                 : IMEState
     294               0 : nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
     295                 :                                   nsIContent*    aContent)
     296                 : {
     297                 :   // On Printing or Print Preview, we don't need IME.
     298               0 :   if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
     299               0 :       aPresContext->Type() == nsPresContext::eContext_Print) {
     300               0 :     return IMEState(IMEState::DISABLED);
     301                 :   }
     302                 : 
     303               0 :   if (sInstalledMenuKeyboardListener) {
     304               0 :     return IMEState(IMEState::DISABLED);
     305                 :   }
     306                 : 
     307               0 :   if (!aContent) {
     308                 :     // Even if there are no focused content, the focused document might be
     309                 :     // editable, such case is design mode.
     310               0 :     nsIDocument* doc = aPresContext->Document();
     311               0 :     if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
     312               0 :       return IMEState(IMEState::ENABLED);
     313                 :     }
     314               0 :     return IMEState(IMEState::DISABLED);
     315                 :   }
     316                 : 
     317               0 :   return aContent->GetDesiredIMEState();
     318                 : }
     319                 : 
     320                 : // Helper class, used for IME enabled state change notification
     321               0 : class IMEEnabledStateChangedEvent : public nsRunnable {
     322                 : public:
     323               0 :   IMEEnabledStateChangedEvent(PRUint32 aState)
     324               0 :     : mState(aState)
     325                 :   {
     326               0 :   }
     327                 : 
     328               0 :   NS_IMETHOD Run() {
     329               0 :     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
     330               0 :     if (observerService) {
     331               0 :       nsAutoString state;
     332               0 :       state.AppendInt(mState);
     333               0 :       observerService->NotifyObservers(nsnull, "ime-enabled-state-changed", state.get());
     334                 :     }
     335               0 :     return NS_OK;
     336                 :   }
     337                 : 
     338                 : private:
     339                 :   PRUint32 mState;
     340                 : };
     341                 : 
     342                 : void
     343               0 : nsIMEStateManager::SetIMEState(const IMEState &aState,
     344                 :                                nsIContent* aContent,
     345                 :                                nsIWidget* aWidget,
     346                 :                                InputContextAction aAction)
     347                 : {
     348               0 :   NS_ENSURE_TRUE(aWidget, );
     349                 : 
     350               0 :   InputContext oldContext = aWidget->GetInputContext();
     351                 : 
     352               0 :   InputContext context;
     353               0 :   context.mIMEState = aState;
     354                 : 
     355               0 :   if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
     356               0 :       (aContent->Tag() == nsGkAtoms::input ||
     357               0 :        aContent->Tag() == nsGkAtoms::textarea)) {
     358                 :     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
     359               0 :                       context.mHTMLInputType);
     360                 :     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
     361               0 :                       context.mActionHint);
     362                 : 
     363                 :     // if we don't have an action hint and  return won't submit the form use "next"
     364               0 :     if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) {
     365               0 :       bool willSubmit = false;
     366               0 :       nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
     367               0 :       mozilla::dom::Element* formElement = control->GetFormElement();
     368               0 :       nsCOMPtr<nsIForm> form;
     369               0 :       if (control) {
     370                 :         // is this a form and does it have a default submit element?
     371               0 :         if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) {
     372               0 :           willSubmit = true;
     373                 :         // is this an html form and does it only have a single text input element?
     374               0 :         } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() &&
     375               0 :                    static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) {
     376               0 :           willSubmit = true;
     377                 :         }
     378                 :       }
     379               0 :       context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH
     380               0 :                                                 ? NS_LITERAL_STRING("search")
     381               0 :                                                 : NS_LITERAL_STRING("go")
     382                 :                                             : formElement
     383               0 :                                                 ? NS_LITERAL_STRING("next")
     384               0 :                                                 : EmptyString());
     385                 :     }
     386                 :   }
     387                 : 
     388                 :   // XXX I think that we should use nsContentUtils::IsCallerChrome() instead
     389                 :   //     of the process type.
     390               0 :   if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
     391               0 :       XRE_GetProcessType() != GeckoProcessType_Content) {
     392               0 :     aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
     393                 :   }
     394                 : 
     395               0 :   aWidget->SetInputContext(context, aAction);
     396               0 :   if (oldContext.mIMEState.mEnabled != context.mIMEState.mEnabled) {
     397                 :     nsContentUtils::AddScriptRunner(
     398               0 :       new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
     399                 :   }
     400                 : }
     401                 : 
     402                 : nsIWidget*
     403               0 : nsIMEStateManager::GetWidget(nsPresContext* aPresContext)
     404                 : {
     405               0 :   nsIPresShell* shell = aPresContext->GetPresShell();
     406               0 :   NS_ENSURE_TRUE(shell, nsnull);
     407                 : 
     408               0 :   nsIViewManager* vm = shell->GetViewManager();
     409               0 :   if (!vm)
     410               0 :     return nsnull;
     411               0 :   nsCOMPtr<nsIWidget> widget = nsnull;
     412               0 :   nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
     413               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
     414               0 :   return widget;
     415                 : }
     416                 : 
     417                 : 
     418                 : // nsTextStateManager notifies widget of any text and selection changes
     419                 : //  in the currently focused editor
     420                 : // sTextStateObserver points to the currently active nsTextStateManager
     421                 : // sTextStateObserver is null if there is no focused editor
     422                 : 
     423                 : class nsTextStateManager : public nsISelectionListener,
     424                 :                            public nsStubMutationObserver
     425               0 : {
     426                 : public:
     427                 :   nsTextStateManager();
     428                 : 
     429                 :   NS_DECL_ISUPPORTS
     430                 :   NS_DECL_NSISELECTIONLISTENER
     431                 :   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
     432                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     433                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     434                 :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     435                 : 
     436                 :   nsresult Init(nsIWidget* aWidget,
     437                 :                 nsPresContext* aPresContext,
     438                 :                 nsINode* aNode,
     439                 :                 bool aWantUpdates);
     440                 :   void     Destroy(void);
     441                 : 
     442                 :   nsCOMPtr<nsIWidget>            mWidget;
     443                 :   nsCOMPtr<nsISelection>         mSel;
     444                 :   nsCOMPtr<nsIContent>           mRootContent;
     445                 :   nsCOMPtr<nsINode>              mEditableNode;
     446                 :   bool                           mDestroying;
     447                 : 
     448                 : private:
     449                 :   void NotifyContentAdded(nsINode* aContainer, PRInt32 aStart, PRInt32 aEnd);
     450                 : };
     451                 : 
     452               0 : nsTextStateManager::nsTextStateManager()
     453                 : {
     454               0 :   mDestroying = false;
     455               0 : }
     456                 : 
     457                 : nsresult
     458               0 : nsTextStateManager::Init(nsIWidget* aWidget,
     459                 :                          nsPresContext* aPresContext,
     460                 :                          nsINode* aNode,
     461                 :                          bool aWantUpdates)
     462                 : {
     463               0 :   mWidget = aWidget;
     464               0 :   MOZ_ASSERT(mWidget);
     465               0 :   if (!aWantUpdates) {
     466               0 :     mEditableNode = aNode;
     467               0 :     return NS_OK;
     468                 :   }
     469                 : 
     470               0 :   nsIPresShell* presShell = aPresContext->PresShell();
     471                 : 
     472                 :   // get selection and root content
     473               0 :   nsCOMPtr<nsISelectionController> selCon;
     474               0 :   if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
     475               0 :     nsIFrame* frame = static_cast<nsIContent*>(aNode)->GetPrimaryFrame();
     476               0 :     NS_ENSURE_TRUE(frame, NS_ERROR_UNEXPECTED);
     477                 : 
     478                 :     frame->GetSelectionController(aPresContext,
     479               0 :                                   getter_AddRefs(selCon));
     480                 :   } else {
     481                 :     // aNode is a document
     482               0 :     selCon = do_QueryInterface(presShell);
     483                 :   }
     484               0 :   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
     485                 : 
     486               0 :   nsCOMPtr<nsISelection> sel;
     487               0 :   nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
     488               0 :                                      getter_AddRefs(sel));
     489               0 :   NS_ENSURE_TRUE(sel, NS_ERROR_UNEXPECTED);
     490                 : 
     491               0 :   nsCOMPtr<nsIDOMRange> selDomRange;
     492               0 :   rv = sel->GetRangeAt(0, getter_AddRefs(selDomRange));
     493                 : 
     494               0 :   if (NS_SUCCEEDED(rv)) {
     495               0 :     nsRange* selRange = static_cast<nsRange*>(selDomRange.get());
     496               0 :     NS_ENSURE_TRUE(selRange && selRange->GetStartParent(),
     497                 :                    NS_ERROR_UNEXPECTED);
     498                 : 
     499                 :     mRootContent = selRange->GetStartParent()->
     500               0 :                      GetSelectionRootContent(presShell);
     501                 :   } else {
     502               0 :     mRootContent = aNode->GetSelectionRootContent(presShell);
     503                 :   }
     504               0 :   if (!mRootContent && aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     505                 :     // The document node is editable, but there are no contents, this document
     506                 :     // is not editable.
     507               0 :     return NS_ERROR_NOT_AVAILABLE;
     508                 :   }
     509               0 :   NS_ENSURE_TRUE(mRootContent, NS_ERROR_UNEXPECTED);
     510                 : 
     511                 :   // add text change observer
     512               0 :   mRootContent->AddMutationObserver(this);
     513                 : 
     514                 :   // add selection change listener
     515               0 :   nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(sel));
     516               0 :   NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
     517               0 :   rv = selPrivate->AddSelectionListener(this);
     518               0 :   NS_ENSURE_SUCCESS(rv, rv);
     519               0 :   mSel = sel;
     520                 : 
     521               0 :   mEditableNode = aNode;
     522               0 :   return NS_OK;
     523                 : }
     524                 : 
     525                 : void
     526               0 : nsTextStateManager::Destroy(void)
     527                 : {
     528               0 :   if (mSel) {
     529               0 :     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSel));
     530               0 :     if (selPrivate)
     531               0 :       selPrivate->RemoveSelectionListener(this);
     532               0 :     mSel = nsnull;
     533                 :   }
     534               0 :   if (mRootContent) {
     535               0 :     mRootContent->RemoveMutationObserver(this);
     536               0 :     mRootContent = nsnull;
     537                 :   }
     538               0 :   mEditableNode = nsnull;
     539               0 :   mWidget = nsnull;
     540               0 : }
     541                 : 
     542               0 : NS_IMPL_ISUPPORTS2(nsTextStateManager,
     543                 :                    nsIMutationObserver,
     544                 :                    nsISelectionListener)
     545                 : 
     546                 : // Helper class, used for selection change notification
     547               0 : class SelectionChangeEvent : public nsRunnable {
     548                 : public:
     549               0 :   SelectionChangeEvent(nsIWidget *widget)
     550               0 :     : mWidget(widget)
     551                 :   {
     552               0 :     MOZ_ASSERT(mWidget);
     553               0 :   }
     554                 : 
     555               0 :   NS_IMETHOD Run() {
     556               0 :     if(mWidget) {
     557               0 :         mWidget->OnIMESelectionChange();
     558                 :     }
     559               0 :     return NS_OK;
     560                 :   }
     561                 : 
     562                 : private:
     563                 :   nsCOMPtr<nsIWidget> mWidget;
     564                 : };
     565                 : 
     566                 : nsresult
     567               0 : nsTextStateManager::NotifySelectionChanged(nsIDOMDocument* aDoc,
     568                 :                                            nsISelection* aSel,
     569                 :                                            PRInt16 aReason)
     570                 : {
     571               0 :   PRInt32 count = 0;
     572               0 :   nsresult rv = aSel->GetRangeCount(&count);
     573               0 :   NS_ENSURE_SUCCESS(rv, rv);
     574               0 :   if (count > 0 && mWidget) {
     575               0 :     nsContentUtils::AddScriptRunner(new SelectionChangeEvent(mWidget));
     576                 :   }
     577               0 :   return NS_OK;
     578                 : }
     579                 : 
     580                 : // Helper class, used for text change notification
     581               0 : class TextChangeEvent : public nsRunnable {
     582                 : public:
     583               0 :   TextChangeEvent(nsIWidget *widget,
     584                 :                   PRUint32 start, PRUint32 oldEnd, PRUint32 newEnd)
     585                 :     : mWidget(widget)
     586                 :     , mStart(start)
     587                 :     , mOldEnd(oldEnd)
     588               0 :     , mNewEnd(newEnd)
     589                 :   {
     590               0 :     MOZ_ASSERT(mWidget);
     591               0 :   }
     592                 : 
     593               0 :   NS_IMETHOD Run() {
     594               0 :     if(mWidget) {
     595               0 :         mWidget->OnIMETextChange(mStart, mOldEnd, mNewEnd);
     596                 :     }
     597               0 :     return NS_OK;
     598                 :   }
     599                 : 
     600                 : private:
     601                 :   nsCOMPtr<nsIWidget> mWidget;
     602                 :   PRUint32 mStart, mOldEnd, mNewEnd;
     603                 : };
     604                 : 
     605                 : void
     606               0 : nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument,
     607                 :                                          nsIContent* aContent,
     608                 :                                          CharacterDataChangeInfo* aInfo)
     609                 : {
     610               0 :   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
     611                 :                "character data changed for non-text node");
     612                 : 
     613               0 :   PRUint32 offset = 0;
     614                 :   // get offsets of change and fire notification
     615               0 :   if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
     616                 :                     mRootContent, aContent, aInfo->mChangeStart, &offset)))
     617               0 :     return;
     618                 : 
     619               0 :   PRUint32 oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart;
     620               0 :   PRUint32 newEnd = offset + aInfo->mReplaceLength;
     621                 : 
     622                 :   nsContentUtils::AddScriptRunner(
     623               0 :       new TextChangeEvent(mWidget, offset, oldEnd, newEnd));
     624                 : }
     625                 : 
     626                 : void
     627               0 : nsTextStateManager::NotifyContentAdded(nsINode* aContainer,
     628                 :                                        PRInt32 aStartIndex,
     629                 :                                        PRInt32 aEndIndex)
     630                 : {
     631               0 :   PRUint32 offset = 0, newOffset = 0;
     632               0 :   if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
     633                 :                     mRootContent, aContainer, aStartIndex, &offset)))
     634               0 :     return;
     635                 : 
     636                 :   // get offset at the end of the last added node
     637               0 :   if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
     638                 :                     aContainer->GetChildAt(aStartIndex),
     639                 :                     aContainer, aEndIndex, &newOffset)))
     640               0 :     return;
     641                 : 
     642                 :   // fire notification
     643               0 :   if (newOffset)
     644                 :     nsContentUtils::AddScriptRunner(
     645               0 :         new TextChangeEvent(mWidget, offset, offset, offset + newOffset));
     646                 : }
     647                 : 
     648                 : void
     649               0 : nsTextStateManager::ContentAppended(nsIDocument* aDocument,
     650                 :                                     nsIContent* aContainer,
     651                 :                                     nsIContent* aFirstNewContent,
     652                 :                                     PRInt32 aNewIndexInContainer)
     653                 : {
     654                 :   NotifyContentAdded(aContainer, aNewIndexInContainer,
     655               0 :                      aContainer->GetChildCount());
     656               0 : }
     657                 : 
     658                 : void
     659               0 : nsTextStateManager::ContentInserted(nsIDocument* aDocument,
     660                 :                                      nsIContent* aContainer,
     661                 :                                      nsIContent* aChild,
     662                 :                                      PRInt32 aIndexInContainer)
     663                 : {
     664                 :   NotifyContentAdded(NODE_FROM(aContainer, aDocument),
     665               0 :                      aIndexInContainer, aIndexInContainer + 1);
     666               0 : }
     667                 : 
     668                 : void
     669               0 : nsTextStateManager::ContentRemoved(nsIDocument* aDocument,
     670                 :                                    nsIContent* aContainer,
     671                 :                                    nsIContent* aChild,
     672                 :                                    PRInt32 aIndexInContainer,
     673                 :                                    nsIContent* aPreviousSibling)
     674                 : {
     675               0 :   PRUint32 offset = 0, childOffset = 1;
     676               0 :   if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
     677                 :                     mRootContent, NODE_FROM(aContainer, aDocument),
     678                 :                     aIndexInContainer, &offset)))
     679               0 :     return;
     680                 : 
     681                 :   // get offset at the end of the deleted node
     682               0 :   if (aChild->IsNodeOfType(nsINode::eTEXT))
     683               0 :     childOffset = aChild->TextLength();
     684               0 :   else if (0 < aChild->GetChildCount())
     685               0 :     childOffset = aChild->GetChildCount();
     686                 : 
     687               0 :   if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
     688                 :                     aChild, aChild, childOffset, &childOffset)))
     689               0 :     return;
     690                 : 
     691                 :   // fire notification
     692               0 :   if (childOffset)
     693                 :     nsContentUtils::AddScriptRunner(
     694               0 :         new TextChangeEvent(mWidget, offset, offset + childOffset, offset));
     695                 : }
     696                 : 
     697               0 : static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
     698                 :                                     nsIContent* aContent)
     699                 : {
     700               0 :   if (aContent) {
     701               0 :     nsINode* root = nsnull;
     702               0 :     nsINode* node = aContent;
     703               0 :     while (node && node->IsEditable()) {
     704               0 :       root = node;
     705               0 :       node = node->GetNodeParent();
     706                 :     }
     707               0 :     return root;
     708                 :   }
     709               0 :   if (aPresContext) {
     710               0 :     nsIDocument* document = aPresContext->Document();
     711               0 :     if (document && document->IsEditable())
     712               0 :       return document;
     713                 :   }
     714               0 :   return nsnull;
     715                 : }
     716                 : 
     717                 : nsresult
     718               0 : nsIMEStateManager::OnTextStateBlur(nsPresContext* aPresContext,
     719                 :                                    nsIContent* aContent)
     720                 : {
     721               0 :   if (!sTextStateObserver || sTextStateObserver->mDestroying ||
     722                 :       sTextStateObserver->mEditableNode ==
     723               0 :           GetRootEditableNode(aPresContext, aContent))
     724               0 :     return NS_OK;
     725                 : 
     726               0 :   sTextStateObserver->mDestroying = true;
     727               0 :   sTextStateObserver->mWidget->OnIMEFocusChange(false);
     728               0 :   sTextStateObserver->Destroy();
     729               0 :   NS_RELEASE(sTextStateObserver);
     730               0 :   return NS_OK;
     731                 : }
     732                 : 
     733                 : nsresult
     734               0 : nsIMEStateManager::OnTextStateFocus(nsPresContext* aPresContext,
     735                 :                                     nsIContent* aContent)
     736                 : {
     737               0 :   if (sTextStateObserver) return NS_OK;
     738                 : 
     739               0 :   nsINode *editableNode = GetRootEditableNode(aPresContext, aContent);
     740               0 :   if (!editableNode) return NS_OK;
     741                 : 
     742               0 :   nsIPresShell* shell = aPresContext->GetPresShell();
     743               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_NOT_AVAILABLE);
     744                 :   
     745               0 :   nsIViewManager* vm = shell->GetViewManager();
     746               0 :   NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE);
     747                 : 
     748               0 :   nsCOMPtr<nsIWidget> widget;
     749               0 :   nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
     750               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
     751               0 :   if (!widget) {
     752               0 :     return NS_OK; // Sometimes, there are no widgets.
     753                 :   }
     754                 : 
     755               0 :   rv = widget->OnIMEFocusChange(true);
     756               0 :   if (rv == NS_ERROR_NOT_IMPLEMENTED)
     757               0 :     return NS_OK;
     758               0 :   NS_ENSURE_SUCCESS(rv, rv);
     759                 : 
     760               0 :   bool wantUpdates = rv != NS_SUCCESS_IME_NO_UPDATES;
     761                 : 
     762                 :   // OnIMEFocusChange may cause focus and sTextStateObserver to change
     763                 :   // In that case return and keep the current sTextStateObserver
     764               0 :   NS_ENSURE_TRUE(!sTextStateObserver, NS_OK);
     765                 : 
     766               0 :   sTextStateObserver = new nsTextStateManager();
     767               0 :   NS_ENSURE_TRUE(sTextStateObserver, NS_ERROR_OUT_OF_MEMORY);
     768               0 :   NS_ADDREF(sTextStateObserver);
     769                 :   rv = sTextStateObserver->Init(widget, aPresContext,
     770               0 :                                 editableNode, wantUpdates);
     771               0 :   if (NS_FAILED(rv)) {
     772               0 :     sTextStateObserver->mDestroying = true;
     773               0 :     sTextStateObserver->Destroy();
     774               0 :     NS_RELEASE(sTextStateObserver);
     775               0 :     widget->OnIMEFocusChange(false);
     776               0 :     return rv;
     777                 :   }
     778               0 :   return NS_OK;
     779                 : }
     780                 : 
     781                 : nsresult
     782               0 : nsIMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSel,
     783                 :                                             nsIContent** aRoot)
     784                 : {
     785               0 :   if (!sTextStateObserver || !sTextStateObserver->mEditableNode ||
     786               0 :       !sTextStateObserver->mSel)
     787               0 :     return NS_ERROR_NOT_AVAILABLE;
     788                 : 
     789               0 :   NS_ASSERTION(sTextStateObserver->mSel && sTextStateObserver->mRootContent,
     790                 :                "uninitialized text state observer");
     791               0 :   NS_ADDREF(*aSel = sTextStateObserver->mSel);
     792               0 :   NS_ADDREF(*aRoot = sTextStateObserver->mRootContent);
     793               0 :   return NS_OK;
     794                 : }

Generated by: LCOV version 1.7