LCOV - code coverage report
Current view: top level - editor/libeditor - EditorEventListener.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 113 544 20.8 %
Date: 2017-07-14 16:53:18 Functions: 9 38 23.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=4 sw=2 et tw=78: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "EditorEventListener.h"
       8             : 
       9             : #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc.
      10             : #include "mozilla/ContentEvents.h"      // for InternalFocusEvent
      11             : #include "mozilla/EditorBase.h"         // for EditorBase, etc.
      12             : #include "mozilla/EventListenerManager.h" // for EventListenerManager
      13             : #include "mozilla/IMEStateManager.h"    // for IMEStateManager
      14             : #include "mozilla/Preferences.h"        // for Preferences
      15             : #include "mozilla/TextEvents.h"         // for WidgetCompositionEvent
      16             : #include "mozilla/dom/Element.h"        // for Element
      17             : #include "mozilla/dom/Event.h"          // for Event
      18             : #include "mozilla/dom/EventTarget.h"    // for EventTarget
      19             : #include "mozilla/dom/Selection.h"
      20             : #include "nsAString.h"
      21             : #include "nsCaret.h"                    // for nsCaret
      22             : #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc.
      23             : #include "nsFocusManager.h"             // for nsFocusManager
      24             : #include "nsGkAtoms.h"                  // for nsGkAtoms, nsGkAtoms::input
      25             : #include "nsIClipboard.h"               // for nsIClipboard, etc.
      26             : #include "nsIContent.h"                 // for nsIContent
      27             : #include "nsIController.h"              // for nsIController
      28             : #include "nsID.h"
      29             : #include "mozilla/dom/DOMStringList.h"
      30             : #include "mozilla/dom/DataTransfer.h"
      31             : #include "nsIDOMDocument.h"             // for nsIDOMDocument
      32             : #include "nsIDOMDragEvent.h"            // for nsIDOMDragEvent
      33             : #include "nsIDOMElement.h"              // for nsIDOMElement
      34             : #include "nsIDOMEvent.h"                // for nsIDOMEvent
      35             : #include "nsIDOMEventTarget.h"          // for nsIDOMEventTarget
      36             : #include "nsIDOMMouseEvent.h"           // for nsIDOMMouseEvent
      37             : #include "nsIDOMNode.h"                 // for nsIDOMNode
      38             : #include "nsIDocument.h"                // for nsIDocument
      39             : #include "nsIEditor.h"                  // for EditorBase::GetSelection, etc.
      40             : #include "nsIEditorMailSupport.h"       // for nsIEditorMailSupport
      41             : #include "nsIFocusManager.h"            // for nsIFocusManager
      42             : #include "nsIFormControl.h"             // for nsIFormControl, etc.
      43             : #include "nsIHTMLEditor.h"              // for nsIHTMLEditor
      44             : #include "nsINode.h"                    // for nsINode, ::NODE_IS_EDITABLE, etc.
      45             : #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor, etc.
      46             : #include "nsIPresShell.h"               // for nsIPresShell
      47             : #include "nsISelectionController.h"     // for nsISelectionController, etc.
      48             : #include "nsITransferable.h"            // for kFileMime, kHTMLMime, etc.
      49             : #include "nsIWidget.h"                  // for nsIWidget
      50             : #include "nsLiteralString.h"            // for NS_LITERAL_STRING
      51             : #include "nsPIWindowRoot.h"             // for nsPIWindowRoot
      52             : #include "nsPrintfCString.h"            // for nsPrintfCString
      53             : #include "nsRange.h"
      54             : #include "nsServiceManagerUtils.h"      // for do_GetService
      55             : #include "nsString.h"                   // for nsAutoString
      56             : #include "nsQueryObject.h"              // for do_QueryObject
      57             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
      58             : #include "nsContentUtils.h"             // for nsContentUtils, etc.
      59             : #include "nsIBidiKeyboard.h"            // for nsIBidiKeyboard
      60             : #endif
      61             : 
      62             : #include "mozilla/dom/TabParent.h"
      63             : 
      64             : class nsPresContext;
      65             : 
      66             : namespace mozilla {
      67             : 
      68             : using namespace dom;
      69             : 
      70             : static void
      71           0 : DoCommandCallback(Command aCommand, void* aData)
      72             : {
      73           0 :   nsIDocument* doc = static_cast<nsIDocument*>(aData);
      74           0 :   nsPIDOMWindowOuter* win = doc->GetWindow();
      75           0 :   if (!win) {
      76           0 :     return;
      77             :   }
      78           0 :   nsCOMPtr<nsPIWindowRoot> root = win->GetTopWindowRoot();
      79           0 :   if (!root) {
      80           0 :     return;
      81             :   }
      82             : 
      83           0 :   const char* commandStr = WidgetKeyboardEvent::GetCommandStr(aCommand);
      84             : 
      85           0 :   nsCOMPtr<nsIController> controller;
      86           0 :   root->GetControllerForCommand(commandStr, getter_AddRefs(controller));
      87           0 :   if (!controller) {
      88           0 :     return;
      89             :   }
      90             : 
      91             :   bool commandEnabled;
      92           0 :   nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
      93           0 :   NS_ENSURE_SUCCESS_VOID(rv);
      94           0 :   if (commandEnabled) {
      95           0 :     controller->DoCommand(commandStr);
      96             :   }
      97             : }
      98             : 
      99           1 : EditorEventListener::EditorEventListener()
     100             :   : mEditorBase(nullptr)
     101             :   , mCommitText(false)
     102             :   , mInTransaction(false)
     103           1 :   , mMouseDownOrUpConsumedByIME(false)
     104             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     105             :   , mHaveBidiKeyboards(false)
     106             :   , mShouldSwitchTextDirection(false)
     107             :   , mSwitchToRTL(false)
     108             : #endif
     109             : {
     110           1 : }
     111             : 
     112           0 : EditorEventListener::~EditorEventListener()
     113             : {
     114           0 :   if (mEditorBase) {
     115           0 :     NS_WARNING("We're not uninstalled");
     116           0 :     Disconnect();
     117             :   }
     118           0 : }
     119             : 
     120             : nsresult
     121           2 : EditorEventListener::Connect(EditorBase* aEditorBase)
     122             : {
     123           2 :   NS_ENSURE_ARG(aEditorBase);
     124             : 
     125             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     126             :   nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
     127             :   if (bidiKeyboard) {
     128             :     bool haveBidiKeyboards = false;
     129             :     bidiKeyboard->GetHaveBidiKeyboards(&haveBidiKeyboards);
     130             :     mHaveBidiKeyboards = haveBidiKeyboards;
     131             :   }
     132             : #endif
     133             : 
     134           2 :   mEditorBase = aEditorBase;
     135             : 
     136           2 :   nsresult rv = InstallToEditor();
     137           2 :   if (NS_FAILED(rv)) {
     138           0 :     Disconnect();
     139             :   }
     140           2 :   return rv;
     141             : }
     142             : 
     143             : nsresult
     144           2 : EditorEventListener::InstallToEditor()
     145             : {
     146           2 :   NS_PRECONDITION(mEditorBase, "The caller must set mEditorBase");
     147             : 
     148           4 :   nsCOMPtr<EventTarget> piTarget = mEditorBase->GetDOMEventTarget();
     149           2 :   NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
     150             : 
     151             :   // register the event listeners with the listener manager
     152           2 :   EventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
     153           2 :   NS_ENSURE_STATE(elmP);
     154             : 
     155             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     156             :   elmP->AddEventListenerByType(this,
     157             :                                NS_LITERAL_STRING("keydown"),
     158             :                                TrustedEventsAtSystemGroupBubble());
     159             :   elmP->AddEventListenerByType(this,
     160             :                                NS_LITERAL_STRING("keyup"),
     161             :                                TrustedEventsAtSystemGroupBubble());
     162             : #endif
     163           2 :   elmP->AddEventListenerByType(this,
     164           4 :                                NS_LITERAL_STRING("keypress"),
     165           8 :                                TrustedEventsAtSystemGroupBubble());
     166           2 :   elmP->AddEventListenerByType(this,
     167           4 :                                NS_LITERAL_STRING("dragenter"),
     168           8 :                                TrustedEventsAtSystemGroupBubble());
     169           2 :   elmP->AddEventListenerByType(this,
     170           4 :                                NS_LITERAL_STRING("dragover"),
     171           8 :                                TrustedEventsAtSystemGroupBubble());
     172           2 :   elmP->AddEventListenerByType(this,
     173           4 :                                NS_LITERAL_STRING("dragexit"),
     174           8 :                                TrustedEventsAtSystemGroupBubble());
     175           2 :   elmP->AddEventListenerByType(this,
     176           4 :                                NS_LITERAL_STRING("drop"),
     177           8 :                                TrustedEventsAtSystemGroupBubble());
     178             :   // XXX We should add the mouse event listeners as system event group.
     179             :   //     E.g., web applications cannot prevent middle mouse paste by
     180             :   //     preventDefault() of click event at bubble phase.
     181             :   //     However, if we do so, all click handlers in any frames and frontend
     182             :   //     code need to check if it's editable.  It makes easier create new bugs.
     183           2 :   elmP->AddEventListenerByType(this,
     184           4 :                                NS_LITERAL_STRING("mousedown"),
     185           8 :                                TrustedEventsAtCapture());
     186           2 :   elmP->AddEventListenerByType(this,
     187           4 :                                NS_LITERAL_STRING("mouseup"),
     188           8 :                                TrustedEventsAtCapture());
     189           2 :   elmP->AddEventListenerByType(this,
     190           4 :                                NS_LITERAL_STRING("click"),
     191           8 :                                TrustedEventsAtCapture());
     192             :   // Focus event doesn't bubble so adding the listener to capturing phase.
     193             :   // XXX Should we listen focus/blur events of system group too? Or should
     194             :   //     editor notified focus/blur of the element from nsFocusManager
     195             :   //     directly?  Because if the event propagation is stopped by JS,
     196             :   //     editor cannot initialize selection as expected.
     197           2 :   elmP->AddEventListenerByType(this,
     198           4 :                                NS_LITERAL_STRING("blur"),
     199           8 :                                TrustedEventsAtCapture());
     200           2 :   elmP->AddEventListenerByType(this,
     201           4 :                                NS_LITERAL_STRING("focus"),
     202           8 :                                TrustedEventsAtCapture());
     203           2 :   elmP->AddEventListenerByType(this,
     204           4 :                                NS_LITERAL_STRING("text"),
     205           8 :                                TrustedEventsAtSystemGroupBubble());
     206           2 :   elmP->AddEventListenerByType(this,
     207           4 :                                NS_LITERAL_STRING("compositionstart"),
     208           8 :                                TrustedEventsAtSystemGroupBubble());
     209           2 :   elmP->AddEventListenerByType(this,
     210           4 :                                NS_LITERAL_STRING("compositionend"),
     211           8 :                                TrustedEventsAtSystemGroupBubble());
     212             : 
     213           2 :   return NS_OK;
     214             : }
     215             : 
     216             : void
     217           1 : EditorEventListener::Disconnect()
     218             : {
     219           1 :   if (DetachedFromEditor()) {
     220           0 :     return;
     221             :   }
     222           1 :   UninstallFromEditor();
     223             : 
     224           1 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     225           1 :   if (fm) {
     226           2 :     nsCOMPtr<nsIDOMElement> domFocus;
     227           1 :     fm->GetFocusedElement(getter_AddRefs(domFocus));
     228           2 :     nsCOMPtr<nsINode> focusedElement = do_QueryInterface(domFocus);
     229           1 :     mozilla::dom::Element* root = mEditorBase->GetRoot();
     230           1 :     if (focusedElement && root &&
     231           0 :         nsContentUtils::ContentIsDescendantOf(focusedElement, root)) {
     232             :       // Reset the Selection ancestor limiter and SelectionController state
     233             :       // that EditorBase::InitializeSelection set up.
     234           0 :       mEditorBase->FinalizeSelection();
     235             :     }
     236             :   }
     237             : 
     238           1 :   mEditorBase = nullptr;
     239             : }
     240             : 
     241             : void
     242           1 : EditorEventListener::UninstallFromEditor()
     243             : {
     244           2 :   nsCOMPtr<EventTarget> piTarget = mEditorBase->GetDOMEventTarget();
     245           1 :   if (!piTarget) {
     246           0 :     return;
     247             :   }
     248             : 
     249           1 :   EventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
     250           1 :   if (!elmP) {
     251           0 :     return;
     252             :   }
     253             : 
     254             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     255             :   elmP->RemoveEventListenerByType(this,
     256             :                                   NS_LITERAL_STRING("keydown"),
     257             :                                   TrustedEventsAtSystemGroupBubble());
     258             :   elmP->RemoveEventListenerByType(this,
     259             :                                   NS_LITERAL_STRING("keyup"),
     260             :                                   TrustedEventsAtSystemGroupBubble());
     261             : #endif
     262           1 :   elmP->RemoveEventListenerByType(this,
     263           2 :                                   NS_LITERAL_STRING("keypress"),
     264           4 :                                   TrustedEventsAtSystemGroupBubble());
     265           1 :   elmP->RemoveEventListenerByType(this,
     266           2 :                                   NS_LITERAL_STRING("dragenter"),
     267           4 :                                   TrustedEventsAtSystemGroupBubble());
     268           1 :   elmP->RemoveEventListenerByType(this,
     269           2 :                                   NS_LITERAL_STRING("dragover"),
     270           4 :                                   TrustedEventsAtSystemGroupBubble());
     271           1 :   elmP->RemoveEventListenerByType(this,
     272           2 :                                   NS_LITERAL_STRING("dragexit"),
     273           4 :                                   TrustedEventsAtSystemGroupBubble());
     274           1 :   elmP->RemoveEventListenerByType(this,
     275           2 :                                   NS_LITERAL_STRING("drop"),
     276           4 :                                   TrustedEventsAtSystemGroupBubble());
     277           1 :   elmP->RemoveEventListenerByType(this,
     278           2 :                                   NS_LITERAL_STRING("mousedown"),
     279           4 :                                   TrustedEventsAtCapture());
     280           1 :   elmP->RemoveEventListenerByType(this,
     281           2 :                                   NS_LITERAL_STRING("mouseup"),
     282           4 :                                   TrustedEventsAtCapture());
     283           1 :   elmP->RemoveEventListenerByType(this,
     284           2 :                                   NS_LITERAL_STRING("click"),
     285           4 :                                   TrustedEventsAtCapture());
     286           1 :   elmP->RemoveEventListenerByType(this,
     287           2 :                                   NS_LITERAL_STRING("blur"),
     288           4 :                                   TrustedEventsAtCapture());
     289           1 :   elmP->RemoveEventListenerByType(this,
     290           2 :                                   NS_LITERAL_STRING("focus"),
     291           4 :                                   TrustedEventsAtCapture());
     292           1 :   elmP->RemoveEventListenerByType(this,
     293           2 :                                   NS_LITERAL_STRING("text"),
     294           4 :                                   TrustedEventsAtSystemGroupBubble());
     295           1 :   elmP->RemoveEventListenerByType(this,
     296           2 :                                   NS_LITERAL_STRING("compositionstart"),
     297           4 :                                   TrustedEventsAtSystemGroupBubble());
     298           1 :   elmP->RemoveEventListenerByType(this,
     299           2 :                                   NS_LITERAL_STRING("compositionend"),
     300           4 :                                   TrustedEventsAtSystemGroupBubble());
     301             : }
     302             : 
     303             : already_AddRefed<nsIPresShell>
     304           0 : EditorEventListener::GetPresShell()
     305             : {
     306           0 :   MOZ_ASSERT(!DetachedFromEditor());
     307           0 :   return mEditorBase->GetPresShell();
     308             : }
     309             : 
     310             : nsPresContext*
     311           0 : EditorEventListener::GetPresContext()
     312             : {
     313           0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     314           0 :   return presShell ? presShell->GetPresContext() : nullptr;
     315             : }
     316             : 
     317             : nsIContent*
     318           0 : EditorEventListener::GetFocusedRootContent()
     319             : {
     320           0 :   MOZ_ASSERT(!DetachedFromEditor());
     321           0 :   nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
     322           0 :   if (!focusedContent) {
     323           0 :     return nullptr;
     324             :   }
     325             : 
     326           0 :   nsIDocument* composedDoc = focusedContent->GetComposedDoc();
     327           0 :   NS_ENSURE_TRUE(composedDoc, nullptr);
     328             : 
     329           0 :   if (composedDoc->HasFlag(NODE_IS_EDITABLE)) {
     330           0 :     return nullptr;
     331             :   }
     332             : 
     333           0 :   return focusedContent;
     334             : }
     335             : 
     336             : bool
     337           0 : EditorEventListener::EditorHasFocus()
     338             : {
     339           0 :   MOZ_ASSERT(!DetachedFromEditor());
     340           0 :   nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
     341           0 :   if (!focusedContent) {
     342           0 :     return false;
     343             :   }
     344           0 :   nsIDocument* composedDoc = focusedContent->GetComposedDoc();
     345           0 :   return !!composedDoc;
     346             : }
     347             : 
     348          95 : NS_IMPL_ISUPPORTS(EditorEventListener, nsIDOMEventListener)
     349             : 
     350             : bool
     351           1 : EditorEventListener::DetachedFromEditor() const
     352             : {
     353           1 :   return !mEditorBase;
     354             : }
     355             : 
     356             : bool
     357           0 : EditorEventListener::DetachedFromEditorOrDefaultPrevented(
     358             :                        WidgetEvent* aWidgetEvent) const
     359             : {
     360           0 :   return NS_WARN_IF(!aWidgetEvent) || DetachedFromEditor() ||
     361           0 :          aWidgetEvent->DefaultPrevented();
     362             : }
     363             : 
     364             : bool
     365           0 : EditorEventListener::EnsureCommitCompoisition()
     366             : {
     367           0 :   MOZ_ASSERT(!DetachedFromEditor());
     368           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     369           0 :   editorBase->ForceCompositionEnd();
     370           0 :   return !DetachedFromEditor();
     371             : }
     372             : 
     373             : NS_IMETHODIMP
     374           0 : EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
     375             : {
     376             :   // Let's handle each event with the message of the internal event of the
     377             :   // coming event.  If the DOM event was created with improper interface,
     378             :   // e.g., keydown event is created with |new MouseEvent("keydown", {});|,
     379             :   // its message is always 0.  Therefore, we can ban such strange event easy.
     380             :   // However, we need to handle strange "focus" and "blur" event.  See the
     381             :   // following code of this switch statement.
     382             :   // NOTE: Each event handler may require specific event interface.  Before
     383             :   //       calling it, this queries the specific interface.  If it would fail,
     384             :   //       each event handler would just ignore the event.  So, in this method,
     385             :   //       you don't need to check if the QI succeeded before each call.
     386           0 :   WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
     387           0 :   switch (internalEvent->mMessage) {
     388             :     // dragenter
     389             :     case eDragEnter: {
     390           0 :       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
     391           0 :       return DragEnter(dragEvent);
     392             :     }
     393             :     // dragover
     394             :     case eDragOver: {
     395           0 :       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
     396           0 :       return DragOver(dragEvent);
     397             :     }
     398             :     // dragexit
     399             :     case eDragExit: {
     400           0 :       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
     401           0 :       return DragExit(dragEvent);
     402             :     }
     403             :     // drop
     404             :     case eDrop: {
     405           0 :       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
     406           0 :       return Drop(dragEvent);
     407             :     }
     408             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     409             :     // keydown
     410             :     case eKeyDown: {
     411             :       return KeyDown(internalEvent->AsKeyboardEvent());
     412             :     }
     413             :     // keyup
     414             :     case eKeyUp:
     415             :       return KeyUp(internalEvent->AsKeyboardEvent());
     416             : #endif // #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     417             :     // keypress
     418             :     case eKeyPress:
     419           0 :       return KeyPress(internalEvent->AsKeyboardEvent());
     420             :     // mousedown
     421             :     case eMouseDown: {
     422             :       // EditorEventListener may receive (1) all mousedown, mouseup and click
     423             :       // events, (2) only mousedown event or (3) only mouseup event.
     424             :       // mMouseDownOrUpConsumedByIME is used only for ignoring click event if
     425             :       // preceding mousedown and/or mouseup event is consumed by IME.
     426             :       // Therefore, even if case #2 or case #3 occurs,
     427             :       // mMouseDownOrUpConsumedByIME is true here.  Therefore, we should always
     428             :       // overwrite it here.
     429           0 :       mMouseDownOrUpConsumedByIME =
     430           0 :         NotifyIMEOfMouseButtonEvent(internalEvent->AsMouseEvent());
     431           0 :       if (mMouseDownOrUpConsumedByIME) {
     432           0 :         return NS_OK;
     433             :       }
     434           0 :       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
     435           0 :       return NS_WARN_IF(!mouseEvent) ? NS_OK : MouseDown(mouseEvent);
     436             :     }
     437             :     // mouseup
     438             :     case eMouseUp: {
     439             :       // See above comment in the eMouseDown case, first.
     440             :       // This code assumes that case #1 is occuring.  However, if case #3 may
     441             :       // occurs after case #2 and the mousedown is consumed,
     442             :       // mMouseDownOrUpConsumedByIME is true even though EditorEventListener
     443             :       // has not received the preceding mousedown event of this mouseup event.
     444             :       // So, mMouseDownOrUpConsumedByIME may be invalid here.  However,
     445             :       // this is not a matter because mMouseDownOrUpConsumedByIME is referred
     446             :       // only by eMouseClick case but click event is fired only in case #1.
     447             :       // So, before a click event is fired, mMouseDownOrUpConsumedByIME is
     448             :       // always initialized in the eMouseDown case if it's referred.
     449           0 :       if (NotifyIMEOfMouseButtonEvent(internalEvent->AsMouseEvent())) {
     450           0 :         mMouseDownOrUpConsumedByIME = true;
     451             :       }
     452           0 :       if (mMouseDownOrUpConsumedByIME) {
     453           0 :         return NS_OK;
     454             :       }
     455           0 :       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
     456           0 :       return NS_WARN_IF(!mouseEvent) ? NS_OK : MouseUp(mouseEvent);
     457             :     }
     458             :     // click
     459             :     case eMouseClick: {
     460           0 :       nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
     461           0 :       NS_ENSURE_TRUE(mouseEvent, NS_OK);
     462             :       // If the preceding mousedown event or mouseup event was consumed,
     463             :       // editor shouldn't handle this click event.
     464           0 :       if (mMouseDownOrUpConsumedByIME) {
     465           0 :         mMouseDownOrUpConsumedByIME = false;
     466           0 :         mouseEvent->AsEvent()->PreventDefault();
     467           0 :         return NS_OK;
     468             :       }
     469           0 :       return MouseClick(mouseEvent);
     470             :     }
     471             :     // focus
     472             :     case eFocus:
     473           0 :       return Focus(internalEvent->AsFocusEvent());
     474             :     // blur
     475             :     case eBlur:
     476           0 :       return Blur(internalEvent->AsFocusEvent());
     477             :     // text
     478             :     case eCompositionChange:
     479           0 :       return HandleChangeComposition(internalEvent->AsCompositionEvent());
     480             :     // compositionstart
     481             :     case eCompositionStart:
     482           0 :       return HandleStartComposition(internalEvent->AsCompositionEvent());
     483             :     // compositionend
     484             :     case eCompositionEnd:
     485           0 :       HandleEndComposition(internalEvent->AsCompositionEvent());
     486           0 :       return NS_OK;
     487             :     default:
     488           0 :       break;
     489             :   }
     490             : 
     491             : #ifdef DEBUG
     492           0 :   nsAutoString eventType;
     493           0 :   aEvent->GetType(eventType);
     494             :   nsPrintfCString assertMessage("Editor doesn't handle \"%s\" event "
     495             :     "because its internal event doesn't have proper message",
     496           0 :     NS_ConvertUTF16toUTF8(eventType).get());
     497           0 :   NS_ASSERTION(false, assertMessage.get());
     498             : #endif
     499             : 
     500           0 :   return NS_OK;
     501             : }
     502             : 
     503             : #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     504             : 
     505             : // This function is borrowed from Chromium's ImeInput::IsCtrlShiftPressed
     506             : bool IsCtrlShiftPressed(const WidgetKeyboardEvent* aKeyboardEvent, bool& isRTL)
     507             : {
     508             :   MOZ_ASSERT(aKeyboardEvent);
     509             :   // To check if a user is pressing only a control key and a right-shift key
     510             :   // (or a left-shift key), we use the steps below:
     511             :   // 1. Check if a user is pressing a control key and a right-shift key (or
     512             :   //    a left-shift key).
     513             :   // 2. If the condition 1 is true, we should check if there are any other
     514             :   //    keys pressed at the same time.
     515             :   //    To ignore the keys checked in 1, we set their status to 0 before
     516             :   //    checking the key status.
     517             : 
     518             :   if (!aKeyboardEvent->IsControl()) {
     519             :     return false;
     520             :   }
     521             : 
     522             :   switch (aKeyboardEvent->mLocation) {
     523             :     case eKeyLocationRight:
     524             :       isRTL = true;
     525             :       break;
     526             :     case eKeyLocationLeft:
     527             :       isRTL = false;
     528             :       break;
     529             :     default:
     530             :       return false;
     531             :   }
     532             : 
     533             :   // Scan the key status to find pressed keys. We should abandon changing the
     534             :   // text direction when there are other pressed keys.
     535             :   if (aKeyboardEvent->IsAlt() || aKeyboardEvent->IsOS()) {
     536             :     return false;
     537             :   }
     538             : 
     539             :   return true;
     540             : }
     541             : 
     542             : // This logic is mostly borrowed from Chromium's
     543             : // RenderWidgetHostViewWin::OnKeyEvent.
     544             : 
     545             : nsresult
     546             : EditorEventListener::KeyUp(const WidgetKeyboardEvent* aKeyboardEvent)
     547             : {
     548             :   if (NS_WARN_IF(!aKeyboardEvent) || DetachedFromEditor()) {
     549             :     return NS_OK;
     550             :   }
     551             : 
     552             :   if (!mHaveBidiKeyboards) {
     553             :     return NS_OK;
     554             :   }
     555             : 
     556             :   // XXX Why doesn't this method check if it's consumed?
     557             :   RefPtr<EditorBase> editorBase(mEditorBase);
     558             :   if ((aKeyboardEvent->mKeyCode == NS_VK_SHIFT ||
     559             :        aKeyboardEvent->mKeyCode == NS_VK_CONTROL) &&
     560             :       mShouldSwitchTextDirection && editorBase->IsPlaintextEditor()) {
     561             :     editorBase->SwitchTextDirectionTo(mSwitchToRTL ?
     562             :       nsIPlaintextEditor::eEditorRightToLeft :
     563             :       nsIPlaintextEditor::eEditorLeftToRight);
     564             :     mShouldSwitchTextDirection = false;
     565             :   }
     566             :   return NS_OK;
     567             : }
     568             : 
     569             : nsresult
     570             : EditorEventListener::KeyDown(const WidgetKeyboardEvent* aKeyboardEvent)
     571             : {
     572             :   if (NS_WARN_IF(!aKeyboardEvent) || DetachedFromEditor()) {
     573             :     return NS_OK;
     574             :   }
     575             : 
     576             :   if (!mHaveBidiKeyboards) {
     577             :     return NS_OK;
     578             :   }
     579             : 
     580             :   // XXX Why isn't this method check if it's consumed?
     581             :   if (aKeyboardEvent->mKeyCode == NS_VK_SHIFT) {
     582             :     bool switchToRTL;
     583             :     if (IsCtrlShiftPressed(aKeyboardEvent, switchToRTL)) {
     584             :       mShouldSwitchTextDirection = true;
     585             :       mSwitchToRTL = switchToRTL;
     586             :     }
     587             :   } else if (aKeyboardEvent->mKeyCode != NS_VK_CONTROL) {
     588             :     // In case the user presses any other key besides Ctrl and Shift
     589             :     mShouldSwitchTextDirection = false;
     590             :   }
     591             :   return NS_OK;
     592             : }
     593             : 
     594             : #endif // #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
     595             : 
     596             : nsresult
     597           0 : EditorEventListener::KeyPress(WidgetKeyboardEvent* aKeyboardEvent)
     598             : {
     599           0 :   if (NS_WARN_IF(!aKeyboardEvent)) {
     600           0 :     return NS_OK;
     601             :   }
     602             : 
     603           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     604           0 :   if (!editorBase->IsAcceptableInputEvent(aKeyboardEvent) ||
     605           0 :       DetachedFromEditorOrDefaultPrevented(aKeyboardEvent)) {
     606           0 :     return NS_OK;
     607             :   }
     608             : 
     609           0 :   nsresult rv = editorBase->HandleKeyPressEvent(aKeyboardEvent);
     610           0 :   NS_ENSURE_SUCCESS(rv, rv);
     611           0 :   if (DetachedFromEditorOrDefaultPrevented(aKeyboardEvent)) {
     612           0 :     return NS_OK;
     613             :   }
     614             : 
     615           0 :   if (!ShouldHandleNativeKeyBindings(aKeyboardEvent)) {
     616           0 :     return NS_OK;
     617             :   }
     618             : 
     619             :   // Now, ask the native key bindings to handle the event.
     620           0 :   nsIWidget* widget = aKeyboardEvent->mWidget;
     621             :   // If the event is created by chrome script, the widget is always nullptr.
     622           0 :   if (!widget) {
     623           0 :     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     624           0 :     nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
     625           0 :     widget = pc ? pc->GetNearestWidget() : nullptr;
     626           0 :     NS_ENSURE_TRUE(widget, NS_OK);
     627             :   }
     628             : 
     629           0 :   nsCOMPtr<nsIDocument> doc = editorBase->GetDocument();
     630             : 
     631             :   // WidgetKeyboardEvent::ExecuteEditCommands() requires non-nullptr mWidget.
     632             :   // If the event is created by chrome script, it is nullptr but we need to
     633             :   // execute native key bindings.  Therefore, we need to set widget to
     634             :   // WidgetEvent::mWidget temporarily.
     635           0 :   AutoRestore<nsCOMPtr<nsIWidget>> saveWidget(aKeyboardEvent->mWidget);
     636           0 :   aKeyboardEvent->mWidget = widget;
     637           0 :   if (aKeyboardEvent->ExecuteEditCommands(
     638             :                         nsIWidget::NativeKeyBindingsForRichTextEditor,
     639           0 :                         DoCommandCallback, doc)) {
     640           0 :     aKeyboardEvent->PreventDefault();
     641             :   }
     642           0 :   return NS_OK;
     643             : }
     644             : 
     645             : nsresult
     646           0 : EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
     647             : {
     648           0 :   if (NS_WARN_IF(!aMouseEvent) || DetachedFromEditor()) {
     649           0 :     return NS_OK;
     650             :   }
     651             :   // nothing to do if editor isn't editable or clicked on out of the editor.
     652           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     653             :   WidgetMouseEvent* clickEvent =
     654           0 :     aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
     655           0 :   if (editorBase->IsReadonly() || editorBase->IsDisabled() ||
     656           0 :       !editorBase->IsAcceptableInputEvent(clickEvent)) {
     657           0 :     return NS_OK;
     658             :   }
     659             : 
     660             :   // Notifies clicking on editor to IMEStateManager even when the event was
     661             :   // consumed.
     662           0 :   if (EditorHasFocus()) {
     663           0 :     nsPresContext* presContext = GetPresContext();
     664           0 :     if (presContext) {
     665           0 :       IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
     666           0 :                                        clickEvent);
     667           0 :       if (DetachedFromEditor()) {
     668           0 :         return NS_OK;
     669             :       }
     670             :     }
     671             :   }
     672             : 
     673           0 :   if (DetachedFromEditorOrDefaultPrevented(clickEvent)) {
     674             :     // We're done if 'preventdefault' is true (see for example bug 70698).
     675           0 :     return NS_OK;
     676             :   }
     677             : 
     678             :   // If we got a mouse down inside the editing area, we should force the
     679             :   // IME to commit before we change the cursor position
     680           0 :   if (!EnsureCommitCompoisition()) {
     681           0 :     return NS_OK;
     682             :   }
     683             : 
     684           0 :   if (clickEvent->button == 1) {
     685           0 :     return HandleMiddleClickPaste(aMouseEvent);
     686             :   }
     687           0 :   return NS_OK;
     688             : }
     689             : 
     690             : nsresult
     691           0 : EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
     692             : {
     693           0 :   MOZ_ASSERT(aMouseEvent);
     694             : 
     695             :   WidgetMouseEvent* clickEvent =
     696           0 :     aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
     697           0 :   MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(clickEvent));
     698             : 
     699           0 :   if (!Preferences::GetBool("middlemouse.paste", false)) {
     700             :     // Middle click paste isn't enabled.
     701           0 :     return NS_OK;
     702             :   }
     703             : 
     704             :   // Set the selection to the point under the mouse cursor:
     705           0 :   nsCOMPtr<nsIDOMNode> parent;
     706           0 :   if (NS_FAILED(aMouseEvent->GetRangeParent(getter_AddRefs(parent)))) {
     707           0 :     return NS_ERROR_NULL_POINTER;
     708             :   }
     709           0 :   int32_t offset = 0;
     710           0 :   if (NS_FAILED(aMouseEvent->GetRangeOffset(&offset))) {
     711           0 :     return NS_ERROR_NULL_POINTER;
     712             :   }
     713             : 
     714           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     715           0 :   RefPtr<Selection> selection = editorBase->GetSelection();
     716           0 :   if (selection) {
     717           0 :     selection->Collapse(parent, offset);
     718             :   }
     719             : 
     720             :   // If the ctrl key is pressed, we'll do paste as quotation.
     721             :   // Would've used the alt key, but the kde wmgr treats alt-middle specially.
     722           0 :   nsCOMPtr<nsIEditorMailSupport> mailEditor;
     723           0 :   if (clickEvent->IsControl()) {
     724           0 :     mailEditor = do_QueryObject(editorBase);
     725             :   }
     726             : 
     727             :   nsresult rv;
     728           0 :   int32_t clipboard = nsIClipboard::kGlobalClipboard;
     729             :   nsCOMPtr<nsIClipboard> clipboardService =
     730           0 :     do_GetService("@mozilla.org/widget/clipboard;1", &rv);
     731           0 :   if (NS_SUCCEEDED(rv)) {
     732             :     bool selectionSupported;
     733           0 :     rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
     734           0 :     if (NS_SUCCEEDED(rv) && selectionSupported) {
     735           0 :       clipboard = nsIClipboard::kSelectionClipboard;
     736             :     }
     737             :   }
     738             : 
     739           0 :   if (mailEditor) {
     740           0 :     mailEditor->PasteAsQuotation(clipboard);
     741             :   } else {
     742           0 :     editorBase->Paste(clipboard);
     743             :   }
     744             : 
     745             :   // Prevent the event from propagating up to be possibly handled
     746             :   // again by the containing window:
     747           0 :   clickEvent->StopPropagation();
     748           0 :   clickEvent->PreventDefault();
     749             : 
     750             :   // We processed the event, whether drop/paste succeeded or not
     751           0 :   return NS_OK;
     752             : }
     753             : 
     754             : bool
     755           0 : EditorEventListener::NotifyIMEOfMouseButtonEvent(
     756             :                        WidgetMouseEvent* aMouseEvent)
     757             : {
     758           0 :   MOZ_ASSERT(aMouseEvent);
     759             : 
     760           0 :   if (!EditorHasFocus()) {
     761           0 :     return false;
     762             :   }
     763             : 
     764           0 :   nsPresContext* presContext = GetPresContext();
     765           0 :   NS_ENSURE_TRUE(presContext, false);
     766           0 :   return IMEStateManager::OnMouseButtonEventInEditor(presContext,
     767             :                                                      GetFocusedRootContent(),
     768           0 :                                                      aMouseEvent);
     769             : }
     770             : 
     771             : nsresult
     772           0 : EditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
     773             : {
     774             :   // FYI: We don't need to check if it's already consumed here because
     775             :   //      we need to commit composition at mouse button operation.
     776             :   // FYI: This may be called by HTMLEditorEventListener::MouseDown() even
     777             :   //      when the event is not acceptable for committing composition.
     778           0 :   if (DetachedFromEditor()) {
     779           0 :     return NS_OK;
     780             :   }
     781           0 :   Unused << EnsureCommitCompoisition();
     782           0 :   return NS_OK;
     783             : }
     784             : 
     785             : nsresult
     786           0 : EditorEventListener::HandleChangeComposition(
     787             :                        WidgetCompositionEvent* aCompositionChangeEvent)
     788             : {
     789           0 :   MOZ_ASSERT(!aCompositionChangeEvent->DefaultPrevented(),
     790             :              "eCompositionChange event shouldn't be cancelable");
     791           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     792           0 :   if (DetachedFromEditor() ||
     793           0 :       !editorBase->IsAcceptableInputEvent(aCompositionChangeEvent)) {
     794           0 :     return NS_OK;
     795             :   }
     796             : 
     797             :   // if we are readonly or disabled, then do nothing.
     798           0 :   if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
     799           0 :     return NS_OK;
     800             :   }
     801             : 
     802           0 :   return editorBase->UpdateIMEComposition(aCompositionChangeEvent);
     803             : }
     804             : 
     805             : /**
     806             :  * Drag event implementation
     807             :  */
     808             : 
     809             : nsresult
     810           0 : EditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
     811             : {
     812           0 :   if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
     813           0 :     return NS_OK;
     814             :   }
     815             : 
     816           0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     817           0 :   NS_ENSURE_TRUE(presShell, NS_OK);
     818             : 
     819           0 :   if (!mCaret) {
     820           0 :     mCaret = new nsCaret();
     821           0 :     mCaret->Init(presShell);
     822           0 :     mCaret->SetCaretReadOnly(true);
     823             :     // This is to avoid the requirement that the Selection is Collapsed which
     824             :     // it can't be when dragging a selection in the same shell.
     825             :     // See nsCaret::IsVisible().
     826           0 :     mCaret->SetVisibilityDuringSelection(true);
     827             :   }
     828             : 
     829           0 :   presShell->SetCaret(mCaret);
     830             : 
     831           0 :   return DragOver(aDragEvent);
     832             : }
     833             : 
     834             : nsresult
     835           0 : EditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
     836             : {
     837           0 :   if (NS_WARN_IF(!aDragEvent) ||
     838           0 :       DetachedFromEditorOrDefaultPrevented(
     839           0 :         aDragEvent->AsEvent()->WidgetEventPtr())) {
     840           0 :     return NS_OK;
     841             :   }
     842             : 
     843           0 :   nsCOMPtr<nsIDOMNode> parent;
     844           0 :   aDragEvent->GetRangeParent(getter_AddRefs(parent));
     845           0 :   nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
     846           0 :   NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
     847             : 
     848           0 :   if (dropParent->IsEditable() && CanDrop(aDragEvent)) {
     849           0 :     aDragEvent->AsEvent()->PreventDefault(); // consumed
     850             : 
     851           0 :     if (!mCaret) {
     852           0 :       return NS_OK;
     853             :     }
     854             : 
     855           0 :     int32_t offset = 0;
     856           0 :     nsresult rv = aDragEvent->GetRangeOffset(&offset);
     857           0 :     NS_ENSURE_SUCCESS(rv, rv);
     858             : 
     859           0 :     mCaret->SetVisible(true);
     860           0 :     mCaret->SetCaretPosition(parent, offset);
     861             : 
     862           0 :     return NS_OK;
     863             :   }
     864             : 
     865           0 :   if (!IsFileControlTextBox()) {
     866             :     // This is needed when dropping on an input, to prevent the editor for
     867             :     // the editable parent from receiving the event.
     868           0 :     aDragEvent->AsEvent()->StopPropagation();
     869             :   }
     870             : 
     871           0 :   if (mCaret) {
     872           0 :     mCaret->SetVisible(false);
     873             :   }
     874           0 :   return NS_OK;
     875             : }
     876             : 
     877             : void
     878           0 : EditorEventListener::CleanupDragDropCaret()
     879             : {
     880           0 :   if (!mCaret) {
     881           0 :     return;
     882             :   }
     883             : 
     884           0 :   mCaret->SetVisible(false);    // hide it, so that it turns off its timer
     885             : 
     886           0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     887           0 :   if (presShell) {
     888           0 :     presShell->RestoreCaret();
     889             :   }
     890             : 
     891           0 :   mCaret->Terminate();
     892           0 :   mCaret = nullptr;
     893             : }
     894             : 
     895             : nsresult
     896           0 : EditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
     897             : {
     898             :   // XXX If aDragEvent was created by chrome script, its defaultPrevented
     899             :   //     may be true, though.  We shouldn't handle such event but we don't
     900             :   //     have a way to distinguish if coming event is created by chrome script.
     901           0 :   NS_WARNING_ASSERTION(
     902             :     !aDragEvent->AsEvent()->WidgetEventPtr()->DefaultPrevented(),
     903             :     "eDragExit shouldn't be cancelable");
     904           0 :   if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
     905           0 :     return NS_OK;
     906             :   }
     907             : 
     908           0 :   CleanupDragDropCaret();
     909             : 
     910           0 :   return NS_OK;
     911             : }
     912             : 
     913             : nsresult
     914           0 : EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
     915             : {
     916           0 :   CleanupDragDropCaret();
     917             : 
     918           0 :   if (NS_WARN_IF(!aDragEvent) ||
     919           0 :       DetachedFromEditorOrDefaultPrevented(
     920           0 :         aDragEvent->AsEvent()->WidgetEventPtr())) {
     921           0 :     return NS_OK;
     922             :   }
     923             : 
     924           0 :   nsCOMPtr<nsIDOMNode> parent;
     925           0 :   aDragEvent->GetRangeParent(getter_AddRefs(parent));
     926           0 :   nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
     927           0 :   NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
     928             : 
     929           0 :   if (!dropParent->IsEditable() || !CanDrop(aDragEvent)) {
     930             :     // was it because we're read-only?
     931           0 :     RefPtr<EditorBase> editorBase(mEditorBase);
     932           0 :     if ((editorBase->IsReadonly() || editorBase->IsDisabled()) &&
     933           0 :         !IsFileControlTextBox()) {
     934             :       // it was decided to "eat" the event as this is the "least surprise"
     935             :       // since someone else handling it might be unintentional and the
     936             :       // user could probably re-drag to be not over the disabled/readonly
     937             :       // editfields if that is what is desired.
     938           0 :       return aDragEvent->AsEvent()->StopPropagation();
     939             :     }
     940           0 :     return NS_OK;
     941             :   }
     942             : 
     943           0 :   aDragEvent->AsEvent()->StopPropagation();
     944           0 :   aDragEvent->AsEvent()->PreventDefault();
     945           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     946           0 :   return editorBase->InsertFromDrop(aDragEvent->AsEvent());
     947             : }
     948             : 
     949             : bool
     950           0 : EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
     951             : {
     952           0 :   MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(
     953             :                 aEvent->AsEvent()->WidgetEventPtr()));
     954             : 
     955             :   // if the target doc is read-only, we can't drop
     956           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
     957           0 :   if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
     958           0 :     return false;
     959             :   }
     960             : 
     961           0 :   nsCOMPtr<nsIDOMDataTransfer> domDataTransfer;
     962           0 :   aEvent->GetDataTransfer(getter_AddRefs(domDataTransfer));
     963           0 :   nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(domDataTransfer);
     964           0 :   NS_ENSURE_TRUE(dataTransfer, false);
     965             : 
     966           0 :   nsTArray<nsString> types;
     967           0 :   dataTransfer->GetTypes(types, CallerType::System);
     968             : 
     969             :   // Plaintext editors only support dropping text. Otherwise, HTML and files
     970             :   // can be dropped as well.
     971           0 :   if (!types.Contains(NS_LITERAL_STRING(kTextMime)) &&
     972           0 :       !types.Contains(NS_LITERAL_STRING(kMozTextInternal)) &&
     973           0 :       (editorBase->IsPlaintextEditor() ||
     974           0 :        (!types.Contains(NS_LITERAL_STRING(kHTMLMime)) &&
     975           0 :         !types.Contains(NS_LITERAL_STRING(kFileMime))))) {
     976           0 :     return false;
     977             :   }
     978             : 
     979             :   // If there is no source node, this is probably an external drag and the
     980             :   // drop is allowed. The later checks rely on checking if the drag target
     981             :   // is the same as the drag source.
     982           0 :   nsCOMPtr<nsIDOMNode> sourceNode;
     983           0 :   dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
     984           0 :   if (!sourceNode) {
     985           0 :     return true;
     986             :   }
     987             : 
     988             :   // There is a source node, so compare the source documents and this document.
     989             :   // Disallow drops on the same document.
     990             : 
     991           0 :   nsCOMPtr<nsIDOMDocument> domdoc = editorBase->GetDOMDocument();
     992           0 :   NS_ENSURE_TRUE(domdoc, false);
     993             : 
     994           0 :   nsCOMPtr<nsIDOMDocument> sourceDoc;
     995           0 :   nsresult rv = sourceNode->GetOwnerDocument(getter_AddRefs(sourceDoc));
     996           0 :   NS_ENSURE_SUCCESS(rv, false);
     997             : 
     998             :   // If the source and the dest are not same document, allow to drop it always.
     999           0 :   if (domdoc != sourceDoc) {
    1000           0 :     return true;
    1001             :   }
    1002             : 
    1003             :   // If the source node is a remote browser, treat this as coming from a
    1004             :   // different document and allow the drop.
    1005           0 :   nsCOMPtr<nsIContent> sourceContent = do_QueryInterface(sourceNode);
    1006           0 :   TabParent* tp = TabParent::GetFrom(sourceContent);
    1007           0 :   if (tp) {
    1008           0 :     return true;
    1009             :   }
    1010             : 
    1011           0 :   RefPtr<Selection> selection = editorBase->GetSelection();
    1012           0 :   if (!selection) {
    1013           0 :     return false;
    1014             :   }
    1015             : 
    1016             :   // If selection is collapsed, allow to drop it always.
    1017           0 :   if (selection->Collapsed()) {
    1018           0 :     return true;
    1019             :   }
    1020             : 
    1021           0 :   nsCOMPtr<nsIDOMNode> parent;
    1022           0 :   rv = aEvent->GetRangeParent(getter_AddRefs(parent));
    1023           0 :   if (NS_FAILED(rv) || !parent) {
    1024           0 :     return false;
    1025             :   }
    1026             : 
    1027           0 :   int32_t offset = 0;
    1028           0 :   rv = aEvent->GetRangeOffset(&offset);
    1029           0 :   NS_ENSURE_SUCCESS(rv, false);
    1030             : 
    1031             :   int32_t rangeCount;
    1032           0 :   rv = selection->GetRangeCount(&rangeCount);
    1033           0 :   NS_ENSURE_SUCCESS(rv, false);
    1034             : 
    1035           0 :   for (int32_t i = 0; i < rangeCount; i++) {
    1036           0 :     RefPtr<nsRange> range = selection->GetRangeAt(i);
    1037           0 :     if (!range) {
    1038             :       // Don't bail yet, iterate through them all
    1039           0 :       continue;
    1040             :     }
    1041             : 
    1042           0 :     bool inRange = true;
    1043           0 :     range->IsPointInRange(parent, offset, &inRange);
    1044           0 :     if (inRange) {
    1045             :       // Okay, now you can bail, we are over the orginal selection
    1046           0 :       return false;
    1047             :     }
    1048             :   }
    1049           0 :   return true;
    1050             : }
    1051             : 
    1052             : nsresult
    1053           0 : EditorEventListener::HandleStartComposition(
    1054             :                        WidgetCompositionEvent* aCompositionStartEvent)
    1055             : {
    1056           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1057           0 :   if (DetachedFromEditor() ||
    1058           0 :       !editorBase->IsAcceptableInputEvent(aCompositionStartEvent)) {
    1059           0 :     return NS_OK;
    1060             :   }
    1061             :   // Although, "compositionstart" should be cancelable, but currently,
    1062             :   // eCompositionStart event coming from widget is not cancelable.
    1063           0 :   MOZ_ASSERT(!aCompositionStartEvent->DefaultPrevented(),
    1064             :              "eCompositionStart shouldn't be cancelable");
    1065           0 :   return editorBase->BeginIMEComposition(aCompositionStartEvent);
    1066             : }
    1067             : 
    1068             : void
    1069           0 : EditorEventListener::HandleEndComposition(
    1070             :                        WidgetCompositionEvent* aCompositionEndEvent)
    1071             : {
    1072           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1073           0 :   if (DetachedFromEditor() ||
    1074           0 :       !editorBase->IsAcceptableInputEvent(aCompositionEndEvent)) {
    1075           0 :     return;
    1076             :   }
    1077           0 :   MOZ_ASSERT(!aCompositionEndEvent->DefaultPrevented(),
    1078             :              "eCompositionEnd shouldn't be cancelable");
    1079           0 :   editorBase->EndIMEComposition();
    1080             : }
    1081             : 
    1082             : nsresult
    1083           0 : EditorEventListener::Focus(InternalFocusEvent* aFocusEvent)
    1084             : {
    1085           0 :   if (NS_WARN_IF(!aFocusEvent) || DetachedFromEditor()) {
    1086           0 :     return NS_OK;
    1087             :   }
    1088             : 
    1089             :   // Don't turn on selection and caret when the editor is disabled.
    1090           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1091           0 :   if (editorBase->IsDisabled()) {
    1092           0 :     return NS_OK;
    1093             :   }
    1094             : 
    1095             :   // Spell check a textarea the first time that it is focused.
    1096           0 :   SpellCheckIfNeeded();
    1097           0 :   if (!editorBase) {
    1098             :     // In e10s, this can cause us to flush notifications, which can destroy
    1099             :     // the node we're about to focus.
    1100           0 :     return NS_OK;
    1101             :   }
    1102             : 
    1103           0 :   nsCOMPtr<nsIDOMEventTarget> target = aFocusEvent->GetDOMEventTarget();
    1104           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(target);
    1105           0 :   NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
    1106             : 
    1107             :   // If the target is a document node but it's not editable, we should ignore
    1108             :   // it because actual focused element's event is going to come.
    1109           0 :   if (node->IsNodeOfType(nsINode::eDOCUMENT) &&
    1110           0 :       !node->HasFlag(NODE_IS_EDITABLE)) {
    1111           0 :     return NS_OK;
    1112             :   }
    1113             : 
    1114           0 :   if (node->IsNodeOfType(nsINode::eCONTENT)) {
    1115             :     // XXX If the focus event target is a form control in contenteditable
    1116             :     // element, perhaps, the parent HTML editor should do nothing by this
    1117             :     // handler.  However, FindSelectionRoot() returns the root element of the
    1118             :     // contenteditable editor.  So, the editableRoot value is invalid for
    1119             :     // the plain text editor, and it will be set to the wrong limiter of
    1120             :     // the selection.  However, fortunately, actual bugs are not found yet.
    1121           0 :     nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(node);
    1122             : 
    1123             :     // make sure that the element is really focused in case an earlier
    1124             :     // listener in the chain changed the focus.
    1125           0 :     if (editableRoot) {
    1126           0 :       nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    1127           0 :       NS_ENSURE_TRUE(fm, NS_OK);
    1128             : 
    1129           0 :       nsCOMPtr<nsIDOMElement> element;
    1130           0 :       fm->GetFocusedElement(getter_AddRefs(element));
    1131           0 :       if (!element) {
    1132           0 :         return NS_OK;
    1133             :       }
    1134             : 
    1135             :       nsCOMPtr<nsIDOMEventTarget> originalTarget =
    1136           0 :         aFocusEvent->GetOriginalDOMEventTarget();
    1137             : 
    1138             :       nsCOMPtr<nsIContent> originalTargetAsContent =
    1139           0 :         do_QueryInterface(originalTarget);
    1140             :       nsCOMPtr<nsIContent> focusedElementAsContent =
    1141           0 :         do_QueryInterface(element);
    1142             : 
    1143           0 :       if (!SameCOMIdentity(
    1144           0 :             focusedElementAsContent->FindFirstNonChromeOnlyAccessContent(),
    1145           0 :             originalTargetAsContent->FindFirstNonChromeOnlyAccessContent())) {
    1146           0 :         return NS_OK;
    1147             :       }
    1148             :     }
    1149             :   }
    1150             : 
    1151           0 :   editorBase->OnFocus(target);
    1152           0 :   if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
    1153           0 :     return NS_OK;
    1154             :   }
    1155             : 
    1156           0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    1157           0 :   NS_ENSURE_TRUE(ps, NS_OK);
    1158           0 :   nsCOMPtr<nsIContent> focusedContent = editorBase->GetFocusedContentForIME();
    1159           0 :   IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
    1160           0 :                                    *editorBase);
    1161             : 
    1162           0 :   return NS_OK;
    1163             : }
    1164             : 
    1165             : nsresult
    1166           0 : EditorEventListener::Blur(InternalFocusEvent* aBlurEvent)
    1167             : {
    1168           0 :   if (NS_WARN_IF(!aBlurEvent) || DetachedFromEditor()) {
    1169           0 :     return NS_OK;
    1170             :   }
    1171             : 
    1172             :   // check if something else is focused. If another element is focused, then
    1173             :   // we should not change the selection.
    1174           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    1175           0 :   NS_ENSURE_TRUE(fm, NS_OK);
    1176             : 
    1177           0 :   nsCOMPtr<nsIDOMElement> element;
    1178           0 :   fm->GetFocusedElement(getter_AddRefs(element));
    1179           0 :   if (!element) {
    1180           0 :     RefPtr<EditorBase> editorBase(mEditorBase);
    1181           0 :     editorBase->FinalizeSelection();
    1182             :   }
    1183           0 :   return NS_OK;
    1184             : }
    1185             : 
    1186             : void
    1187           0 : EditorEventListener::SpellCheckIfNeeded()
    1188             : {
    1189           0 :   MOZ_ASSERT(!DetachedFromEditor());
    1190             : 
    1191             :   // If the spell check skip flag is still enabled from creation time,
    1192             :   // disable it because focused editors are allowed to spell check.
    1193           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1194           0 :   uint32_t currentFlags = 0;
    1195           0 :   editorBase->GetFlags(&currentFlags);
    1196           0 :   if(currentFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) {
    1197           0 :     currentFlags ^= nsIPlaintextEditor::eEditorSkipSpellCheck;
    1198           0 :     editorBase->SetFlags(currentFlags);
    1199             :   }
    1200           0 : }
    1201             : 
    1202             : bool
    1203           0 : EditorEventListener::IsFileControlTextBox()
    1204             : {
    1205           0 :   MOZ_ASSERT(!DetachedFromEditor());
    1206             : 
    1207           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1208           0 :   Element* root = editorBase->GetRoot();
    1209           0 :   if (!root || !root->ChromeOnlyAccess()) {
    1210           0 :     return false;
    1211             :   }
    1212           0 :   nsIContent* parent = root->FindFirstNonChromeOnlyAccessContent();
    1213           0 :   if (!parent || !parent->IsHTMLElement(nsGkAtoms::input)) {
    1214           0 :     return false;
    1215             :   }
    1216           0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(parent);
    1217           0 :   return formControl->ControlType() == NS_FORM_INPUT_FILE;
    1218             : }
    1219             : 
    1220             : bool
    1221           0 : EditorEventListener::ShouldHandleNativeKeyBindings(
    1222             :                        WidgetKeyboardEvent* aKeyboardEvent)
    1223             : {
    1224           0 :   MOZ_ASSERT(!DetachedFromEditor());
    1225             : 
    1226             :   // Only return true if the target of the event is a desendant of the active
    1227             :   // editing host in order to match the similar decision made in
    1228             :   // nsXBLWindowKeyHandler.
    1229             :   // Note that IsAcceptableInputEvent doesn't check for the active editing
    1230             :   // host for keyboard events, otherwise this check would have been
    1231             :   // unnecessary.  IsAcceptableInputEvent currently makes a similar check for
    1232             :   // mouse events.
    1233             : 
    1234           0 :   nsCOMPtr<nsIDOMEventTarget> target = aKeyboardEvent->GetDOMEventTarget();
    1235           0 :   nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
    1236           0 :   if (!targetContent) {
    1237           0 :     return false;
    1238             :   }
    1239             : 
    1240           0 :   RefPtr<EditorBase> editorBase(mEditorBase);
    1241           0 :   HTMLEditor* htmlEditor = editorBase->AsHTMLEditor();
    1242           0 :   if (!htmlEditor) {
    1243           0 :     return false;
    1244             :   }
    1245             : 
    1246           0 :   nsCOMPtr<nsIDocument> doc = editorBase->GetDocument();
    1247           0 :   if (doc->HasFlag(NODE_IS_EDITABLE)) {
    1248             :     // Don't need to perform any checks in designMode documents.
    1249           0 :     return true;
    1250             :   }
    1251             : 
    1252           0 :   nsIContent* editingHost = htmlEditor->GetActiveEditingHost();
    1253           0 :   if (!editingHost) {
    1254           0 :     return false;
    1255             :   }
    1256             : 
    1257           0 :   return nsContentUtils::ContentIsDescendantOf(targetContent, editingHost);
    1258             : }
    1259             : 
    1260             : } // namespace mozilla

Generated by: LCOV version 1.13